<commit_before>AliAnalysisTask *AddTask_dsekihat_lowmass_PbPb(
    Bool_t getFromAlien = kFALSE,
    TString cFileName = "Config_dsekihat_lowmass_PbPb.C",
    TString lFileName = "LMEECutLib_dsekihat.C",
		TString calibFileName = "",
    UInt_t trigger = AliVEvent::kINT7|AliVEvent::kCentral|AliVEvent::kSemiCentral,
    const Int_t CenMin =  0,
    const Int_t CenMax = 10,
    const Int_t Nmix   = 10,
    const Float_t PtMin = 0.2,
    const Float_t PtMax = 10,
    const Float_t EtaMin = -0.8,
    const Float_t EtaMax = +0.8,
		const TString outname = "LMEE.root"
    )
{
  //get the current analysis manager
  AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
  if (!mgr) {
    Error("AddTask_dsekihat_lowmass_PbPb", "No analysis manager found.");
    return 0;
  }

  //Base Directory for GRID / LEGO Train
  TString configBasePath= "$ALICE_PHYSICS/PWGDQ/dielectron/macrosLMEE/";
  //TString configBasePath= "./";
  if(getFromAlien
    && (!gSystem->Exec(Form("alien_cp alien:///alice/cern.ch/user/d/dsekihat/PWGDQ/dielectron/macrosLMEE/%s .",cFileName.Data())))
    && (!gSystem->Exec(Form("alien_cp alien:///alice/cern.ch/user/d/dsekihat/PWGDQ/dielectron/macrosLMEE/%s .",lFileName.Data())))
    ){
    configBasePath=Form("%s/",gSystem->pwd());
  }

  TString configFilePath(configBasePath + cFileName);
  TString libFilePath(configBasePath + lFileName);
  std::cout << "Configpath:  " << configFilePath << std::endl;
  std::cout << "Libpath:  "    << libFilePath << std::endl;

  TString triggername = "NULL";
  if(trigger == (UInt_t)AliVEvent::kINT7)             triggername = "kINT7";
  else if(trigger == (UInt_t)AliVEvent::kCentral)     triggername = "kCentral";
  else if(trigger == (UInt_t)AliVEvent::kSemiCentral) triggername = "kSemiCentral";
  else if(trigger == (UInt_t)(AliVEvent::kINT7 | AliVEvent::kCentral | AliVEvent::kSemiCentral)) triggername = "kCombinedCentralityTriggers";
  else if(trigger == (UInt_t)(AliVEvent::kINT7 | AliVEvent::kCentral))                           triggername = "kCombinedCentral";
  else if(trigger == (UInt_t)(AliVEvent::kINT7 | AliVEvent::kSemiCentral))                       triggername = "kCombinedSemiCentral";

  //create task and add it to the manager (MB)
  AliAnalysisTaskMultiDielectron *task = new AliAnalysisTaskMultiDielectron(Form("MultiDielectron_Cen%d_%d_%s",CenMin,CenMax,triggername.Data()));
  task->UsePhysicsSelection(kTRUE);
  task->SetTriggerMask(trigger);

  //add dielectron analysis with different cuts to the task
  gROOT->LoadMacro(libFilePath.Data());//library first
  gROOT->LoadMacro(configFilePath.Data());

  //const Int_t nDie = (Int_t)gROOT->ProcessLine("GetN()");
  const Int_t nTC  = Int_t(gROOT->ProcessLine("GetNTC()") );
  const Int_t nPID = Int_t(gROOT->ProcessLine("GetNPID()"));
  const Int_t nPF  = Int_t(gROOT->ProcessLine("GetNPF()") );

  THnF *hs_mean_TPC_El  = 0x0;
  THnF *hs_width_TPC_El = 0x0;
  THnF *hs_mean_ITS_El  = 0x0;
  THnF *hs_width_ITS_El = 0x0;
  THnF *hs_mean_TOF_El  = 0x0;
  THnF *hs_width_TOF_El = 0x0;
  THnF *hs_mean_TPC_Pi  = 0x0;
  THnF *hs_width_TPC_Pi = 0x0;

	TFile *rootfile = 0x0;
	if(calibFileName != ""){
		printf("reading : %s for PID calibration\n",calibFileName.Data());
		rootfile = TFile::Open(calibFileName,"READ");
		hs_mean_TPC_El  = (THnF*)rootfile->Get("hs_mean_TPC_El");
		hs_width_TPC_El = (THnF*)rootfile->Get("hs_width_TPC_El");
		hs_mean_ITS_El  = (THnF*)rootfile->Get("hs_mean_ITS_El");
		hs_width_ITS_El = (THnF*)rootfile->Get("hs_width_ITS_El");
		hs_mean_TOF_El  = (THnF*)rootfile->Get("hs_mean_TOF_El");
		hs_width_TOF_El = (THnF*)rootfile->Get("hs_width_TOF_El");
		hs_mean_TPC_Pi  = (THnF*)rootfile->Get("hs_mean_TPC_Pi");
		hs_width_TPC_Pi = (THnF*)rootfile->Get("hs_width_TPC_Pi");
	}

  for (Int_t itc=0; itc<nTC; ++itc){
    for (Int_t ipid=0; ipid<nPID; ++ipid){
      for (Int_t ipf=0; ipf<nPF; ++ipf){
        AliDielectron *diel = reinterpret_cast<AliDielectron*>(gROOT->ProcessLine(Form("Config_dsekihat_lowmass_PbPb(%d,%d,%d,%f,%f,%f,%f)",itc,ipid,ipf,PtMin,PtMax,EtaMin,EtaMax)));
        if(!diel) continue;

        //AliDielectronVarCuts*  centCuts = new AliDielectronVarCuts("centCuts",Form("kPbPb%02d%02d",CenMin,CenMax));
        //centCuts->AddCut(AliDielectronVarManager::kCentralityNew, (Float_t)CenMin, (Float_t)CenMax);
        //diel->GetEventFilter().AddCuts(centCuts);

				//if(calibFileName!=""){
				if(rootfile && rootfile->IsOpen()){
					diel->SetPIDCaibinPU(kTRUE);
					//for electron
					diel->SetCentroidCorrFunctionPU(AliDielectronPID::kTPC,AliPID::kElectron,hs_mean_TPC_El ,AliDielectronVarManager::kPIn,AliDielectronVarManager::kEta,AliDielectronVarManager::kNclsITS1,AliDielectronVarManager::kTPCpileupZ,AliDielectronVarManager::kTPCpileupM);
					diel->   SetWidthCorrFunctionPU(AliDielectronPID::kTPC,AliPID::kElectron,hs_width_TPC_El,AliDielectronVarManager::kPIn,AliDielectronVarManager::kEta,AliDielectronVarManager::kNclsITS1,AliDielectronVarManager::kTPCpileupZ,AliDielectronVarManager::kTPCpileupM);
					diel->SetCentroidCorrFunctionPU(AliDielectronPID::kITS,AliPID::kElectron,hs_mean_ITS_El ,AliDielectronVarManager::kPIn,AliDielectronVarManager::kEta,AliDielectronVarManager::kNclsITS1,AliDielectronVarManager::kTPCpileupZ,AliDielectronVarManager::kTPCpileupM);
					diel->   SetWidthCorrFunctionPU(AliDielectronPID::kITS,AliPID::kElectron,hs_width_ITS_El,AliDielectronVarManager::kPIn,AliDielectronVarManager::kEta,AliDielectronVarManager::kNclsITS1,AliDielectronVarManager::kTPCpileupZ,AliDielectronVarManager::kTPCpileupM);
					diel->SetCentroidCorrFunctionPU(AliDielectronPID::kTOF,AliPID::kElectron,hs_mean_TOF_El ,AliDielectronVarManager::kPIn,AliDielectronVarManager::kEta,AliDielectronVarManager::kNclsITS1,AliDielectronVarManager::kTPCpileupZ,AliDielectronVarManager::kTPCpileupM);
					diel->   SetWidthCorrFunctionPU(AliDielectronPID::kTOF,AliPID::kElectron,hs_width_TOF_El,AliDielectronVarManager::kPIn,AliDielectronVarManager::kEta,AliDielectronVarManager::kNclsITS1,AliDielectronVarManager::kTPCpileupZ,AliDielectronVarManager::kTPCpileupM);
					//for pion
					diel->SetCentroidCorrFunctionPU(AliDielectronPID::kTPC,AliPID::kPion,hs_mean_TPC_Pi ,AliDielectronVarManager::kPIn,AliDielectronVarManager::kEta,AliDielectronVarManager::kNclsITS1,AliDielectronVarManager::kTPCpileupZ,AliDielectronVarManager::kTPCpileupM);
					diel->   SetWidthCorrFunctionPU(AliDielectronPID::kTPC,AliPID::kPion,hs_width_TPC_Pi ,AliDielectronVarManager::kPIn,AliDielectronVarManager::kEta,AliDielectronVarManager::kNclsITS1,AliDielectronVarManager::kTPCpileupZ,AliDielectronVarManager::kTPCpileupM);
				}

        TString name = diel->GetName();
        if(name.Contains("PIDCalib",TString::kIgnoreCase) || name.Contains("noPID",TString::kIgnoreCase)){
          printf("No event mixing handler for post PID calibration/noPID\n");
        }
        else{
          printf("Add event mixing handler\n");
          AliDielectronMixingHandler *mix = new AliDielectronMixingHandler;
          mix->SetMixType(AliDielectronMixingHandler::kAll);
          mix->AddVariable(AliDielectronVarManager::kZvPrim,"-10., -8., -6., -4., -2. , 0., 2., 4., 6., 8. , 10.");
          mix->AddVariable(AliDielectronVarManager::kCentralityNew,"0,5,10,30,50,70,90,101");
          mix->AddVariable(AliDielectronVarManager::kNacc,"0,10000");
          mix->SetDepth(Nmix);
          diel->SetMixingHandler(mix);
        }
        task->AddDielectron(diel);
      }//pre-filter loop
    }//PID loop
  }//track cut loop

	//if(rootfile && rootfile->IsOpen()) rootfile->Close();

  task->SetEventFilter(reinterpret_cast<AliDielectronEventCuts*>(gROOT->ProcessLine(Form("LMEECutLib::SetupEventCuts(%f,%f,%d,\"%s\")",(Float_t)CenMin,(Float_t)CenMax,kTRUE,"V0M"))));//kTRUE is for Run2

  mgr->AddTask(task);

  //const TString outputFileName = AliAnalysisManager::GetCommonFileName();
  const TString outputFileName = outname;
  //const TString dirname = Form("PWGDQ_LMEE_Cen%d_%d_%s",CenMin,CenMax,triggername.Data());

  //create output container
  AliAnalysisDataContainer *coutput1 =
    mgr->CreateContainer(Form("Tree_dsekihat_Cen%d_%d_%s",CenMin,CenMax,triggername.Data()),
                         TTree::Class(),
                         AliAnalysisManager::kExchangeContainer,
                         Form("%s",outputFileName.Data()));

  AliAnalysisDataContainer *cOutputHist1 =
    mgr->CreateContainer(Form("Histos_dsekihat_Cen%d_%d_%s",CenMin,CenMax,triggername.Data()),
                         TList::Class(),
                         AliAnalysisManager::kOutputContainer,
                         Form("%s",outputFileName.Data()));

  AliAnalysisDataContainer *cOutputHist2 =
    mgr->CreateContainer(Form("CF_dsekihat_Cen%d_%d_%s",CenMin,CenMax,triggername.Data()),
                         TList::Class(),
                         AliAnalysisManager::kOutputContainer,
                         Form("%s",outputFileName.Data()));

  AliAnalysisDataContainer *cOutputHist3 =
    mgr->CreateContainer(Form("EventStat_dsekihat_Cen%d_%d_%s",CenMin,CenMax,triggername.Data()),
                         TH1D::Class(),
                         AliAnalysisManager::kOutputContainer,
                         Form("%s",outputFileName.Data()));

  mgr->ConnectInput(task,  0, mgr->GetCommonInputContainer());
  mgr->ConnectOutput(task, 0, coutput1 );
  mgr->ConnectOutput(task, 1, cOutputHist1);
  mgr->ConnectOutput(task, 2, cOutputHist2);
  mgr->ConnectOutput(task, 3, cOutputHist3);

  return task;
}

<commit_msg>update AddTask for MC<commit_after>AliAnalysisTask *AddTask_dsekihat_lowmass_PbPb(
    Bool_t getFromAlien = kFALSE,
    TString cFileName = "Config_dsekihat_lowmass_PbPb.C",
    TString lFileName = "LMEECutLib_dsekihat.C",
		TString calibFileName = "",
    UInt_t trigger = AliVEvent::kINT7|AliVEvent::kCentral|AliVEvent::kSemiCentral,
    const Int_t CenMin =  0,
    const Int_t CenMax = 10,
    const Int_t Nmix   = 10,
    const Float_t PtMin = 0.2,
    const Float_t PtMax = 10,
    const Float_t EtaMin = -0.8,
    const Float_t EtaMax = +0.8,
		const TString outname = "LMEE.root",
		const Bool_t isMC = kFALSE
    )
{
  //get the current analysis manager
  AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
  if (!mgr) {
    Error("AddTask_dsekihat_lowmass_PbPb", "No analysis manager found.");
    return 0;
  }

  //Base Directory for GRID / LEGO Train
  TString configBasePath= "$ALICE_PHYSICS/PWGDQ/dielectron/macrosLMEE/";
  //TString configBasePath= "./";
  if(getFromAlien
    && (!gSystem->Exec(Form("alien_cp alien:///alice/cern.ch/user/d/dsekihat/PWGDQ/dielectron/macrosLMEE/%s .",cFileName.Data())))
    && (!gSystem->Exec(Form("alien_cp alien:///alice/cern.ch/user/d/dsekihat/PWGDQ/dielectron/macrosLMEE/%s .",lFileName.Data())))
    ){
    configBasePath=Form("%s/",gSystem->pwd());
  }

  TString configFilePath(configBasePath + cFileName);
  TString libFilePath(configBasePath + lFileName);
  std::cout << "Configpath:  " << configFilePath << std::endl;
  std::cout << "Libpath:  "    << libFilePath << std::endl;

  TString triggername = "NULL";
  if(trigger == (UInt_t)AliVEvent::kINT7)             triggername = "kINT7";
  else if(trigger == (UInt_t)AliVEvent::kCentral)     triggername = "kCentral";
  else if(trigger == (UInt_t)AliVEvent::kSemiCentral) triggername = "kSemiCentral";
  else if(trigger == (UInt_t)(AliVEvent::kINT7 | AliVEvent::kCentral | AliVEvent::kSemiCentral)) triggername = "kCombinedCentralityTriggers";
  else if(trigger == (UInt_t)(AliVEvent::kINT7 | AliVEvent::kCentral))                           triggername = "kCombinedCentral";
  else if(trigger == (UInt_t)(AliVEvent::kINT7 | AliVEvent::kSemiCentral))                       triggername = "kCombinedSemiCentral";

  //create task and add it to the manager (MB)
  AliAnalysisTaskMultiDielectron *task = new AliAnalysisTaskMultiDielectron(Form("MultiDielectron_Cen%d_%d_%s",CenMin,CenMax,triggername.Data()));
  task->UsePhysicsSelection(kTRUE);
  task->SetTriggerMask(trigger);

  //add dielectron analysis with different cuts to the task
  gROOT->LoadMacro(libFilePath.Data());//library first
  gROOT->LoadMacro(configFilePath.Data());

  //const Int_t nDie = (Int_t)gROOT->ProcessLine("GetN()");
  const Int_t nTC  = Int_t(gROOT->ProcessLine("GetNTC()") );
  const Int_t nPID = Int_t(gROOT->ProcessLine("GetNPID()"));
  const Int_t nPF  = Int_t(gROOT->ProcessLine("GetNPF()") );

  THnF *hs_mean_TPC_El  = 0x0;
  THnF *hs_width_TPC_El = 0x0;
  THnF *hs_mean_ITS_El  = 0x0;
  THnF *hs_width_ITS_El = 0x0;
  THnF *hs_mean_TOF_El  = 0x0;
  THnF *hs_width_TOF_El = 0x0;
  THnF *hs_mean_TPC_Pi  = 0x0;
  THnF *hs_width_TPC_Pi = 0x0;

	TFile *rootfile = 0x0;
	if(calibFileName != ""){
		printf("reading : %s for PID calibration\n",calibFileName.Data());
		rootfile = TFile::Open(calibFileName,"READ");
		hs_mean_TPC_El  = (THnF*)rootfile->Get("hs_mean_TPC_El");
		hs_width_TPC_El = (THnF*)rootfile->Get("hs_width_TPC_El");
		hs_mean_ITS_El  = (THnF*)rootfile->Get("hs_mean_ITS_El");
		hs_width_ITS_El = (THnF*)rootfile->Get("hs_width_ITS_El");
		hs_mean_TOF_El  = (THnF*)rootfile->Get("hs_mean_TOF_El");
		hs_width_TOF_El = (THnF*)rootfile->Get("hs_width_TOF_El");
		hs_mean_TPC_Pi  = (THnF*)rootfile->Get("hs_mean_TPC_Pi");
		hs_width_TPC_Pi = (THnF*)rootfile->Get("hs_width_TPC_Pi");
	}

  for (Int_t itc=0; itc<nTC; ++itc){
    for (Int_t ipid=0; ipid<nPID; ++ipid){
      for (Int_t ipf=0; ipf<nPF; ++ipf){
        AliDielectron *diel = reinterpret_cast<AliDielectron*>(gROOT->ProcessLine(Form("Config_dsekihat_lowmass_PbPb(%d,%d,%d,%f,%f,%f,%f,%d)",itc,ipid,ipf,PtMin,PtMax,EtaMin,EtaMax,isMC)));
        if(!diel) continue;
        TString name = diel->GetName();

				//if(calibFileName!=""){
				if(rootfile && rootfile->IsOpen()){
					diel->SetPIDCaibinPU(kTRUE);
					//for electron
					diel->SetCentroidCorrFunctionPU(AliDielectronPID::kTPC,AliPID::kElectron,hs_mean_TPC_El ,AliDielectronVarManager::kPIn,AliDielectronVarManager::kEta,AliDielectronVarManager::kNclsITS1,AliDielectronVarManager::kTPCpileupZ,AliDielectronVarManager::kTPCpileupM);
					diel->   SetWidthCorrFunctionPU(AliDielectronPID::kTPC,AliPID::kElectron,hs_width_TPC_El,AliDielectronVarManager::kPIn,AliDielectronVarManager::kEta,AliDielectronVarManager::kNclsITS1,AliDielectronVarManager::kTPCpileupZ,AliDielectronVarManager::kTPCpileupM);
					diel->SetCentroidCorrFunctionPU(AliDielectronPID::kITS,AliPID::kElectron,hs_mean_ITS_El ,AliDielectronVarManager::kPIn,AliDielectronVarManager::kEta,AliDielectronVarManager::kNclsITS1,AliDielectronVarManager::kTPCpileupZ,AliDielectronVarManager::kTPCpileupM);
					diel->   SetWidthCorrFunctionPU(AliDielectronPID::kITS,AliPID::kElectron,hs_width_ITS_El,AliDielectronVarManager::kPIn,AliDielectronVarManager::kEta,AliDielectronVarManager::kNclsITS1,AliDielectronVarManager::kTPCpileupZ,AliDielectronVarManager::kTPCpileupM);
					diel->SetCentroidCorrFunctionPU(AliDielectronPID::kTOF,AliPID::kElectron,hs_mean_TOF_El ,AliDielectronVarManager::kPIn,AliDielectronVarManager::kEta,AliDielectronVarManager::kNclsITS1,AliDielectronVarManager::kTPCpileupZ,AliDielectronVarManager::kTPCpileupM);
					diel->   SetWidthCorrFunctionPU(AliDielectronPID::kTOF,AliPID::kElectron,hs_width_TOF_El,AliDielectronVarManager::kPIn,AliDielectronVarManager::kEta,AliDielectronVarManager::kNclsITS1,AliDielectronVarManager::kTPCpileupZ,AliDielectronVarManager::kTPCpileupM);
					//for pion
					diel->SetCentroidCorrFunctionPU(AliDielectronPID::kTPC,AliPID::kPion,hs_mean_TPC_Pi ,AliDielectronVarManager::kPIn,AliDielectronVarManager::kEta,AliDielectronVarManager::kNclsITS1,AliDielectronVarManager::kTPCpileupZ,AliDielectronVarManager::kTPCpileupM);
					diel->   SetWidthCorrFunctionPU(AliDielectronPID::kTPC,AliPID::kPion,hs_width_TPC_Pi ,AliDielectronVarManager::kPIn,AliDielectronVarManager::kEta,AliDielectronVarManager::kNclsITS1,AliDielectronVarManager::kTPCpileupZ,AliDielectronVarManager::kTPCpileupM);
				}

        if(name.Contains("PIDCalib",TString::kIgnoreCase) || name.Contains("noPID",TString::kIgnoreCase)){
          printf("No event mixing handler for post PID calibration/noPID\n");
        }
        else{
          printf("Add event mixing handler\n");
          AliDielectronMixingHandler *mix = new AliDielectronMixingHandler;
          mix->SetMixType(AliDielectronMixingHandler::kAll);
          mix->AddVariable(AliDielectronVarManager::kZvPrim,"-10., -8., -6., -4., -2. , 0., 2., 4., 6., 8. , 10.");
          mix->AddVariable(AliDielectronVarManager::kCentralityNew,"0,5,10,30,50,70,90,101");
          mix->AddVariable(AliDielectronVarManager::kNacc,"0,10000");
          mix->SetDepth(Nmix);
          if(!isMC) diel->SetMixingHandler(mix);
        }
        task->AddDielectron(diel);
      }//pre-filter loop
    }//PID loop
  }//track cut loop

	//if(rootfile && rootfile->IsOpen()) rootfile->Close();

  task->SetEventFilter(reinterpret_cast<AliDielectronEventCuts*>(gROOT->ProcessLine(Form("LMEECutLib::SetupEventCuts(%f,%f,%d,\"%s\")",(Float_t)CenMin,(Float_t)CenMax,kTRUE,"V0M"))));//kTRUE is for Run2

  mgr->AddTask(task);

  //const TString outputFileName = AliAnalysisManager::GetCommonFileName();
  const TString outputFileName = outname;
  //const TString dirname = Form("PWGDQ_LMEE_Cen%d_%d_%s",CenMin,CenMax,triggername.Data());

  //create output container
  AliAnalysisDataContainer *coutput1 =
    mgr->CreateContainer(Form("Tree_dsekihat_Cen%d_%d_%s",CenMin,CenMax,triggername.Data()),
                         TTree::Class(),
                         AliAnalysisManager::kExchangeContainer,
                         Form("%s",outputFileName.Data()));

  AliAnalysisDataContainer *cOutputHist1 =
    mgr->CreateContainer(Form("Histos_dsekihat_Cen%d_%d_%s",CenMin,CenMax,triggername.Data()),
                         TList::Class(),
                         AliAnalysisManager::kOutputContainer,
                         Form("%s",outputFileName.Data()));

  AliAnalysisDataContainer *cOutputHist2 =
    mgr->CreateContainer(Form("CF_dsekihat_Cen%d_%d_%s",CenMin,CenMax,triggername.Data()),
                         TList::Class(),
                         AliAnalysisManager::kOutputContainer,
                         Form("%s",outputFileName.Data()));

  AliAnalysisDataContainer *cOutputHist3 =
    mgr->CreateContainer(Form("EventStat_dsekihat_Cen%d_%d_%s",CenMin,CenMax,triggername.Data()),
                         TH1D::Class(),
                         AliAnalysisManager::kOutputContainer,
                         Form("%s",outputFileName.Data()));

  mgr->ConnectInput(task,  0, mgr->GetCommonInputContainer());
  mgr->ConnectOutput(task, 0, coutput1 );
  mgr->ConnectOutput(task, 1, cOutputHist1);
  mgr->ConnectOutput(task, 2, cOutputHist2);
  mgr->ConnectOutput(task, 3, cOutputHist3);

  return task;
}

<|endoftext|>


<commit_before>//
//  Copyright (C) 2015 Greg Landrum and NextMove Software
//
//   @@ All Rights Reserved @@
//  This file is part of the RDKit.
//  The contents are covered by the terms of the BSD license
//  which is included in the file license.txt, found at the root
//  of the RDKit source tree.
//
#include <string.h>

#include <string>

#include <GraphMol/RDKitBase.h>
#include <GraphMol/GraphMol.h>
#include <GraphMol/MonomerInfo.h>

namespace RDKit {

static char getOneLetterCode(const AtomPDBResidueInfo *info)
{
  const char *ptr = info->getResidueName().c_str();
  switch (ptr[0]) {
  case 'A':
    if (!strcmp(ptr,"ALA"))
      return 'A';
    if (!strcmp(ptr,"ARG"))
      return 'R';
    if (!strcmp(ptr,"ASN"))
      return 'N';
    if (!strcmp(ptr,"ASP"))
      return 'D';
    break;
  case 'C':
    if (!strcmp(ptr,"CYS"))
      return 'C';
    break;
  case 'D':
    if (!strcmp(ptr,"DAL"))
      return 'a';
    if (!strcmp(ptr,"DAR"))
      return 'r';
    if (!strcmp(ptr,"DAS"))
      return 'd';
    if (!strcmp(ptr,"DCY"))
      return 'c';
    if (!strcmp(ptr,"DGL"))
      return 'e';
    if (!strcmp(ptr,"DGN"))
      return 'q';
    if (!strcmp(ptr,"DHI"))
      return 'h';
    if (!strcmp(ptr,"DIL"))
      return 'i';
    if (!strcmp(ptr,"DLE"))
      return 'l';
    if (!strcmp(ptr,"DLY"))
      return 'k';
    if (!strcmp(ptr,"DPN"))
      return 'f';
    if (!strcmp(ptr,"DPR"))
      return 'p';
    if (!strcmp(ptr,"DSG"))
      return 'n';
    if (!strcmp(ptr,"DSN"))
      return 's';
    if (!strcmp(ptr,"DTH"))
      return 't';
    if (!strcmp(ptr,"DTR"))
      return 'w';
    if (!strcmp(ptr,"DTY"))
      return 'y';
    if (!strcmp(ptr,"DVA"))
      return 'v';
    break;
  case 'G':
    if (!strcmp(ptr,"GLU"))
      return 'E';
    if (!strcmp(ptr,"GLN"))
      return 'Q';
    if (!strcmp(ptr,"GLY"))
      return 'G';
    break;
  case 'H':
    if (!strcmp(ptr,"HIS"))
      return 'H';
    break;
  case 'I':
    if (!strcmp(ptr,"ILE"))
      return 'I';
    break;
  case 'L':
    if (!strcmp(ptr,"LEU"))
      return 'L';
    if (!strcmp(ptr,"LYS"))
      return 'K';
    break;
  case 'M':
    if (!strcmp(ptr,"MET"))
      return 'M';
    if (!strcmp(ptr,"MED"))
      return 'm';
    break;
  case 'P':
    if (!strcmp(ptr,"PHE"))
      return 'F';
    if (!strcmp(ptr,"PRO"))
      return 'P';
    break;
  case 'S':
    if (!strcmp(ptr,"SER"))
      return 'S';
    break;
  case 'T':
    if (!strcmp(ptr,"THR"))
      return 'T';
    if (!strcmp(ptr,"TRP"))
      return 'W';
    if (!strcmp(ptr,"TYR"))
      return 'Y';
    break;
  case 'V':
    if (!strcmp(ptr,"VAL"))
      return 'V';
    break;
  }
  return 'X';
}

std::string MolToSequence(const ROMol &mol)
{
  std::string result;

  for (ROMol::ConstAtomIterator atomIt=mol.beginAtoms();
        atomIt!=mol.endAtoms();++atomIt){
    const Atom *atom = *atomIt;
    AtomPDBResidueInfo *info = (AtomPDBResidueInfo*)(atom->getMonomerInfo());
    if (info && info->getMonomerType()==AtomMonomerInfo::PDBRESIDUE &&
        info->getName() == " CA ") {
      result += getOneLetterCode(info);
    }
  }
  return result;
}

std::string MolToFASTA(const ROMol &mol)
{
  std::string seq = MolToSequence(mol);
  if (seq.empty())
    return "";

  std::string result = ">";
  std::string name;
  if (mol.getPropIfPresent(common_properties::_Name,name))
    result += name;
  result += '\n';
  result += seq;
  result += '\n';
  return result;
}

static const char *getHELMMonomer(const AtomPDBResidueInfo *info)
{
  const char *ptr = info->getResidueName().c_str();
  switch (ptr[0]) {
  case 'A':
    if (!strcmp(ptr,"ALA"))
      return "A";
    if (!strcmp(ptr,"ARG"))
      return "R";
    if (!strcmp(ptr,"ASN"))
      return "N";
    if (!strcmp(ptr,"ASP"))
      return "D";
    break;
  case 'C':
    if (!strcmp(ptr,"CYS"))
      return "C";
    break;
  case 'D':
    if (!strcmp(ptr,"DAL"))
      return "[dA]";
    if (!strcmp(ptr,"DAR"))
      return "[dR]";
    if (!strcmp(ptr,"DAS"))
      return "[dD]";
    if (!strcmp(ptr,"DCY"))
      return "[dC]";
    if (!strcmp(ptr,"DGL"))
      return "[dE]";
    if (!strcmp(ptr,"DGN"))
      return "[dQ]";
    if (!strcmp(ptr,"DHI"))
      return "[dH]";
    if (!strcmp(ptr,"DLE"))
      return "[dL]";
    if (!strcmp(ptr,"DLY"))
      return "[dK]";
    if (!strcmp(ptr,"DPN"))
      return "[dF]";
    if (!strcmp(ptr,"DPR"))
      return "[dP]";
    if (!strcmp(ptr,"DSG"))
      return "[dN]";
    if (!strcmp(ptr,"DSN"))
      return "[dS]";
    if (!strcmp(ptr,"DTR"))
      return "[dW]";
    if (!strcmp(ptr,"DTY"))
      return "[dY]";
    if (!strcmp(ptr,"DVA"))
      return "[dV]";
    break;
  case 'G':
    if (!strcmp(ptr,"GLU"))
      return "E";
    if (!strcmp(ptr,"GLN"))
      return "Q";
    if (!strcmp(ptr,"GLY"))
      return "G";
    break;
  case 'H':
    if (!strcmp(ptr,"HIS"))
      return "H";
    break;
  case 'I':
    if (!strcmp(ptr,"ILE"))
      return "I";
    break;
  case 'L':
    if (!strcmp(ptr,"LEU"))
      return "L";
    if (!strcmp(ptr,"LYS"))
      return "K";
    break;
  case 'M':
    if (!strcmp(ptr,"MET"))
      return "M";
    if (!strcmp(ptr,"MED"))
      return "[dM]";
    if (!strcmp(ptr,"MSE"))
      return "[seC]";
    break;
  case 'N':
    if (!strcmp(ptr,"NLE"))
      return "[Nle]";
    if (!strcmp(ptr,"NVA"))
      return "[Nva]";
    break;
  case 'O':
    if (!strcmp(ptr,"ORN"))
      return "[Orn]";
    break;
  case 'P':
    if (!strcmp(ptr,"PHE"))
      return "F";
    if (!strcmp(ptr,"PRO"))
      return "P";
    break;
  case 'S':
    if (!strcmp(ptr,"SER"))
      return "S";
    break;
  case 'T':
    if (!strcmp(ptr,"THR"))
      return "T";
    if (!strcmp(ptr,"TRP"))
      return "W";
    if (!strcmp(ptr,"TYR"))
      return "Y";
    break;
  case 'V':
    if (!strcmp(ptr,"VAL"))
      return "V";
    break;
  }
  return (const char*)0;
}

static bool IsEupeptideBond(AtomPDBResidueInfo *src,
                            AtomPDBResidueInfo *dst)
{
  if (src->getChainId() != dst->getChainId())
    return false;

  int sresno = src->getResidueNumber();
  int dresno = dst->getResidueNumber();

  if (src->getName() == " C  " && dst->getName() == " N  ") {
    if (sresno != dresno)
      return dresno > sresno;
    return dst->getInsertionCode() > src->getInsertionCode();
  }
  if (src->getName() == " N  " && dst->getName() == " C  ") {
    if (sresno != dresno)
      return dresno < sresno;
    return dst->getInsertionCode() < src->getInsertionCode();
  }
  return false;
}

static bool IsSupportedHELMBond(AtomPDBResidueInfo *src,
                                AtomPDBResidueInfo *dst)
{
  if (src->getName()==" SG " && dst->getName()==" SG ") {
    if ((src->getResidueName()=="CYS" ||
         src->getResidueName()=="DCY") &&
        (dst->getResidueName()=="CYS" ||
         dst->getResidueName()=="DCY"))
      return true;
  }

  if (src->getName()==" N  " && dst->getName()==" C  ")
    return true;
  if (src->getName()==" C  " && dst->getName()==" N  ")
    return true;
#if 0
  printf("%s%d%s.%s - %s%d%s.%s\n",
         src->getResidueName().c_str(),src->getResidueNumber(),
         src->getChainId().c_str(),src->getName().c_str(),
         dst->getResidueName().c_str(),dst->getResidueNumber(),
         dst->getChainId().c_str(),dst->getName().c_str());
#endif
  return false;
}

static bool FindHELMAtom(std::vector<AtomPDBResidueInfo*> *seq,
                         AtomPDBResidueInfo *info,
                         std::string &id, std::string &pos)
{
  char buffer[32];
  char ch;

  const char *ptr = info->getName().c_str();
  if (ptr[0]==' ' && ptr[1]=='S' && ptr[2]=='G' && ptr[3]==' ')
    ch = '3';
  else if (ptr[0]==' ' && ptr[1]=='N' && ptr[2]==' ' && ptr[3]==' ')
    ch = '1';
  else if (ptr[0]==' ' && ptr[1]=='C' && ptr[2]==' ' && ptr[3]==' ')
    ch = '2';
  else return false;

  int resno = info->getResidueNumber();
  for (unsigned int i=1; i<10; i++) {
    unsigned int len = (unsigned int)seq[i].size();
    for (unsigned int j=0; j<len; j++) {
      AtomPDBResidueInfo *targ = seq[i][j];
      if (targ->getResidueNumber() == resno &&
          targ->getResidueName() == info->getResidueName() &&
          targ->getChainId() == info->getChainId() &&
          targ->getInsertionCode() == info->getInsertionCode()) {
        id = "PEPTIDE";
        id += (char)(i+'0');
        sprintf(buffer,"%u:R%c",j+1,ch);
        pos = buffer;
        return true;
      }
    }
  }
  return false;
}

static std::string NameHELMBond(std::vector<AtomPDBResidueInfo*> *seq,
                                AtomPDBResidueInfo *src,
                                AtomPDBResidueInfo *dst)
{
  std::string id1,pos1;
  if (!FindHELMAtom(seq,src,id1,pos1))
    return "";
  std::string id2,pos2;
  if (!FindHELMAtom(seq,dst,id2,pos2))
    return "";

  std::string result = id1;
  result += ',';
  result += id2;
  result += ',';
  result += pos1;
  result += '-';
  result += pos2;
  return result;
}

std::string MolToHELM(const ROMol &mol)
{
  std::vector<AtomPDBResidueInfo*> seq[10];
  std::string result;
  bool first = true;
  std::string chain;
  int id = 1;

  /* First pass: Monomers */
  for (ROMol::ConstAtomIterator atomIt=mol.beginAtoms();
        atomIt!=mol.endAtoms();++atomIt){
    const Atom *atom = *atomIt;
    AtomPDBResidueInfo *info = (AtomPDBResidueInfo*)(atom->getMonomerInfo());
    // We can only write HELM if all atoms have PDB residue information
    if (!info || info->getMonomerType()!=AtomMonomerInfo::PDBRESIDUE)
      return "";

    if (info->getName() == " CA ") {
      const char *mono = getHELMMonomer(info);
      if (!mono)
        return "";
      if (first) {
        chain = info->getChainId();
        result = "PEPTIDE1{";
        first = false;
      } else if (info->getChainId() != chain) {
        // Nine chains should be enough?
        if (id == 9)
          return "";
        id++;
        chain = info->getChainId();
        result += "}|PEPTIDE";
        result += (char)(id+'0');
        result += "{";
      } else result += ".";
      result += mono;
      seq[id].push_back(info);
    } else if (info->getResidueName() == "NH2" &&
               info->getName() == " N  ") {
      if (first)
        return "";
      result += ".[am]";
    } else if (info->getResidueName() == "ACE" &&
               info->getName() == " C  ") {
      if (first) {
        chain = info->getChainId();
        result = "PEPTIDE1{[ac]";
        first = false;
      } else if (info->getChainId() != chain) {
        // Nine chains should be enough?
        if (id == 9)
          return "";
        id++;
        chain = info->getChainId();
        result += "}|PEPTIDE";
        result += (char)(id+'0');
        result += "{[ac]";
      } else return "";
      seq[id].push_back(info);
    }
  }

  if (first)
    return "";

  result += "}$";

  first = true;
  for (ROMol::ConstBondIterator bondIt=mol.beginBonds();
       bondIt!=mol.endBonds(); ++bondIt){
    const Bond *bond = *bondIt;
    Atom *beg = bond->getBeginAtom();
    Atom *end = bond->getEndAtom();
    if (!beg || !end)
      continue;
    AtomPDBResidueInfo *binfo = (AtomPDBResidueInfo*)(beg->getMonomerInfo());
    AtomPDBResidueInfo *einfo = (AtomPDBResidueInfo*)(end->getMonomerInfo());
    if (!binfo || !einfo)
      continue;
    // Test if this is an uninteresting intra-residue bond
    if (binfo->getResidueNumber() == einfo->getResidueNumber() &&
        binfo->getResidueName() == einfo->getResidueName() &&
        binfo->getChainId() == einfo->getChainId() &&
        binfo->getInsertionCode() == einfo->getInsertionCode())
      continue;
    if (bond->getBondType() != Bond::SINGLE)
      return "";
    if (IsEupeptideBond(binfo,einfo))
      continue;
    if (!IsSupportedHELMBond(binfo,einfo))
      return "";
    std::string tmp = NameHELMBond(seq,binfo,einfo);
    if (tmp.empty())
      return "";
    if (!first)
      result += "|";
    else first = false;
    result += tmp;
  }

  result += "$$$";
  return result;
}

} // namespace RDKit

<commit_msg>Fixes sprintf not found on some gcc compiles<commit_after>//
//  Copyright (C) 2015 Greg Landrum and NextMove Software
//
//   @@ All Rights Reserved @@
//  This file is part of the RDKit.
//  The contents are covered by the terms of the BSD license
//  which is included in the file license.txt, found at the root
//  of the RDKit source tree.
//
#include <string.h>
#include <stdio.h>
#include <string>

#include <GraphMol/RDKitBase.h>
#include <GraphMol/GraphMol.h>
#include <GraphMol/MonomerInfo.h>

namespace RDKit {

static char getOneLetterCode(const AtomPDBResidueInfo *info)
{
  const char *ptr = info->getResidueName().c_str();
  switch (ptr[0]) {
  case 'A':
    if (!strcmp(ptr,"ALA"))
      return 'A';
    if (!strcmp(ptr,"ARG"))
      return 'R';
    if (!strcmp(ptr,"ASN"))
      return 'N';
    if (!strcmp(ptr,"ASP"))
      return 'D';
    break;
  case 'C':
    if (!strcmp(ptr,"CYS"))
      return 'C';
    break;
  case 'D':
    if (!strcmp(ptr,"DAL"))
      return 'a';
    if (!strcmp(ptr,"DAR"))
      return 'r';
    if (!strcmp(ptr,"DAS"))
      return 'd';
    if (!strcmp(ptr,"DCY"))
      return 'c';
    if (!strcmp(ptr,"DGL"))
      return 'e';
    if (!strcmp(ptr,"DGN"))
      return 'q';
    if (!strcmp(ptr,"DHI"))
      return 'h';
    if (!strcmp(ptr,"DIL"))
      return 'i';
    if (!strcmp(ptr,"DLE"))
      return 'l';
    if (!strcmp(ptr,"DLY"))
      return 'k';
    if (!strcmp(ptr,"DPN"))
      return 'f';
    if (!strcmp(ptr,"DPR"))
      return 'p';
    if (!strcmp(ptr,"DSG"))
      return 'n';
    if (!strcmp(ptr,"DSN"))
      return 's';
    if (!strcmp(ptr,"DTH"))
      return 't';
    if (!strcmp(ptr,"DTR"))
      return 'w';
    if (!strcmp(ptr,"DTY"))
      return 'y';
    if (!strcmp(ptr,"DVA"))
      return 'v';
    break;
  case 'G':
    if (!strcmp(ptr,"GLU"))
      return 'E';
    if (!strcmp(ptr,"GLN"))
      return 'Q';
    if (!strcmp(ptr,"GLY"))
      return 'G';
    break;
  case 'H':
    if (!strcmp(ptr,"HIS"))
      return 'H';
    break;
  case 'I':
    if (!strcmp(ptr,"ILE"))
      return 'I';
    break;
  case 'L':
    if (!strcmp(ptr,"LEU"))
      return 'L';
    if (!strcmp(ptr,"LYS"))
      return 'K';
    break;
  case 'M':
    if (!strcmp(ptr,"MET"))
      return 'M';
    if (!strcmp(ptr,"MED"))
      return 'm';
    break;
  case 'P':
    if (!strcmp(ptr,"PHE"))
      return 'F';
    if (!strcmp(ptr,"PRO"))
      return 'P';
    break;
  case 'S':
    if (!strcmp(ptr,"SER"))
      return 'S';
    break;
  case 'T':
    if (!strcmp(ptr,"THR"))
      return 'T';
    if (!strcmp(ptr,"TRP"))
      return 'W';
    if (!strcmp(ptr,"TYR"))
      return 'Y';
    break;
  case 'V':
    if (!strcmp(ptr,"VAL"))
      return 'V';
    break;
  }
  return 'X';
}

std::string MolToSequence(const ROMol &mol)
{
  std::string result;

  for (ROMol::ConstAtomIterator atomIt=mol.beginAtoms();
        atomIt!=mol.endAtoms();++atomIt){
    const Atom *atom = *atomIt;
    AtomPDBResidueInfo *info = (AtomPDBResidueInfo*)(atom->getMonomerInfo());
    if (info && info->getMonomerType()==AtomMonomerInfo::PDBRESIDUE &&
        info->getName() == " CA ") {
      result += getOneLetterCode(info);
    }
  }
  return result;
}

std::string MolToFASTA(const ROMol &mol)
{
  std::string seq = MolToSequence(mol);
  if (seq.empty())
    return "";

  std::string result = ">";
  std::string name;
  if (mol.getPropIfPresent(common_properties::_Name,name))
    result += name;
  result += '\n';
  result += seq;
  result += '\n';
  return result;
}

static const char *getHELMMonomer(const AtomPDBResidueInfo *info)
{
  const char *ptr = info->getResidueName().c_str();
  switch (ptr[0]) {
  case 'A':
    if (!strcmp(ptr,"ALA"))
      return "A";
    if (!strcmp(ptr,"ARG"))
      return "R";
    if (!strcmp(ptr,"ASN"))
      return "N";
    if (!strcmp(ptr,"ASP"))
      return "D";
    break;
  case 'C':
    if (!strcmp(ptr,"CYS"))
      return "C";
    break;
  case 'D':
    if (!strcmp(ptr,"DAL"))
      return "[dA]";
    if (!strcmp(ptr,"DAR"))
      return "[dR]";
    if (!strcmp(ptr,"DAS"))
      return "[dD]";
    if (!strcmp(ptr,"DCY"))
      return "[dC]";
    if (!strcmp(ptr,"DGL"))
      return "[dE]";
    if (!strcmp(ptr,"DGN"))
      return "[dQ]";
    if (!strcmp(ptr,"DHI"))
      return "[dH]";
    if (!strcmp(ptr,"DLE"))
      return "[dL]";
    if (!strcmp(ptr,"DLY"))
      return "[dK]";
    if (!strcmp(ptr,"DPN"))
      return "[dF]";
    if (!strcmp(ptr,"DPR"))
      return "[dP]";
    if (!strcmp(ptr,"DSG"))
      return "[dN]";
    if (!strcmp(ptr,"DSN"))
      return "[dS]";
    if (!strcmp(ptr,"DTR"))
      return "[dW]";
    if (!strcmp(ptr,"DTY"))
      return "[dY]";
    if (!strcmp(ptr,"DVA"))
      return "[dV]";
    break;
  case 'G':
    if (!strcmp(ptr,"GLU"))
      return "E";
    if (!strcmp(ptr,"GLN"))
      return "Q";
    if (!strcmp(ptr,"GLY"))
      return "G";
    break;
  case 'H':
    if (!strcmp(ptr,"HIS"))
      return "H";
    break;
  case 'I':
    if (!strcmp(ptr,"ILE"))
      return "I";
    break;
  case 'L':
    if (!strcmp(ptr,"LEU"))
      return "L";
    if (!strcmp(ptr,"LYS"))
      return "K";
    break;
  case 'M':
    if (!strcmp(ptr,"MET"))
      return "M";
    if (!strcmp(ptr,"MED"))
      return "[dM]";
    if (!strcmp(ptr,"MSE"))
      return "[seC]";
    break;
  case 'N':
    if (!strcmp(ptr,"NLE"))
      return "[Nle]";
    if (!strcmp(ptr,"NVA"))
      return "[Nva]";
    break;
  case 'O':
    if (!strcmp(ptr,"ORN"))
      return "[Orn]";
    break;
  case 'P':
    if (!strcmp(ptr,"PHE"))
      return "F";
    if (!strcmp(ptr,"PRO"))
      return "P";
    break;
  case 'S':
    if (!strcmp(ptr,"SER"))
      return "S";
    break;
  case 'T':
    if (!strcmp(ptr,"THR"))
      return "T";
    if (!strcmp(ptr,"TRP"))
      return "W";
    if (!strcmp(ptr,"TYR"))
      return "Y";
    break;
  case 'V':
    if (!strcmp(ptr,"VAL"))
      return "V";
    break;
  }
  return (const char*)0;
}

static bool IsEupeptideBond(AtomPDBResidueInfo *src,
                            AtomPDBResidueInfo *dst)
{
  if (src->getChainId() != dst->getChainId())
    return false;

  int sresno = src->getResidueNumber();
  int dresno = dst->getResidueNumber();

  if (src->getName() == " C  " && dst->getName() == " N  ") {
    if (sresno != dresno)
      return dresno > sresno;
    return dst->getInsertionCode() > src->getInsertionCode();
  }
  if (src->getName() == " N  " && dst->getName() == " C  ") {
    if (sresno != dresno)
      return dresno < sresno;
    return dst->getInsertionCode() < src->getInsertionCode();
  }
  return false;
}

static bool IsSupportedHELMBond(AtomPDBResidueInfo *src,
                                AtomPDBResidueInfo *dst)
{
  if (src->getName()==" SG " && dst->getName()==" SG ") {
    if ((src->getResidueName()=="CYS" ||
         src->getResidueName()=="DCY") &&
        (dst->getResidueName()=="CYS" ||
         dst->getResidueName()=="DCY"))
      return true;
  }

  if (src->getName()==" N  " && dst->getName()==" C  ")
    return true;
  if (src->getName()==" C  " && dst->getName()==" N  ")
    return true;
#if 0
  printf("%s%d%s.%s - %s%d%s.%s\n",
         src->getResidueName().c_str(),src->getResidueNumber(),
         src->getChainId().c_str(),src->getName().c_str(),
         dst->getResidueName().c_str(),dst->getResidueNumber(),
         dst->getChainId().c_str(),dst->getName().c_str());
#endif
  return false;
}

static bool FindHELMAtom(std::vector<AtomPDBResidueInfo*> *seq,
                         AtomPDBResidueInfo *info,
                         std::string &id, std::string &pos)
{
  char buffer[32];
  char ch;

  const char *ptr = info->getName().c_str();
  if (ptr[0]==' ' && ptr[1]=='S' && ptr[2]=='G' && ptr[3]==' ')
    ch = '3';
  else if (ptr[0]==' ' && ptr[1]=='N' && ptr[2]==' ' && ptr[3]==' ')
    ch = '1';
  else if (ptr[0]==' ' && ptr[1]=='C' && ptr[2]==' ' && ptr[3]==' ')
    ch = '2';
  else return false;

  int resno = info->getResidueNumber();
  for (unsigned int i=1; i<10; i++) {
    unsigned int len = (unsigned int)seq[i].size();
    for (unsigned int j=0; j<len; j++) {
      AtomPDBResidueInfo *targ = seq[i][j];
      if (targ->getResidueNumber() == resno &&
          targ->getResidueName() == info->getResidueName() &&
          targ->getChainId() == info->getChainId() &&
          targ->getInsertionCode() == info->getInsertionCode()) {
        id = "PEPTIDE";
        id += (char)(i+'0');
        sprintf(buffer,"%u:R%c",j+1,ch);
        pos = buffer;
        return true;
      }
    }
  }
  return false;
}

static std::string NameHELMBond(std::vector<AtomPDBResidueInfo*> *seq,
                                AtomPDBResidueInfo *src,
                                AtomPDBResidueInfo *dst)
{
  std::string id1,pos1;
  if (!FindHELMAtom(seq,src,id1,pos1))
    return "";
  std::string id2,pos2;
  if (!FindHELMAtom(seq,dst,id2,pos2))
    return "";

  std::string result = id1;
  result += ',';
  result += id2;
  result += ',';
  result += pos1;
  result += '-';
  result += pos2;
  return result;
}

std::string MolToHELM(const ROMol &mol)
{
  std::vector<AtomPDBResidueInfo*> seq[10];
  std::string result;
  bool first = true;
  std::string chain;
  int id = 1;

  /* First pass: Monomers */
  for (ROMol::ConstAtomIterator atomIt=mol.beginAtoms();
        atomIt!=mol.endAtoms();++atomIt){
    const Atom *atom = *atomIt;
    AtomPDBResidueInfo *info = (AtomPDBResidueInfo*)(atom->getMonomerInfo());
    // We can only write HELM if all atoms have PDB residue information
    if (!info || info->getMonomerType()!=AtomMonomerInfo::PDBRESIDUE)
      return "";

    if (info->getName() == " CA ") {
      const char *mono = getHELMMonomer(info);
      if (!mono)
        return "";
      if (first) {
        chain = info->getChainId();
        result = "PEPTIDE1{";
        first = false;
      } else if (info->getChainId() != chain) {
        // Nine chains should be enough?
        if (id == 9)
          return "";
        id++;
        chain = info->getChainId();
        result += "}|PEPTIDE";
        result += (char)(id+'0');
        result += "{";
      } else result += ".";
      result += mono;
      seq[id].push_back(info);
    } else if (info->getResidueName() == "NH2" &&
               info->getName() == " N  ") {
      if (first)
        return "";
      result += ".[am]";
    } else if (info->getResidueName() == "ACE" &&
               info->getName() == " C  ") {
      if (first) {
        chain = info->getChainId();
        result = "PEPTIDE1{[ac]";
        first = false;
      } else if (info->getChainId() != chain) {
        // Nine chains should be enough?
        if (id == 9)
          return "";
        id++;
        chain = info->getChainId();
        result += "}|PEPTIDE";
        result += (char)(id+'0');
        result += "{[ac]";
      } else return "";
      seq[id].push_back(info);
    }
  }

  if (first)
    return "";

  result += "}$";

  first = true;
  for (ROMol::ConstBondIterator bondIt=mol.beginBonds();
       bondIt!=mol.endBonds(); ++bondIt){
    const Bond *bond = *bondIt;
    Atom *beg = bond->getBeginAtom();
    Atom *end = bond->getEndAtom();
    if (!beg || !end)
      continue;
    AtomPDBResidueInfo *binfo = (AtomPDBResidueInfo*)(beg->getMonomerInfo());
    AtomPDBResidueInfo *einfo = (AtomPDBResidueInfo*)(end->getMonomerInfo());
    if (!binfo || !einfo)
      continue;
    // Test if this is an uninteresting intra-residue bond
    if (binfo->getResidueNumber() == einfo->getResidueNumber() &&
        binfo->getResidueName() == einfo->getResidueName() &&
        binfo->getChainId() == einfo->getChainId() &&
        binfo->getInsertionCode() == einfo->getInsertionCode())
      continue;
    if (bond->getBondType() != Bond::SINGLE)
      return "";
    if (IsEupeptideBond(binfo,einfo))
      continue;
    if (!IsSupportedHELMBond(binfo,einfo))
      return "";
    std::string tmp = NameHELMBond(seq,binfo,einfo);
    if (tmp.empty())
      return "";
    if (!first)
      result += "|";
    else first = false;
    result += tmp;
  }

  result += "$$$";
  return result;
}

} // namespace RDKit

<|endoftext|>


<commit_before>#include <iostream>
#include <algorithm>
#include <iterator>
#include <vector>

#define Iterator typename
#define Functor typename

template <Iterator Iterator_t, Functor Functor_t>
class ConditionalIterator
{
public:
  bool operator==(ConditionalIterator<Iterator_t, Functor_t> that) const
  {
    return iterator_ == that.iterator_;
  }

  bool operator!=(ConditionalIterator<Iterator_t, Functor_t> that) const
  {
    return iterator_ != that.iterator_;
  }

  ConditionalIterator<Iterator_t, Functor_t>& operator++()
  {
    if (iterator_ == end_) return *this;

    ++iterator_;

    while (iterator_ != end_ && !f_(*(iterator_)))
    {
      ++iterator_;
    }

    return *this;
  }

  ConditionalIterator(Iterator_t iterator, Iterator_t end, Functor_t f)
      : iterator_(iterator), end_(end), f_(f)
  {
    while (iterator_ != end_ && !f_(*iterator_))
    {
      ++iterator_;
    }
  }

private:
  Iterator_t iterator_;
  Iterator_t end_;
  Functor_t f_;

public:
  auto operator*() const -> decltype(*iterator_) { return *iterator_; }
};

template <Iterator Iterator_t, Functor Functor_t>
std::pair<ConditionalIterator<Iterator_t, Functor_t>,
          ConditionalIterator<Iterator_t, Functor_t>>
make_conditional_begin_and_end(Iterator_t begin, Iterator_t end,
                               Functor_t condition)
{
  return {ConditionalIterator<Iterator_t, Functor_t>(begin, end, condition),
          ConditionalIterator<Iterator_t, Functor_t>(end, end, condition)};
}

int main(int argc, char* argv[])
{
  std::vector<int> numbers = {1, 2, 3, 5, 6, 7, 5, 4, 3, 2, 3,
                              4, 5, 7, 9, 2, 1, 3, 4, 5, 7, 3};

  auto isThree = [](int x)
  { return x == 3; };

  auto conditional_begin_end =
      make_conditional_begin_and_end(numbers.begin(), numbers.end(), isThree);
  std::ostream_iterator<int> osi(std::cout, " ");

  std::copy(numbers.begin(), numbers.end(), osi);
  std::cout << "\n3 appears in the list "
            << std::count_if(numbers.begin(), numbers.end(), isThree)
            << " times" << std::endl;
  std::copy(conditional_begin_end.first, conditional_begin_end.second, osi);
  std::cout << std::endl;
}
<commit_msg>remove check to get closer to raw loop performance<commit_after>#include <iostream>
#include <algorithm>
#include <iterator>
#include <vector>

#define Iterator typename
#define FunctionObject typename

template <Iterator Iterator_t, FunctionObject FunctionObject_t>
class ConditionalIterator
{
public:
  bool operator==(ConditionalIterator<Iterator_t, FunctionObject_t> that) const
  {
    return iterator_ == that.iterator_;
  }

  bool operator!=(ConditionalIterator<Iterator_t, FunctionObject_t> that) const
  {
    return iterator_ != that.iterator_;
  }

  ConditionalIterator<Iterator_t, FunctionObject_t>& operator++()
  {
    // NB this is unsafe if called when an iterator is already equal to end

		++iterator_;

    while (iterator_ != end_ && !f_(*(iterator_)))
    {
      ++iterator_;
    }

    return *this;
  }

  ConditionalIterator(Iterator_t iterator, Iterator_t end, FunctionObject_t f)
      : iterator_(iterator), end_(end), f_(f)
  {
    while (iterator_ != end_ && !f_(*iterator_))
    {
      ++iterator_;
    }
  }

private:
  Iterator_t iterator_;
  Iterator_t end_;
  FunctionObject_t f_;

public:
  auto operator*() const { return *iterator_; }
};

template <Iterator Iterator_t, FunctionObject FunctionObject_t>
std::pair<ConditionalIterator<Iterator_t, FunctionObject_t>,
          ConditionalIterator<Iterator_t, FunctionObject_t>>
make_conditional_begin_and_end(Iterator_t begin, Iterator_t end,
                               FunctionObject_t condition)
{
  return {ConditionalIterator<Iterator_t, FunctionObject_t>(begin, end, condition),
          ConditionalIterator<Iterator_t, FunctionObject_t>(end, end, condition)};
}

int main(int argc, char* argv[])
{
  std::vector<int> numbers = {1, 2, 3, 5, 6, 7, 5, 4, 3, 2, 3,
                              4, 5, 7, 9, 2, 1, 3, 4, 5, 7, 3};

  auto isThree = [](int x)
  { return x == 3; };

  auto conditional_begin_end =
      make_conditional_begin_and_end(numbers.begin(), numbers.end(), isThree);
  std::ostream_iterator<int> osi(std::cout, " ");

  std::copy(numbers.begin(), numbers.end(), osi);
  std::cout << "\n3 appears in the list "
            << std::count_if(numbers.begin(), numbers.end(), isThree)
            << " times" << std::endl;
  std::copy(conditional_begin_end.first, conditional_begin_end.second, osi);
  std::cout << std::endl;
}
<|endoftext|>


<commit_before>/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Language:  C++
Date:      $Date$
Version:   $Revision$

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "mitkOrganTypeProperty.h"

mitk::OrganTypeProperty::OrganTypeProperty()
{
  AddEnumerationTypes();
}

mitk::OrganTypeProperty::OrganTypeProperty( const IdType& value )
{
  AddEnumerationTypes();
  if ( IsValidEnumerationValue( value ) )
  {
    SetValue( value ) ;
  }
  else
  {
    SetValue( 0 );
  }
}

mitk::OrganTypeProperty::OrganTypeProperty( const std::string& value )
{
  AddEnumerationTypes();
  if ( IsValidEnumerationValue( value ) )
  {
    SetValue( value );
  }
  else
  {
    SetValue( "undefined" );
  }
}

mitk::OrganTypeProperty::~OrganTypeProperty()
{
}

void mitk::OrganTypeProperty::AddEnumerationTypes()
{
  IdType newId = EnumerationProperty::Size();

  // On changes, please also change mitk::DataTreeNodeFactory::DefaultColorForOrgan()

  AddEnum( "undefined", newId++ );
  AddEnum( "Ankle", newId++ );
  AddEnum( "Appendix", newId++ );
  AddEnum( "Blood vessels", newId++ );
  AddEnum( "Bone", newId++ );
  AddEnum( "Brain", newId++ );
  AddEnum( "Bronchial tree", newId++ );
  AddEnum( "Coccyx", newId++ );
  AddEnum( "Colon", newId++ );
  AddEnum( "Cyst", newId++ );
  AddEnum( "Elbow", newId++ );
  AddEnum( "Eye", newId++ );
  AddEnum( "Fallopian tube", newId++ );
  AddEnum( "Gall bladder", newId++ );
  AddEnum( "Hand", newId++ );
  AddEnum( "Heart", newId++ );
  AddEnum( "Hip", newId++ );
  AddEnum( "Kidney", newId++ );
  AddEnum( "Knee", newId++ );
  AddEnum( "Larynx", newId++ );
  AddEnum( "Liver", newId++ );
  AddEnum( "Lung", newId++ );
  AddEnum( "Lymph node", newId++ );
  AddEnum( "Muscle", newId++ );
  AddEnum( "Nerve", newId++ );
  AddEnum( "Nose", newId++ );
  AddEnum( "Oesophagus", newId++ );
  AddEnum( "Ovaries", newId++ );
  AddEnum( "Pancreas", newId++ );
  AddEnum( "Pelvis", newId++ );
  AddEnum( "Penis", newId++ );
  AddEnum( "Pharynx", newId++ );
  AddEnum( "Prostate", newId++ );
  AddEnum( "Rectum", newId++ );
  AddEnum( "Sacrum", newId++ );
  AddEnum( "Seminal vesicle", newId++ );
  AddEnum( "Shoulder", newId++ );
  AddEnum( "Spinal cord", newId++ );
  AddEnum( "Spleen", newId++ );
  AddEnum( "Stomach", newId++ );
  AddEnum( "Teeth", newId++ );
  AddEnum( "Testicles", newId++ );
  AddEnum( "Thyroid", newId++ );
  AddEnum( "Tongue", newId++ );
  AddEnum( "Tumor", newId++ );
  AddEnum( "Urethra", newId++ );
  AddEnum( "Urinary bladder", newId++ );
  AddEnum( "Uterus", newId++ );
  AddEnum( "Vagina", newId++ );
  AddEnum( "Vertebra", newId++ );
  AddEnum( "Wrist", newId++ );
}

<commit_msg>CHG (#1891): add Enumeration Type for FAT<commit_after>/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Language:  C++
Date:      $Date$
Version:   $Revision$

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "mitkOrganTypeProperty.h"

mitk::OrganTypeProperty::OrganTypeProperty()
{
  AddEnumerationTypes();
}

mitk::OrganTypeProperty::OrganTypeProperty( const IdType& value )
{
  AddEnumerationTypes();
  if ( IsValidEnumerationValue( value ) )
  {
    SetValue( value ) ;
  }
  else
  {
    SetValue( 0 );
  }
}

mitk::OrganTypeProperty::OrganTypeProperty( const std::string& value )
{
  AddEnumerationTypes();
  if ( IsValidEnumerationValue( value ) )
  {
    SetValue( value );
  }
  else
  {
    SetValue( "undefined" );
  }
}

mitk::OrganTypeProperty::~OrganTypeProperty()
{
}

void mitk::OrganTypeProperty::AddEnumerationTypes()
{
  IdType newId = EnumerationProperty::Size();

  // On changes, please also change mitk::DataTreeNodeFactory::DefaultColorForOrgan()

  AddEnum( "undefined", newId++ );
  AddEnum( "Ankle", newId++ );
  AddEnum( "Appendix", newId++ );
  AddEnum( "Blood vessels", newId++ );
  AddEnum( "Bone", newId++ );
  AddEnum( "Brain", newId++ );
  AddEnum( "Bronchial tree", newId++ );
  AddEnum( "Coccyx", newId++ );
  AddEnum( "Colon", newId++ );
  AddEnum( "Cyst", newId++ );
  AddEnum( "Elbow", newId++ );
  AddEnum( "Eye", newId++ );
  AddEnum( "Fallopian tube", newId++ );
  AddEnum( "Fat", newId++ );
  AddEnum( "Gall bladder", newId++ );
  AddEnum( "Hand", newId++ );
  AddEnum( "Heart", newId++ );
  AddEnum( "Hip", newId++ );
  AddEnum( "Kidney", newId++ );
  AddEnum( "Knee", newId++ );
  AddEnum( "Larynx", newId++ );
  AddEnum( "Liver", newId++ );
  AddEnum( "Lung", newId++ );
  AddEnum( "Lymph node", newId++ );
  AddEnum( "Muscle", newId++ );
  AddEnum( "Nerve", newId++ );
  AddEnum( "Nose", newId++ );
  AddEnum( "Oesophagus", newId++ );
  AddEnum( "Ovaries", newId++ );
  AddEnum( "Pancreas", newId++ );
  AddEnum( "Pelvis", newId++ );
  AddEnum( "Penis", newId++ );
  AddEnum( "Pharynx", newId++ );
  AddEnum( "Prostate", newId++ );
  AddEnum( "Rectum", newId++ );
  AddEnum( "Sacrum", newId++ );
  AddEnum( "Seminal vesicle", newId++ );
  AddEnum( "Shoulder", newId++ );
  AddEnum( "Spinal cord", newId++ );
  AddEnum( "Spleen", newId++ );
  AddEnum( "Stomach", newId++ );
  AddEnum( "Teeth", newId++ );
  AddEnum( "Testicles", newId++ );
  AddEnum( "Thyroid", newId++ );
  AddEnum( "Tongue", newId++ );
  AddEnum( "Tumor", newId++ );
  AddEnum( "Urethra", newId++ );
  AddEnum( "Urinary bladder", newId++ );
  AddEnum( "Uterus", newId++ );
  AddEnum( "Vagina", newId++ );
  AddEnum( "Vertebra", newId++ );
  AddEnum( "Wrist", newId++ );
}

<|endoftext|>


<commit_before>#include <chrono>
#include <cstring>
#include <ctime>
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <signal.h>
#include <sstream>
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <thread>
#include <unistd.h>

#include "libs/exceptionpp/exception.h"

#include "src/msg_node.h"

msgpp::Message::Message(size_t id, std::string ip, std::string hostname, std::string message) : id(id), ip(ip), hostname(hostname), message(message) {}

size_t msgpp::Message::get_identifier() { return(this->id); }
std::string msgpp::Message::get_ip() { return(this->ip); }
std::string msgpp::Message::get_hostname() { return(this->hostname); }
std::string msgpp::Message::get_message() { return(this->message); }

std::vector<std::shared_ptr<msgpp::MessageNode>> msgpp::MessageNode::instances;
std::recursive_mutex msgpp::MessageNode::l;
std::chrono::milliseconds msgpp::MessageNode::increment = std::chrono::milliseconds(100);
sighandler_t msgpp::MessageNode::handler;

msgpp::MessageNode::MessageNode(size_t port, uint8_t protocol, size_t timeout, size_t max_conn) : protocol(protocol), port(port), timeout(timeout), max_conn(max_conn) {
	this->flag = std::shared_ptr<std::atomic<bool>> (new std::atomic<bool> (0));
}

uint8_t msgpp::MessageNode::get_protocol() { return(this->protocol); }
size_t msgpp::MessageNode::get_port() { return(this->port); }
size_t msgpp::MessageNode::get_timeout() { return(this->timeout); }
size_t msgpp::MessageNode::get_max_conn() { return(this->max_conn); }
bool msgpp::MessageNode::get_status() { return(*(this->flag)); }
void msgpp::MessageNode::set_timeout(size_t timeout) { this->timeout = timeout; }

void msgpp::MessageNode::up() {
	{
		std::lock_guard<std::recursive_mutex> lock(msgpp::MessageNode::l);
		if(*flag == 1) {
			return;
		}
		if(msgpp::MessageNode::instances.size() == 0) {
			msgpp::MessageNode::handler = signal(SIGINT, msgpp::MessageNode::term);
		}
		*flag = 1;
		msgpp::MessageNode::instances.push_back(this->shared_from_this());
	}

	std::stringstream port;
	port << this->port;

	int server_sock, status;
	struct addrinfo info;
	struct addrinfo *list;
	memset(&info, 0, sizeof(info));

	if(this->protocol & msgpp::MessageNode::ipv6) {
		info.ai_family = AF_INET6;
	} else if(this->protocol & msgpp::MessageNode::ipv4) {
		info.ai_family = AF_INET;
	} else {
		info.ai_family = AF_UNSPEC;
	}
	info.ai_socktype = SOCK_STREAM;
	info.ai_flags = AI_PASSIVE;

	status = getaddrinfo(NULL, port.str().c_str(), &info, &list);
	if(list == NULL) {
		throw(exceptionpp::RuntimeError("msgpp::MessageNode::up", "cannot find address"));
	}

	server_sock = socket(list->ai_family, list->ai_socktype, list->ai_protocol);
	if(server_sock == -1) {
		freeaddrinfo(list);
		throw(exceptionpp::RuntimeError("msgpp::MessageNode::up", "cannot open socket"));
	}

	int yes = 1;
	status = setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
	status = bind(server_sock, list->ai_addr, list->ai_addrlen);
	if(status == -1) {
		freeaddrinfo(list);
		shutdown(server_sock, SHUT_RDWR);
		close(server_sock);
		throw(exceptionpp::RuntimeError("msgpp::MessageNode::up", "cannot bind server-side socket"));
	}

	status = listen(server_sock, this->get_max_conn());
	if(status == -1) {
		freeaddrinfo(list);
		shutdown(server_sock, SHUT_RDWR);
		close(server_sock);
		throw(exceptionpp::RuntimeError("msgpp::MessageNode::up", "cannot listen on server-side socket"));
	}

	// set as non-blocking
	//	cf. http://bit.ly/1tse7i3
	fcntl(server_sock, F_SETFL, O_NONBLOCK);

	this->threads.clear();

	// use sockaddr_storage for protocol-agnostic IP storage
	//	cf. http://bit.ly/1ukHOQ8
	struct sockaddr_storage client_addr;
	memset(&client_addr, sizeof(struct sockaddr_storage), sizeof(char));
	socklen_t client_size = 0;

	while(*(this->flag)) {
		// dispatch any incoming clients
		int client_sock = accept(server_sock, (sockaddr *) &client_addr, &client_size);
		if(client_sock != -1) {
			std::shared_ptr<std::thread> t (new std::thread(&msgpp::MessageNode::dispatch, this, client_sock, client_addr, client_size));
			this->threads.push_back(t);
		}
	}

	// clean up client connections
	for(size_t i = 0; i < this->threads.size(); ++i) {
		this->threads.at(i)->join();
	}

	freeaddrinfo(list);
	shutdown(server_sock, SHUT_RDWR);
	close(server_sock);

	return;
}

void msgpp::MessageNode::dispatch(int client_sock, struct sockaddr_storage client_addr, socklen_t client_size) {
	char host[NI_MAXHOST] = "";
	char ip[NI_MAXHOST] = "";

	getnameinfo((struct sockaddr *) &client_addr, client_size, host, NI_MAXHOST, NULL, 0, 0);
	getnameinfo((struct sockaddr *) &client_addr, client_size, ip, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);

	fcntl(client_sock, F_SETFL, O_NONBLOCK);
	std::stringstream len_buf;
	std::stringstream msg_buf;
	bool is_done = 0;
	size_t size = 0;
	while(!is_done) {
		char tmp_buf[msgpp::MessageNode::size];
		memset(&tmp_buf, 0, msgpp::MessageNode::size);
		int n_bytes = 0;
		time_t start = time(NULL);
		while(((size_t) time(NULL) - start) < this->timeout) {
			n_bytes = recv(client_sock, &tmp_buf, msgpp::MessageNode::size, 0);
			if(n_bytes == -1) {
				if(errno != EAGAIN) {
					break;
				}
				std::this_thread::sleep_for(msgpp::MessageNode::increment);
			} else {
				break;
			}
		}
		if(n_bytes == 0 || n_bytes == -1) {
			// client closed unexpectedly
			// as the message queue is atomically set (i.e., no half-assed data), we will roll back changes and not touch the queue
			break;
		}
		std::string tmp = std::string(tmp_buf, n_bytes);
		if(size == 0) {
			size_t pos = tmp.find(':');
			if(pos == std::string::npos) {
				pos = tmp.size();
			}
			len_buf << tmp.substr(0, pos);
			if(pos != tmp.size()) {
				size = std::stoll(len_buf.str());
				msg_buf << tmp.substr(pos + 1);
			}
		} else {
			msg_buf << tmp;
		}
		if(size != 0) {
			is_done = (msg_buf.str().length() >= size);
		}
	}

	if(is_done && (msg_buf.str().length() >= size)) {
		std::lock_guard<std::mutex> lock(this->messages_l);
		this->messages.push_back(msgpp::Message(++this->count, ip, host, msg_buf.str().substr(0, size)));
	}
	shutdown(client_sock, SHUT_RDWR);
	close(client_sock);
}

void msgpp::MessageNode::dn() {
	std::lock_guard<std::recursive_mutex> lock(msgpp::MessageNode::l);
	if(*(this->flag) == 0) {
		return;
	}
	*(this->flag) = 0;

	// restore signal handler if no more instances are running
	if(msgpp::MessageNode::instances.size() == 0) {
		signal(SIGINT, msgpp::MessageNode::handler);
	}
}

size_t msgpp::MessageNode::query() {
	std::lock_guard<std::mutex> lock(this->messages_l);
	return(this->messages.size());
}

size_t msgpp::MessageNode::push(std::string message, std::string hostname, size_t port, bool silent_fail) {
	std::stringstream port_buf, msg_buf;
	port_buf << port;
	msg_buf << message.length() << ":" << message;

	int client_sock, status;
	struct addrinfo info;
	struct addrinfo *list;
	memset(&info, 0, sizeof(info));

	info.ai_family = AF_UNSPEC;
	info.ai_socktype = SOCK_STREAM;

	getaddrinfo(hostname.c_str(), port_buf.str().c_str(), &info, &list);
	if(list == NULL) {
		if(silent_fail) { return(0); }
		throw(exceptionpp::RuntimeError("msgpp::MessageNode::push", "cannot find endpoint"));
	}
	client_sock = socket(list->ai_family, list->ai_socktype, list->ai_protocol);
	if(client_sock == -1) {
		freeaddrinfo(list);
		shutdown(client_sock, SHUT_RDWR);
		close(client_sock);
		if(silent_fail) { return(0); }
		throw(exceptionpp::RuntimeError("msgpp::MessageNode::push", "cannot open socket"));
	}

	int yes = 1;
	status = setsockopt(client_sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
	fcntl(client_sock, F_SETFL, O_NONBLOCK);

	time_t start = time(NULL);
	while(((size_t) time(NULL) - start) < this->timeout) {
		status = connect(client_sock, list->ai_addr, list->ai_addrlen);
		if(status != -1) {
			break;
		}
		std::this_thread::sleep_for(msgpp::MessageNode::increment);
	}

	if(status == -1) {
		freeaddrinfo(list);
		shutdown(client_sock, SHUT_RDWR);
		close(client_sock);
		if(silent_fail) { return(0); }
		throw(exceptionpp::RuntimeError("msgpp::MessageNode::push", "cannot connect to destination"));
	}

	int result = -1;
	size_t n_bytes = 0;

	start = time(NULL);
	while(((size_t) time(NULL) - start) < this->timeout) {
		result = send(client_sock, msg_buf.str().c_str(), msg_buf.str().length(), 0);
		if(result != -1) {
			n_bytes += result;
			if(n_bytes == msg_buf.str().length()) {
				break;
			}
		} else {
			if(errno == EWOULDBLOCK) {
				std::this_thread::sleep_for(msgpp::MessageNode::increment);
			} else {
				break;
			}
		}
	}

	if(result == -1 || n_bytes != msg_buf.str().length()) {
		freeaddrinfo(list);
		shutdown(client_sock, SHUT_RDWR);
		close(client_sock);
		if(silent_fail) { return(0); }
		throw(exceptionpp::RuntimeError("msgpp::MessageNode::send", "could not send data"));
	}

	freeaddrinfo(list);
	shutdown(client_sock, SHUT_RDWR);
	close(client_sock);

	return(result - (msg_buf.str().length() - message.length()));
}

std::string msgpp::MessageNode::pull(std::string hostname, bool silent_fail) {
	size_t target = 0;
	bool is_found = 0;

	time_t start = time(NULL);
	while(((size_t) time(NULL) - start) < this->timeout) {
		// lock during iteration, but unlock during sleep to give the queue an opportunity to fill up again
		{
			std::lock_guard<std::mutex> lock(this->messages_l);
			if(!this->messages.empty()) {
				for(std::vector<msgpp::Message>::iterator it = this->messages.begin(); it != this->messages.end(); ++it) {
					msgpp::Message instance = *it;
					bool match_h = (instance.get_hostname().compare("") == 0) || (instance.get_ip().compare("") == 0) || (hostname.compare("") == 0) || (hostname.compare(instance.get_hostname()) == 0) || (hostname.compare(instance.get_ip()) == 0);
					if(match_h) {
						target = it->get_identifier();
						is_found = 1;
						break;
					}
				}
			}
		}
		if(is_found) {
			break;
		}
		std::this_thread::sleep_for(msgpp::MessageNode::increment);
	}

	if(!is_found) {
		if(silent_fail) { return(""); }
		throw(exceptionpp::RuntimeError("msgpp::MessageNode::pull", "message does not exist"));
	}

	std::string message;
	{
		std::lock_guard<std::mutex> lock(this->messages_l);
		auto index = this->messages.end();
		for(std::vector<msgpp::Message>::iterator it = this->messages.begin(); it != this->messages.end(); ++it) {
			msgpp::Message instance = *it;
			if(it->get_identifier() == target) {
				index = it;
				message = it->get_message();
			}
		}
		this->messages.erase(index);
	}
	return(message);
}

/**
 * SIGINT handler -- terminate all running MessageNode instances
 */
void msgpp::MessageNode::term(int p) {
	std::lock_guard<std::recursive_mutex> lock(msgpp::MessageNode::l);
	for(std::vector<std::shared_ptr<msgpp::MessageNode>>::iterator it = msgpp::MessageNode::instances.begin(); it != msgpp::MessageNode::instances.end(); ++it) {
		(*it)->dn();
	}
	msgpp::MessageNode::instances.clear();
	// install old sighandler
	//	cf. http://bit.ly/1unilFS
	signal(SIGINT, msgpp::MessageNode::handler);
}
<commit_msg>fixed uninitialized value bug<commit_after>#include <chrono>
#include <cstring>
#include <ctime>
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <signal.h>
#include <sstream>
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <thread>
#include <unistd.h>

#include "libs/exceptionpp/exception.h"

#include "src/msg_node.h"

msgpp::Message::Message(size_t id, std::string ip, std::string hostname, std::string message) : id(id), ip(ip), hostname(hostname), message(message) {}

size_t msgpp::Message::get_identifier() { return(this->id); }
std::string msgpp::Message::get_ip() { return(this->ip); }
std::string msgpp::Message::get_hostname() { return(this->hostname); }
std::string msgpp::Message::get_message() { return(this->message); }

std::vector<std::shared_ptr<msgpp::MessageNode>> msgpp::MessageNode::instances;
std::recursive_mutex msgpp::MessageNode::l;
std::chrono::milliseconds msgpp::MessageNode::increment = std::chrono::milliseconds(100);
sighandler_t msgpp::MessageNode::handler;

msgpp::MessageNode::MessageNode(size_t port, uint8_t protocol, size_t timeout, size_t max_conn) : protocol(protocol), port(port), timeout(timeout), max_conn(max_conn) {
	this->flag = std::shared_ptr<std::atomic<bool>> (new std::atomic<bool> (0));
	this->count = 0;
	this->threads = std::vector<std::shared_ptr<std::thread>> ();
	this->messages = std::vector<msgpp::Message> ();
}

uint8_t msgpp::MessageNode::get_protocol() { return(this->protocol); }
size_t msgpp::MessageNode::get_port() { return(this->port); }
size_t msgpp::MessageNode::get_timeout() { return(this->timeout); }
size_t msgpp::MessageNode::get_max_conn() { return(this->max_conn); }
bool msgpp::MessageNode::get_status() { return(*(this->flag)); }
void msgpp::MessageNode::set_timeout(size_t timeout) { this->timeout = timeout; }

void msgpp::MessageNode::up() {
	{
		std::lock_guard<std::recursive_mutex> lock(msgpp::MessageNode::l);
		if(*flag == 1) {
			return;
		}
		if(msgpp::MessageNode::instances.size() == 0) {
			msgpp::MessageNode::handler = signal(SIGINT, msgpp::MessageNode::term);
		}
		*flag = 1;
		msgpp::MessageNode::instances.push_back(this->shared_from_this());
	}

	std::stringstream port;
	port << this->port;

	int server_sock, status;
	struct addrinfo info;
	struct addrinfo *list;
	memset(&info, 0, sizeof(info));

	if(this->protocol & msgpp::MessageNode::ipv6) {
		info.ai_family = AF_INET6;
	} else if(this->protocol & msgpp::MessageNode::ipv4) {
		info.ai_family = AF_INET;
	} else {
		info.ai_family = AF_UNSPEC;
	}
	info.ai_socktype = SOCK_STREAM;
	info.ai_flags = AI_PASSIVE;

	status = getaddrinfo(NULL, port.str().c_str(), &info, &list);
	if(list == NULL) {
		throw(exceptionpp::RuntimeError("msgpp::MessageNode::up", "cannot find address"));
	}

	server_sock = socket(list->ai_family, list->ai_socktype, list->ai_protocol);
	if(server_sock == -1) {
		freeaddrinfo(list);
		throw(exceptionpp::RuntimeError("msgpp::MessageNode::up", "cannot open socket"));
	}

	int yes = 1;
	status = setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
	status = bind(server_sock, list->ai_addr, list->ai_addrlen);
	if(status == -1) {
		freeaddrinfo(list);
		shutdown(server_sock, SHUT_RDWR);
		close(server_sock);
		throw(exceptionpp::RuntimeError("msgpp::MessageNode::up", "cannot bind server-side socket"));
	}

	status = listen(server_sock, this->get_max_conn());
	if(status == -1) {
		freeaddrinfo(list);
		shutdown(server_sock, SHUT_RDWR);
		close(server_sock);
		throw(exceptionpp::RuntimeError("msgpp::MessageNode::up", "cannot listen on server-side socket"));
	}

	// set as non-blocking
	//	cf. http://bit.ly/1tse7i3
	fcntl(server_sock, F_SETFL, O_NONBLOCK);

	this->threads.clear();

	// use sockaddr_storage for protocol-agnostic IP storage
	//	cf. http://bit.ly/1ukHOQ8
	struct sockaddr_storage client_addr;
	memset(&client_addr, sizeof(struct sockaddr_storage), sizeof(char));
	socklen_t client_size = 0;

	while(*(this->flag)) {
		// dispatch any incoming clients
		int client_sock = accept(server_sock, (sockaddr *) &client_addr, &client_size);
		if(client_sock != -1) {
			std::shared_ptr<std::thread> t (new std::thread(&msgpp::MessageNode::dispatch, this, client_sock, client_addr, client_size));
			this->threads.push_back(t);
		}
	}

	// clean up client connections
	for(size_t i = 0; i < this->threads.size(); ++i) {
		this->threads.at(i)->join();
	}

	freeaddrinfo(list);
	shutdown(server_sock, SHUT_RDWR);
	close(server_sock);

	return;
}

void msgpp::MessageNode::dispatch(int client_sock, struct sockaddr_storage client_addr, socklen_t client_size) {
	char host[NI_MAXHOST] = "";
	char ip[NI_MAXHOST] = "";

	getnameinfo((struct sockaddr *) &client_addr, client_size, host, NI_MAXHOST, NULL, 0, 0);
	getnameinfo((struct sockaddr *) &client_addr, client_size, ip, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);

	fcntl(client_sock, F_SETFL, O_NONBLOCK);
	std::stringstream len_buf;
	std::stringstream msg_buf;
	bool is_done = 0;
	size_t size = 0;
	while(!is_done) {
		char tmp_buf[msgpp::MessageNode::size];
		memset(&tmp_buf, 0, msgpp::MessageNode::size);
		int n_bytes = 0;
		time_t start = time(NULL);
		while(((size_t) time(NULL) - start) < this->timeout) {
			n_bytes = recv(client_sock, &tmp_buf, msgpp::MessageNode::size, 0);
			if(n_bytes == -1) {
				if(errno != EAGAIN) {
					break;
				}
				std::this_thread::sleep_for(msgpp::MessageNode::increment);
			} else {
				break;
			}
		}
		if(n_bytes == 0 || n_bytes == -1) {
			// client closed unexpectedly
			// as the message queue is atomically set (i.e., no half-assed data), we will roll back changes and not touch the queue
			break;
		}
		std::string tmp = std::string(tmp_buf, n_bytes);
		if(size == 0) {
			size_t pos = tmp.find(':');
			if(pos == std::string::npos) {
				pos = tmp.size();
			}
			len_buf << tmp.substr(0, pos);
			if(pos != tmp.size()) {
				size = std::stoll(len_buf.str());
				msg_buf << tmp.substr(pos + 1);
			}
		} else {
			msg_buf << tmp;
		}
		if(size != 0) {
			is_done = (msg_buf.str().length() >= size);
		}
	}

	if(is_done && (msg_buf.str().length() >= size)) {
		std::lock_guard<std::mutex> lock(this->messages_l);
		this->messages.push_back(msgpp::Message(++this->count, ip, host, msg_buf.str().substr(0, size)));
	}
	shutdown(client_sock, SHUT_RDWR);
	close(client_sock);
}

void msgpp::MessageNode::dn() {
	std::lock_guard<std::recursive_mutex> lock(msgpp::MessageNode::l);
	if(*(this->flag) == 0) {
		return;
	}
	*(this->flag) = 0;

	// restore signal handler if no more instances are running
	if(msgpp::MessageNode::instances.size() == 0) {
		signal(SIGINT, msgpp::MessageNode::handler);
	}
}

size_t msgpp::MessageNode::query() {
	std::lock_guard<std::mutex> lock(this->messages_l);
	return(this->messages.size());
}

size_t msgpp::MessageNode::push(std::string message, std::string hostname, size_t port, bool silent_fail) {
	std::stringstream port_buf, msg_buf;
	port_buf << port;
	msg_buf << message.length() << ":" << message;

	int client_sock, status;
	struct addrinfo info;
	struct addrinfo *list;
	memset(&info, 0, sizeof(info));

	info.ai_family = AF_UNSPEC;
	info.ai_socktype = SOCK_STREAM;

	getaddrinfo(hostname.c_str(), port_buf.str().c_str(), &info, &list);
	if(list == NULL) {
		if(silent_fail) { return(0); }
		throw(exceptionpp::RuntimeError("msgpp::MessageNode::push", "cannot find endpoint"));
	}
	client_sock = socket(list->ai_family, list->ai_socktype, list->ai_protocol);
	if(client_sock == -1) {
		freeaddrinfo(list);
		shutdown(client_sock, SHUT_RDWR);
		close(client_sock);
		if(silent_fail) { return(0); }
		throw(exceptionpp::RuntimeError("msgpp::MessageNode::push", "cannot open socket"));
	}

	int yes = 1;
	status = setsockopt(client_sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
	fcntl(client_sock, F_SETFL, O_NONBLOCK);

	time_t start = time(NULL);
	while(((size_t) time(NULL) - start) < this->timeout) {
		status = connect(client_sock, list->ai_addr, list->ai_addrlen);
		if(status != -1) {
			break;
		}
		std::this_thread::sleep_for(msgpp::MessageNode::increment);
	}

	if(status == -1) {
		freeaddrinfo(list);
		shutdown(client_sock, SHUT_RDWR);
		close(client_sock);
		if(silent_fail) { return(0); }
		throw(exceptionpp::RuntimeError("msgpp::MessageNode::push", "cannot connect to destination"));
	}

	int result = -1;
	size_t n_bytes = 0;

	start = time(NULL);
	while(((size_t) time(NULL) - start) < this->timeout) {
		result = send(client_sock, msg_buf.str().c_str(), msg_buf.str().length(), 0);
		if(result != -1) {
			n_bytes += result;
			if(n_bytes == msg_buf.str().length()) {
				break;
			}
		} else {
			if(errno == EWOULDBLOCK) {
				std::this_thread::sleep_for(msgpp::MessageNode::increment);
			} else {
				break;
			}
		}
	}

	if(result == -1 || n_bytes != msg_buf.str().length()) {
		freeaddrinfo(list);
		shutdown(client_sock, SHUT_RDWR);
		close(client_sock);
		if(silent_fail) { return(0); }
		throw(exceptionpp::RuntimeError("msgpp::MessageNode::send", "could not send data"));
	}

	freeaddrinfo(list);
	shutdown(client_sock, SHUT_RDWR);
	close(client_sock);

	return(result - (msg_buf.str().length() - message.length()));
}

std::string msgpp::MessageNode::pull(std::string hostname, bool silent_fail) {
	size_t target = 0;
	bool is_found = 0;

	time_t start = time(NULL);
	while(((size_t) time(NULL) - start) < this->timeout) {
		// lock during iteration, but unlock during sleep to give the queue an opportunity to fill up again
		{
			std::lock_guard<std::mutex> lock(this->messages_l);
			if(!this->messages.empty()) {
				for(std::vector<msgpp::Message>::iterator it = this->messages.begin(); it != this->messages.end(); ++it) {
					msgpp::Message instance = *it;
					bool match_h = (instance.get_hostname().compare("") == 0) || (instance.get_ip().compare("") == 0) || (hostname.compare("") == 0) || (hostname.compare(instance.get_hostname()) == 0) || (hostname.compare(instance.get_ip()) == 0);
					if(match_h) {
						target = it->get_identifier();
						is_found = 1;
						break;
					}
				}
			}
		}
		if(is_found) {
			break;
		}
		std::this_thread::sleep_for(msgpp::MessageNode::increment);
	}

	if(!is_found) {
		if(silent_fail) { return(""); }
		throw(exceptionpp::RuntimeError("msgpp::MessageNode::pull", "message does not exist"));
	}

	std::string message = "";
	{
		std::lock_guard<std::mutex> lock(this->messages_l);
		auto index = this->messages.end();
		for(std::vector<msgpp::Message>::iterator it = this->messages.begin(); it != this->messages.end(); ++it) {
			msgpp::Message instance = *it;
			if(instance.get_identifier() == target) {
				index = it;
				message = instance.get_message();
			}
		}
		this->messages.erase(index);
	}
	return(message);
}

/**
 * SIGINT handler -- terminate all running MessageNode instances
 */
void msgpp::MessageNode::term(int p) {
	std::lock_guard<std::recursive_mutex> lock(msgpp::MessageNode::l);
	for(std::vector<std::shared_ptr<msgpp::MessageNode>>::iterator it = msgpp::MessageNode::instances.begin(); it != msgpp::MessageNode::instances.end(); ++it) {
		(*it)->dn();
	}
	msgpp::MessageNode::instances.clear();
	// install old sighandler
	//	cf. http://bit.ly/1unilFS
	signal(SIGINT, msgpp::MessageNode::handler);
}
<|endoftext|>


<commit_before>// Copyright (c) 2013-2014 Flowgrammable.org
//
// 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 <iostream>
#include <fstream>
#include <iterator>
#include <string>
#include <vector>
#include <assert.h>

#include <freeflow/sys/socket.hpp>
#include <freeflow/sys/json.hpp>

using namespace std;
using namespace freeflow;

struct CLI_parser_exception {
  CLI_parser_exception(string err);
};

CLI_parser_exception::CLI_parser_exception(string err) {
  cout << "CLI parser exception: " << err << endl;
}

struct CLI_parser_rule {
  string format;

  bool match(string & str,vector<pair<string,string> > & args);

  CLI_parser_rule(string rule);
};

// Constructor for CLI_parser_rule
// Currently, it just checks to make sure that all square brackets are closed
CLI_parser_rule::CLI_parser_rule(string rule) : format(rule) {
  // Make sure all square brackets are closed
  bool in_bracket = false;

  for (char c : format) {
    if (c == '[') {
      if (not in_bracket) {
        in_bracket = true;
      }
      else {
        throw CLI_parser_exception("Too many opening square brackets ('[')"
          " in parser rule: " + format);
      }
    } else if (c == ']') {
      if (in_bracket) {
        in_bracket = false;
      }
      else {
        throw CLI_parser_exception("Too many closing square brackets (']')"
          " in parser rule: " + format);
      }
    }
  }

  if (in_bracket){
    throw CLI_parser_exception("Expected closing square bracket (']')"
      " in parser rule: " + format);
  }
}

// Performs basic, greedy "pattern matching" between a rule and a string.
//
// If it matches the pattern, it returns true and populates args with
// pairs of variable names and their values. Otherwise, it returns
// false and clears args.
bool CLI_parser_rule::match(string & str,vector<pair<string,string> > & args) {
  int pos_f = 0;        // Position in the formate string (i.e. rule)
  int pos_s = 0;        // Position in the string to be matched
  string var_name;      // Name of the current variable
  string var_value;     // Value of the current variable
  bool var = false;     // Whether we're currently matching a variable

  while (pos_s < (int)str.length()) {
    if (!var) {
      if (format[pos_f] == '[') {
        pos_f++;
        var_name = "";
        var_value = "";
        var = true;

        bool matched = false;

        // Extract the name of the variable
        while (pos_f < (int)format.length()) {
          if (format[pos_f] == ']') {
            matched = true;
            pos_f++;
            break;
          }
          else{
            var_name += format[pos_f++];
          }
        }

        // Should never happen because this is checked for in the constructor
        if (!matched) {
          throw CLI_parser_exception("Impossible unmatched bracket in: "+format);
        }
      }
    }

    if (var) {
        // Peek ahead and see if the current character matches the current
        // format character. If so, assume we're done matching the variable
        // (this works because the algorithm is greedy)
        if (str[pos_s] == format[pos_f]) {
          var = false;
          args.push_back(pair<string,string>(var_name,var_value));
        }
        else {
          var_value += str[pos_s++];
        }
    }
    else {
      if (format[pos_f] != str[pos_s]) {
        args.clear();
        return false;
      }

      pos_f++;
      pos_s++;
    }
  }

  if (var){
    args.push_back(pair<string,string>(var_name,var_value));
  }

  if (pos_f < (int)format.length()) {
    args.clear();
    return false;
  }

  else return true;
}

struct CLI_parser {
  vector<CLI_parser_rule> rules;
  vector<string> args;
  int arg_pos;

  void parse(int argc,char *argv[]);
  string & get_arg();
  bool next_arg();
  void set_arg_pos(int pos);

};

void CLI_parser::parse(int argc,char *argv[]) {
  // Probably a good idea to clear the args vector if this is called more than once
  args.clear();

  for (int i = 0; i < argc; i++) {
    args.push_back(argv[i]);
  }

  set_arg_pos(0);
}

// Gets the current argument
string & CLI_parser::get_arg() {
  assert(arg_pos < (int)args.size());

  return args[arg_pos];
}

// Advances to the next argument
// Returns whether there is another argument
bool CLI_parser::next_arg() {
  return ++arg_pos < (int)args.size();
}

// Sets the position of the current argument
void CLI_parser::set_arg_pos(int pos) {
  if (pos < (int)args.size())
    arg_pos = pos;
  else
    arg_pos = args.size();
}

int main(int argc,char *argv[]){
  CLI_parser parser;

  CLI_parser_rule("--[flag]=[value]");

  parser.parse(argc,argv);

  do{
    cout << parser.get_arg() << endl;
  } while(parser.next_arg());
}

<commit_msg>Put function return types on separate lines to conform to coding style<commit_after>// Copyright (c) 2013-2014 Flowgrammable.org
//
// 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 <iostream>
#include <fstream>
#include <iterator>
#include <string>
#include <vector>
#include <assert.h>

#include <freeflow/sys/socket.hpp>
#include <freeflow/sys/json.hpp>

using namespace std;
using namespace freeflow;

// Very simple CLI exception handling class
// TODO: redirect output to stderr
struct CLI_parser_exception {
  CLI_parser_exception(string err);
};

CLI_parser_exception::CLI_parser_exception(string err) {
  cout << "CLI parser exception: " << err << endl;
}

// A rule which control how the parser parses command line arguments
struct CLI_parser_rule {
  string format;

  bool match(string & str,vector<pair<string,string> > & args);

  CLI_parser_rule(string rule);
};

// Constructor for CLI_parser_rule
// Currently, it just checks to make sure that all square brackets are closed
CLI_parser_rule::CLI_parser_rule(string rule) : format(rule) {
  // Make sure all square brackets are closed
  bool in_bracket = false;

  for (char c : format) {
    if (c == '[') {
      if (not in_bracket) {
        in_bracket = true;
      }
      else {
        throw CLI_parser_exception("Too many opening square brackets ('[')"
          " in parser rule: " + format);
      }
    } else if (c == ']') {
      if (in_bracket) {
        in_bracket = false;
      }
      else {
        throw CLI_parser_exception("Too many closing square brackets (']')"
          " in parser rule: " + format);
      }
    }
  }

  if (in_bracket){
    throw CLI_parser_exception("Expected closing square bracket (']')"
      " in parser rule: " + format);
  }
}

// Performs basic, greedy "pattern matching" between a rule and a string.
//
// If it matches the pattern, it returns true and populates args with
// pairs of variable names and their values. Otherwise, it returns
// false and clears args.
bool
CLI_parser_rule::match(string & str,vector<pair<string,string> > & args) {
  int pos_f = 0;        // Position in the formate string (i.e. rule)
  int pos_s = 0;        // Position in the string to be matched
  string var_name;      // Name of the current variable
  string var_value;     // Value of the current variable
  bool var = false;     // Whether we're currently matching a variable

  while (pos_s < (int)str.length()) {
    if (!var) {
      if (format[pos_f] == '[') {
        pos_f++;
        var_name = "";
        var_value = "";
        var = true;

        bool matched = false;

        // Extract the name of the variable
        while (pos_f < (int)format.length()) {
          if (format[pos_f] == ']') {
            matched = true;
            pos_f++;
            break;
          }
          else{
            var_name += format[pos_f++];
          }
        }

        // Should never happen because this is checked for in the constructor
        if (!matched) {
          throw CLI_parser_exception("Impossible unmatched bracket in: "+format);
        }
      }
    }

    if (var) {
        // Peek ahead and see if the current character matches the current
        // format character. If so, assume we're done matching the variable
        // (this works because the algorithm is greedy)
        if (str[pos_s] == format[pos_f]) {
          var = false;
          args.push_back(pair<string,string>(var_name,var_value));
        }
        else {
          var_value += str[pos_s++];
        }
    }
    else {
      if (format[pos_f] != str[pos_s]) {
        args.clear();
        return false;
      }

      pos_f++;
      pos_s++;
    }
  }

  if (var){
    args.push_back(pair<string,string>(var_name,var_value));
  }

  if (pos_f < (int)format.length()) {
    args.clear();
    return false;
  }

  else return true;
}

struct CLI_parser {
  vector<CLI_parser_rule> rules;
  vector<string> args;
  int arg_pos;

  void parse(int argc,char *argv[]);
  string & get_arg();
  bool next_arg();
  void set_arg_pos(int pos);

};

// Actual parsing function
// TODO: implement actual parsing
void
CLI_parser::parse(int argc,char *argv[]) {
  // Probably a good idea to clear the args vector if this is called more than once
  args.clear();

  for (int i = 0; i < argc; i++) {
    args.push_back(argv[i]);
  }

  set_arg_pos(0);
}

// Gets the current argument
string &
CLI_parser::get_arg() {
  assert(arg_pos < (int)args.size());

  return args[arg_pos];
}

// Advances to the next argument
// Returns whether there is another argument
bool
CLI_parser::next_arg() {
  return ++arg_pos < (int)args.size();
}

// Sets the position of the current argument
void
CLI_parser::set_arg_pos(int pos) {
  if (pos < (int)args.size())
    arg_pos = pos;
  else
    arg_pos = args.size();
}

int
main(int argc,char *argv[]) {
  CLI_parser parser;

  CLI_parser_rule("--[flag]=[value]");

  parser.parse(argc,argv);

  do{
    cout << parser.get_arg() << endl;
  } while(parser.next_arg());
}

<|endoftext|>


<commit_before>#include "command.hh"
#include "hash.hh"
#include "legacy.hh"
#include "shared.hh"
#include "references.hh"
#include "archive.hh"

using namespace nix;

struct CmdHash : Command
{
    enum Mode { mFile, mPath };
    Mode mode;
    Base base = SRI;
    bool truncate = false;
    HashType ht = htSHA256;
    std::vector<std::string> paths;
    std::optional<std::string> modulus;

    CmdHash(Mode mode) : mode(mode)
    {
        mkFlag(0, "sri", "print hash in SRI format", &base, SRI);
        mkFlag(0, "base64", "print hash in base-64", &base, Base64);
        mkFlag(0, "base32", "print hash in base-32 (Nix-specific)", &base, Base32);
        mkFlag(0, "base16", "print hash in base-16", &base, Base16);
        mkFlag()
            .longName("type")
            .mkHashTypeFlag(&ht);
        mkFlag()
            .longName("modulo")
            .description("compute hash modulo specified string")
            .labels({"modulus"})
            .dest(&modulus);
        expectArgs("paths", &paths);
    }

    std::string name() override
    {
        return mode == mFile ? "hash-file" : "hash-path";
    }

    std::string description() override
    {
        return mode == mFile
            ? "print cryptographic hash of a regular file"
            : "print cryptographic hash of the NAR serialisation of a path";
    }

    void run() override
    {
        for (auto path : paths) {

            std::unique_ptr<AbstractHashSink> hashSink;
            if (modulus)
                hashSink = std::make_unique<HashModuloSink>(ht, *modulus);
            else
                hashSink = std::make_unique<HashSink>(ht);

            if (mode == mFile)
                readFile(path, *hashSink);
            else
                dumpPath(path, *hashSink);

            Hash h = hashSink->finish().first;
            if (truncate && h.hashSize > 20) h = compressHash(h, 20);
            std::cout << format("%1%\n") %
                h.to_string(base, base == SRI);
        }
    }
};

static RegisterCommand r1(make_ref<CmdHash>(CmdHash::mFile));
static RegisterCommand r2(make_ref<CmdHash>(CmdHash::mPath));

struct CmdToBase : Command
{
    Base base;
    HashType ht = htUnknown;
    std::vector<std::string> args;

    CmdToBase(Base base) : base(base)
    {
        mkFlag()
            .longName("type")
            .mkHashTypeFlag(&ht);
        expectArgs("strings", &args);
    }

    std::string name() override
    {
        return
            base == Base16 ? "to-base16" :
            base == Base32 ? "to-base32" :
            base == Base64 ? "to-base64" :
            "to-sri";
    }

    std::string description() override
    {
        return fmt("convert a hash to %s representation",
            base == Base16 ? "base-16" :
            base == Base32 ? "base-32" :
            base == Base64 ? "base-64" :
            "SRI");
    }

    void run() override
    {
        for (auto s : args)
            std::cout << fmt("%s\n", Hash(s, ht).to_string(base, base == SRI));
    }
};

static RegisterCommand r3(make_ref<CmdToBase>(Base16));
static RegisterCommand r4(make_ref<CmdToBase>(Base32));
static RegisterCommand r5(make_ref<CmdToBase>(Base64));
static RegisterCommand r6(make_ref<CmdToBase>(SRI));

/* Legacy nix-hash command. */
static int compatNixHash(int argc, char * * argv)
{
    HashType ht = htMD5;
    bool flat = false;
    bool base32 = false;
    bool truncate = false;
    enum { opHash, opTo32, opTo16 } op = opHash;
    std::vector<std::string> ss;

    parseCmdLine(argc, argv, [&](Strings::iterator & arg, const Strings::iterator & end) {
        if (*arg == "--help")
            showManPage("nix-hash");
        else if (*arg == "--version")
            printVersion("nix-hash");
        else if (*arg == "--flat") flat = true;
        else if (*arg == "--base32") base32 = true;
        else if (*arg == "--truncate") truncate = true;
        else if (*arg == "--type") {
            string s = getArg(*arg, arg, end);
            ht = parseHashType(s);
            if (ht == htUnknown)
                throw UsageError(format("unknown hash type '%1%'") % s);
        }
        else if (*arg == "--to-base16") op = opTo16;
        else if (*arg == "--to-base32") op = opTo32;
        else if (*arg != "" && arg->at(0) == '-')
            return false;
        else
            ss.push_back(*arg);
        return true;
    });

    if (op == opHash) {
        CmdHash cmd(flat ? CmdHash::mFile : CmdHash::mPath);
        cmd.ht = ht;
        cmd.base = base32 ? Base32 : Base16;
        cmd.truncate = truncate;
        cmd.paths = ss;
        cmd.run();
    }

    else {
        CmdToBase cmd(op == opTo32 ? Base32 : Base16);
        cmd.args = ss;
        cmd.ht = ht;
        cmd.run();
    }

    return 0;
}

static RegisterLegacyCommand s1("nix-hash", compatNixHash);
<commit_msg>Revert "Fix build"<commit_after>#include "command.hh"
#include "hash.hh"
#include "legacy.hh"
#include "shared.hh"
#include "references.hh"
#include "archive.hh"

using namespace nix;

struct CmdHash : Command
{
    enum Mode { mFile, mPath };
    Mode mode;
    Base base = SRI;
    bool truncate = false;
    HashType ht = htSHA256;
    std::vector<std::string> paths;
    std::experimental::optional<std::string> modulus;

    CmdHash(Mode mode) : mode(mode)
    {
        mkFlag(0, "sri", "print hash in SRI format", &base, SRI);
        mkFlag(0, "base64", "print hash in base-64", &base, Base64);
        mkFlag(0, "base32", "print hash in base-32 (Nix-specific)", &base, Base32);
        mkFlag(0, "base16", "print hash in base-16", &base, Base16);
        mkFlag()
            .longName("type")
            .mkHashTypeFlag(&ht);
        mkFlag()
            .longName("modulo")
            .description("compute hash modulo specified string")
            .labels({"modulus"})
            .dest(&modulus);
        expectArgs("paths", &paths);
    }

    std::string name() override
    {
        return mode == mFile ? "hash-file" : "hash-path";
    }

    std::string description() override
    {
        return mode == mFile
            ? "print cryptographic hash of a regular file"
            : "print cryptographic hash of the NAR serialisation of a path";
    }

    void run() override
    {
        for (auto path : paths) {

            std::unique_ptr<AbstractHashSink> hashSink;
            if (modulus)
                hashSink = std::make_unique<HashModuloSink>(ht, *modulus);
            else
                hashSink = std::make_unique<HashSink>(ht);

            if (mode == mFile)
                readFile(path, *hashSink);
            else
                dumpPath(path, *hashSink);

            Hash h = hashSink->finish().first;
            if (truncate && h.hashSize > 20) h = compressHash(h, 20);
            std::cout << format("%1%\n") %
                h.to_string(base, base == SRI);
        }
    }
};

static RegisterCommand r1(make_ref<CmdHash>(CmdHash::mFile));
static RegisterCommand r2(make_ref<CmdHash>(CmdHash::mPath));

struct CmdToBase : Command
{
    Base base;
    HashType ht = htUnknown;
    std::vector<std::string> args;

    CmdToBase(Base base) : base(base)
    {
        mkFlag()
            .longName("type")
            .mkHashTypeFlag(&ht);
        expectArgs("strings", &args);
    }

    std::string name() override
    {
        return
            base == Base16 ? "to-base16" :
            base == Base32 ? "to-base32" :
            base == Base64 ? "to-base64" :
            "to-sri";
    }

    std::string description() override
    {
        return fmt("convert a hash to %s representation",
            base == Base16 ? "base-16" :
            base == Base32 ? "base-32" :
            base == Base64 ? "base-64" :
            "SRI");
    }

    void run() override
    {
        for (auto s : args)
            std::cout << fmt("%s\n", Hash(s, ht).to_string(base, base == SRI));
    }
};

static RegisterCommand r3(make_ref<CmdToBase>(Base16));
static RegisterCommand r4(make_ref<CmdToBase>(Base32));
static RegisterCommand r5(make_ref<CmdToBase>(Base64));
static RegisterCommand r6(make_ref<CmdToBase>(SRI));

/* Legacy nix-hash command. */
static int compatNixHash(int argc, char * * argv)
{
    HashType ht = htMD5;
    bool flat = false;
    bool base32 = false;
    bool truncate = false;
    enum { opHash, opTo32, opTo16 } op = opHash;
    std::vector<std::string> ss;

    parseCmdLine(argc, argv, [&](Strings::iterator & arg, const Strings::iterator & end) {
        if (*arg == "--help")
            showManPage("nix-hash");
        else if (*arg == "--version")
            printVersion("nix-hash");
        else if (*arg == "--flat") flat = true;
        else if (*arg == "--base32") base32 = true;
        else if (*arg == "--truncate") truncate = true;
        else if (*arg == "--type") {
            string s = getArg(*arg, arg, end);
            ht = parseHashType(s);
            if (ht == htUnknown)
                throw UsageError(format("unknown hash type '%1%'") % s);
        }
        else if (*arg == "--to-base16") op = opTo16;
        else if (*arg == "--to-base32") op = opTo32;
        else if (*arg != "" && arg->at(0) == '-')
            return false;
        else
            ss.push_back(*arg);
        return true;
    });

    if (op == opHash) {
        CmdHash cmd(flat ? CmdHash::mFile : CmdHash::mPath);
        cmd.ht = ht;
        cmd.base = base32 ? Base32 : Base16;
        cmd.truncate = truncate;
        cmd.paths = ss;
        cmd.run();
    }

    else {
        CmdToBase cmd(op == opTo32 ? Base32 : Base16);
        cmd.args = ss;
        cmd.ht = ht;
        cmd.run();
    }

    return 0;
}

static RegisterLegacyCommand s1("nix-hash", compatNixHash);
<|endoftext|>