<commit_before>#ifndef STAN_OPTIMIZATION_NEWTON_HPP
#define STAN_OPTIMIZATION_NEWTON_HPP

#include <stan/model/util.hpp>
#include <Eigen/Dense>
#include <Eigen/Cholesky>
#include <Eigen/Eigenvalues>
#include <vector>

namespace stan {

  namespace optimization {

    typedef Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> matrix_d;
    typedef Eigen::Matrix<double, Eigen::Dynamic, 1> vector_d;

    namespace {
      // Negates any positive eigenvalues in H so that H is negative
      // definite, and then solves Hu = g and stores the result into
      // g. Avoids problems due to non-log-concave distributions.
      void make_negative_definite_and_solve(matrix_d& H, vector_d& g) {
        Eigen::SelfAdjointEigenSolver<matrix_d> solver(H);
        matrix_d eigenvectors = solver.eigenvectors();
        vector_d eigenvalues = solver.eigenvalues();
        vector_d eigenprojections = eigenvectors.transpose() * g;
        for (int i = 0; i < g.size(); i++) {
          eigenprojections[i] = -eigenprojections[i] / fabs(eigenvalues[i]);
        }
        g = eigenvectors * eigenprojections;
      }
    }

    template <typename M>
    double newton_step(M& model,
                       std::vector<double>& params_r,
                       std::vector<int>& params_i,
                       std::ostream* output_stream = 0) {
        std::vector<double> gradient;
        std::vector<double> hessian;

        double f0
          = stan::model::grad_hess_log_prob<true, false>(model,
                                                         params_r, params_i,
                                                         gradient, hessian);
        matrix_d H(params_r.size(), params_r.size());
        for (size_t i = 0; i < hessian.size(); i++) {
          H(i) = hessian[i];
        }
        vector_d g(params_r.size());
        for (size_t i = 0; i < gradient.size(); i++)
          g(i) = gradient[i];
        make_negative_definite_and_solve(H, g);
//         H.ldlt().solveInPlace(g);

        std::vector<double> new_params_r(params_r.size());
        double step_size = 2;
        double min_step_size = 1e-50;
        double f1 = -1e100;

        while (f1 < f0) {
          step_size *= 0.5;
          if (step_size < min_step_size)
            return f0;

          for (size_t i = 0; i < params_r.size(); i++)
            new_params_r[i] = params_r[i] - step_size * g[i];
          try {
            f1 = stan::model::log_prob_grad<true, false>(model,
                                                         new_params_r,
                                                         params_i, gradient);
          } catch (std::exception& e) {
            // FIXME:  this is not a good way to handle a general exception
            f1 = -1e100;
          }
        }
        for (size_t i = 0; i < params_r.size(); i++)
          params_r[i] = new_params_r[i];

        return f1;
    }

  }

}

#endif
<commit_msg>Removing empty lines<commit_after>#ifndef STAN_OPTIMIZATION_NEWTON_HPP
#define STAN_OPTIMIZATION_NEWTON_HPP

#include <stan/model/util.hpp>
#include <Eigen/Dense>
#include <Eigen/Cholesky>
#include <Eigen/Eigenvalues>
#include <vector>

namespace stan {
  namespace optimization {

    typedef Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> matrix_d;
    typedef Eigen::Matrix<double, Eigen::Dynamic, 1> vector_d;

    namespace {
      // Negates any positive eigenvalues in H so that H is negative
      // definite, and then solves Hu = g and stores the result into
      // g. Avoids problems due to non-log-concave distributions.
      void make_negative_definite_and_solve(matrix_d& H, vector_d& g) {
        Eigen::SelfAdjointEigenSolver<matrix_d> solver(H);
        matrix_d eigenvectors = solver.eigenvectors();
        vector_d eigenvalues = solver.eigenvalues();
        vector_d eigenprojections = eigenvectors.transpose() * g;
        for (int i = 0; i < g.size(); i++) {
          eigenprojections[i] = -eigenprojections[i] / fabs(eigenvalues[i]);
        }
        g = eigenvectors * eigenprojections;
      }
    }

    template <typename M>
    double newton_step(M& model,
                       std::vector<double>& params_r,
                       std::vector<int>& params_i,
                       std::ostream* output_stream = 0) {
        std::vector<double> gradient;
        std::vector<double> hessian;

        double f0
          = stan::model::grad_hess_log_prob<true, false>(model,
                                                         params_r, params_i,
                                                         gradient, hessian);
        matrix_d H(params_r.size(), params_r.size());
        for (size_t i = 0; i < hessian.size(); i++) {
          H(i) = hessian[i];
        }
        vector_d g(params_r.size());
        for (size_t i = 0; i < gradient.size(); i++)
          g(i) = gradient[i];
        make_negative_definite_and_solve(H, g);
//         H.ldlt().solveInPlace(g);

        std::vector<double> new_params_r(params_r.size());
        double step_size = 2;
        double min_step_size = 1e-50;
        double f1 = -1e100;

        while (f1 < f0) {
          step_size *= 0.5;
          if (step_size < min_step_size)
            return f0;

          for (size_t i = 0; i < params_r.size(); i++)
            new_params_r[i] = params_r[i] - step_size * g[i];
          try {
            f1 = stan::model::log_prob_grad<true, false>(model,
                                                         new_params_r,
                                                         params_i, gradient);
          } catch (std::exception& e) {
            // FIXME:  this is not a good way to handle a general exception
            f1 = -1e100;
          }
        }
        for (size_t i = 0; i < params_r.size(); i++)
          params_r[i] = new_params_r[i];

        return f1;
    }

  }
}
#endif
<|endoftext|>


<commit_before>void rootgeom()
{
//Definition of a simple geometry (the 4 ROOT characters)
//Author: Andrei Gheata

   // gStyle->SetCanvasPreferGL(true);
   gSystem->Load("libGeom");
   TGeoManager *geom = new TGeoManager("simple1", "Simple geometry");

   //--- define some materials
   TGeoMaterial *matVacuum = new TGeoMaterial("Vacuum", 0,0,0);
   TGeoMaterial *matAl = new TGeoMaterial("Al", 26.98,13,2.7);
//   //--- define some media
   TGeoMedium *Vacuum = new TGeoMedium("Vacuum",1, matVacuum);
   TGeoMedium *Al = new TGeoMedium("Root Material",2, matAl);

   //--- define the transformations
   TGeoTranslation *tr1 = new TGeoTranslation(20., 0, 0.);
   TGeoTranslation *tr2 = new TGeoTranslation(10., 0., 0.);
   TGeoTranslation *tr3 = new TGeoTranslation(10., 20., 0.);
   TGeoTranslation *tr4 = new TGeoTranslation(5., 10., 0.);
   TGeoTranslation *tr5 = new TGeoTranslation(20., 0., 0.);
   TGeoTranslation *tr6 = new TGeoTranslation(-5., 0., 0.);
   TGeoTranslation *tr7 = new TGeoTranslation(7.5, 7.5, 0.);
   TGeoRotation   *rot1 = new TGeoRotation("rot1", 90., 0., 90., 270., 0., 0.);
   TGeoCombiTrans *combi1 = new TGeoCombiTrans(7.5, -7.5, 0., rot1);
   TGeoTranslation *tr8 = new TGeoTranslation(7.5, -5., 0.);
   TGeoTranslation *tr9 = new TGeoTranslation(7.5, 20., 0.);
   TGeoTranslation *tr10 = new TGeoTranslation(85., 0., 0.);
   TGeoTranslation *tr11 = new TGeoTranslation(35., 0., 0.);
   TGeoTranslation *tr12 = new TGeoTranslation(-15., 0., 0.);
   TGeoTranslation *tr13 = new TGeoTranslation(-65., 0., 0.);

   TGeoTranslation  *tr14 = new TGeoTranslation(0,0,-100);
   TGeoCombiTrans *combi2 = new TGeoCombiTrans(0,0,100,
                                   new TGeoRotation("rot2",90,180,90,90,180,0));
   TGeoCombiTrans *combi3 = new TGeoCombiTrans(100,0,0,
                                   new TGeoRotation("rot3",90,270,0,0,90,180));
   TGeoCombiTrans *combi4 = new TGeoCombiTrans(-100,0,0,
                                   new TGeoRotation("rot4",90,90,0,0,90,0));
   TGeoCombiTrans *combi5 = new TGeoCombiTrans(0,100,0,
                                   new TGeoRotation("rot5",0,0,90,180,90,270));
   TGeoCombiTrans *combi6 = new TGeoCombiTrans(0,-100,0,
                                   new TGeoRotation("rot6",180,0,90,180,90,90));

   //--- make the top container volume
   Double_t worldx = 110.;
   Double_t worldy = 50.;
   Double_t worldz = 5.;
   TGeoVolume *top = geom->MakeBox("TOP", Vacuum, 270., 270., 120.);
   geom->SetTopVolume(top);
   TGeoVolume *replica = geom->MakeBox("REPLICA", Vacuum,120,120,120);
   replica->SetVisibility(kFALSE);
   TGeoVolume *rootbox = geom->MakeBox("ROOT", Vacuum, 110., 50., 5.);
   rootbox->SetVisibility(kFALSE);

   //--- make letter 'R'
   TGeoVolume *R = geom->MakeBox("R", Vacuum, 25., 25., 5.);
   R->SetVisibility(kFALSE);
   TGeoVolume *bar1 = geom->MakeBox("bar1", Al, 5., 25, 5.);
   bar1->SetLineColor(kRed);
   R->AddNode(bar1, 1, tr1);
   TGeoVolume *bar2 = geom->MakeBox("bar2", Al, 5., 5., 5.);
   bar2->SetLineColor(kRed);
   R->AddNode(bar2, 1, tr2);
   R->AddNode(bar2, 2, tr3);
   TGeoVolume *tub1 = geom->MakeTubs("tub1", Al, 5., 15., 5., 90., 270.);
   tub1->SetLineColor(kRed);
   R->AddNode(tub1, 1, tr4);
   TGeoVolume *bar3 = geom->MakeArb8("bar3", Al, 5.);
   bar3->SetLineColor(kRed);
   TGeoArb8 *arb = (TGeoArb8*)bar3->GetShape();
   arb->SetVertex(0, 15., -5.);
   arb->SetVertex(1, 0., -25.);
   arb->SetVertex(2, -10., -25.);
   arb->SetVertex(3, 5., -5.);
   arb->SetVertex(4, 15., -5.);
   arb->SetVertex(5, 0., -25.);
   arb->SetVertex(6, -10., -25.);
   arb->SetVertex(7, 5., -5.);
   R->AddNode(bar3, 1, gGeoIdentity);

   //--- make letter 'O'
   TGeoVolume *O = geom->MakeBox("O", Vacuum, 25., 25., 5.);
   O->SetVisibility(kFALSE);
   TGeoVolume *bar4 = geom->MakeBox("bar4", Al, 5., 7.5, 5.);
   bar4->SetLineColor(kYellow);
   O->AddNode(bar4, 1, tr5);
   O->AddNode(bar4, 2, tr6);
   TGeoVolume *tub2 = geom->MakeTubs("tub1", Al, 7.5, 17.5, 5., 0., 180.);
   tub2->SetLineColor(kYellow);
   O->AddNode(tub2, 1, tr7);
   O->AddNode(tub2, 2, combi1);

   //--- make letter 'T'
   TGeoVolume *T = geom->MakeBox("T", Vacuum, 25., 25., 5.);
   T->SetVisibility(kFALSE);
   TGeoVolume *bar5 = geom->MakeBox("bar5", Al, 5., 20., 5.);
   bar5->SetLineColor(kBlue);
   T->AddNode(bar5, 1, tr8);
   TGeoVolume *bar6 = geom->MakeBox("bar6", Al, 17.5, 5., 5.);
   bar6->SetLineColor(kBlue);
   T->AddNode(bar6, 1, tr9);

   rootbox->AddNode(R, 1, tr10);
   rootbox->AddNode(O, 1, tr11);
   rootbox->AddNode(O, 2, tr12);
   rootbox->AddNode(T, 1, tr13);

   replica->AddNode(rootbox, 1, tr14);
   replica->AddNode(rootbox, 2, combi2);
   replica->AddNode(rootbox, 3, combi3);
   replica->AddNode(rootbox, 4, combi4);
   replica->AddNode(rootbox, 5, combi5);
   replica->AddNode(rootbox, 6, combi6);

   top->AddNode(replica, 1, new TGeoTranslation(-150, -150, 0));
   top->AddNode(replica, 2, new TGeoTranslation(150, -150, 0));
   top->AddNode(replica, 3, new TGeoTranslation(150, 150, 0));
   top->AddNode(replica, 4, new TGeoTranslation(-150, 150, 0));

   //--- close the geometry
   geom->CloseGeometry();

   //--- draw the ROOT box.
   // by default the picture will appear in the standard ROOT TPad.
   //if you have activated the following line in system.rootrc,
   //it will appear in the GL viewer
   //#Viewer3D.DefaultDrawOption:   ogl

   geom->SetVisLevel(4);
   top->Draw("ogle");
}

<commit_msg>white space.<commit_after>void rootgeom()
{
//Definition of a simple geometry (the 4 ROOT characters)
//Author: Andrei Gheata

   // gStyle->SetCanvasPreferGL(true);
   gSystem->Load("libGeom");
   TGeoManager *geom = new TGeoManager("simple1", "Simple geometry");

   //--- define some materials
   TGeoMaterial *matVacuum = new TGeoMaterial("Vacuum", 0,0,0);
   TGeoMaterial *matAl = new TGeoMaterial("Al", 26.98,13,2.7);
   //--- define some media
   TGeoMedium *Vacuum = new TGeoMedium("Vacuum",1, matVacuum);
   TGeoMedium *Al = new TGeoMedium("Root Material",2, matAl);

   //--- define the transformations
   TGeoTranslation *tr1 = new TGeoTranslation(20., 0, 0.);
   TGeoTranslation *tr2 = new TGeoTranslation(10., 0., 0.);
   TGeoTranslation *tr3 = new TGeoTranslation(10., 20., 0.);
   TGeoTranslation *tr4 = new TGeoTranslation(5., 10., 0.);
   TGeoTranslation *tr5 = new TGeoTranslation(20., 0., 0.);
   TGeoTranslation *tr6 = new TGeoTranslation(-5., 0., 0.);
   TGeoTranslation *tr7 = new TGeoTranslation(7.5, 7.5, 0.);
   TGeoRotation   *rot1 = new TGeoRotation("rot1", 90., 0., 90., 270., 0., 0.);
   TGeoCombiTrans *combi1 = new TGeoCombiTrans(7.5, -7.5, 0., rot1);
   TGeoTranslation *tr8 = new TGeoTranslation(7.5, -5., 0.);
   TGeoTranslation *tr9 = new TGeoTranslation(7.5, 20., 0.);
   TGeoTranslation *tr10 = new TGeoTranslation(85., 0., 0.);
   TGeoTranslation *tr11 = new TGeoTranslation(35., 0., 0.);
   TGeoTranslation *tr12 = new TGeoTranslation(-15., 0., 0.);
   TGeoTranslation *tr13 = new TGeoTranslation(-65., 0., 0.);

   TGeoTranslation  *tr14 = new TGeoTranslation(0,0,-100);
   TGeoCombiTrans *combi2 = new TGeoCombiTrans(0,0,100,
                                   new TGeoRotation("rot2",90,180,90,90,180,0));
   TGeoCombiTrans *combi3 = new TGeoCombiTrans(100,0,0,
                                   new TGeoRotation("rot3",90,270,0,0,90,180));
   TGeoCombiTrans *combi4 = new TGeoCombiTrans(-100,0,0,
                                   new TGeoRotation("rot4",90,90,0,0,90,0));
   TGeoCombiTrans *combi5 = new TGeoCombiTrans(0,100,0,
                                   new TGeoRotation("rot5",0,0,90,180,90,270));
   TGeoCombiTrans *combi6 = new TGeoCombiTrans(0,-100,0,
                                   new TGeoRotation("rot6",180,0,90,180,90,90));

   //--- make the top container volume
   Double_t worldx = 110.;
   Double_t worldy = 50.;
   Double_t worldz = 5.;
   TGeoVolume *top = geom->MakeBox("TOP", Vacuum, 270., 270., 120.);
   geom->SetTopVolume(top);
   TGeoVolume *replica = geom->MakeBox("REPLICA", Vacuum,120,120,120);
   replica->SetVisibility(kFALSE);
   TGeoVolume *rootbox = geom->MakeBox("ROOT", Vacuum, 110., 50., 5.);
   rootbox->SetVisibility(kFALSE);

   //--- make letter 'R'
   TGeoVolume *R = geom->MakeBox("R", Vacuum, 25., 25., 5.);
   R->SetVisibility(kFALSE);
   TGeoVolume *bar1 = geom->MakeBox("bar1", Al, 5., 25, 5.);
   bar1->SetLineColor(kRed);
   R->AddNode(bar1, 1, tr1);
   TGeoVolume *bar2 = geom->MakeBox("bar2", Al, 5., 5., 5.);
   bar2->SetLineColor(kRed);
   R->AddNode(bar2, 1, tr2);
   R->AddNode(bar2, 2, tr3);
   TGeoVolume *tub1 = geom->MakeTubs("tub1", Al, 5., 15., 5., 90., 270.);
   tub1->SetLineColor(kRed);
   R->AddNode(tub1, 1, tr4);
   TGeoVolume *bar3 = geom->MakeArb8("bar3", Al, 5.);
   bar3->SetLineColor(kRed);
   TGeoArb8 *arb = (TGeoArb8*)bar3->GetShape();
   arb->SetVertex(0, 15., -5.);
   arb->SetVertex(1, 0., -25.);
   arb->SetVertex(2, -10., -25.);
   arb->SetVertex(3, 5., -5.);
   arb->SetVertex(4, 15., -5.);
   arb->SetVertex(5, 0., -25.);
   arb->SetVertex(6, -10., -25.);
   arb->SetVertex(7, 5., -5.);
   R->AddNode(bar3, 1, gGeoIdentity);

   //--- make letter 'O'
   TGeoVolume *O = geom->MakeBox("O", Vacuum, 25., 25., 5.);
   O->SetVisibility(kFALSE);
   TGeoVolume *bar4 = geom->MakeBox("bar4", Al, 5., 7.5, 5.);
   bar4->SetLineColor(kYellow);
   O->AddNode(bar4, 1, tr5);
   O->AddNode(bar4, 2, tr6);
   TGeoVolume *tub2 = geom->MakeTubs("tub1", Al, 7.5, 17.5, 5., 0., 180.);
   tub2->SetLineColor(kYellow);
   O->AddNode(tub2, 1, tr7);
   O->AddNode(tub2, 2, combi1);

   //--- make letter 'T'
   TGeoVolume *T = geom->MakeBox("T", Vacuum, 25., 25., 5.);
   T->SetVisibility(kFALSE);
   TGeoVolume *bar5 = geom->MakeBox("bar5", Al, 5., 20., 5.);
   bar5->SetLineColor(kBlue);
   T->AddNode(bar5, 1, tr8);
   TGeoVolume *bar6 = geom->MakeBox("bar6", Al, 17.5, 5., 5.);
   bar6->SetLineColor(kBlue);
   T->AddNode(bar6, 1, tr9);

   rootbox->AddNode(R, 1, tr10);
   rootbox->AddNode(O, 1, tr11);
   rootbox->AddNode(O, 2, tr12);
   rootbox->AddNode(T, 1, tr13);

   replica->AddNode(rootbox, 1, tr14);
   replica->AddNode(rootbox, 2, combi2);
   replica->AddNode(rootbox, 3, combi3);
   replica->AddNode(rootbox, 4, combi4);
   replica->AddNode(rootbox, 5, combi5);
   replica->AddNode(rootbox, 6, combi6);

   top->AddNode(replica, 1, new TGeoTranslation(-150, -150, 0));
   top->AddNode(replica, 2, new TGeoTranslation(150, -150, 0));
   top->AddNode(replica, 3, new TGeoTranslation(150, 150, 0));
   top->AddNode(replica, 4, new TGeoTranslation(-150, 150, 0));

   //--- close the geometry
   geom->CloseGeometry();

   //--- draw the ROOT box.
   // by default the picture will appear in the standard ROOT TPad.
   //if you have activated the following line in system.rootrc,
   //it will appear in the GL viewer
   //#Viewer3D.DefaultDrawOption:   ogl

   geom->SetVisLevel(4);
   top->Draw("ogle");
}

<|endoftext|>


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

 Infomap software package for multi-level network clustering

 Copyright (c) 2013, 2014 Daniel Edler, Martin Rosvall

 For more information, see <http://www.mapequation.org>

 This file is part of Infomap software package.

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

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

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

**********************************************************************************/

#include "ProgramInterface.h"
#include <iostream>
#include <cstdlib>
#include <map>
#include <utility>
#include "convert.h"
#include "../utils/Log.h"

namespace infomap {

const std::string ArgType::integer = "integer";
const std::string ArgType::number = "number";
const std::string ArgType::string = "string";
const std::string ArgType::path = "path";
const std::string ArgType::probability = "probability";
const std::string ArgType::option = "option";
const std::string ArgType::list = "list";

const std::unordered_map<std::string, char> ArgType::toShort = {
  { "integer", 'n' },
  { "number", 'f' },
  { "string", 's' },
  { "path", 'p' },
  { "probability", 'P' },
  { "option", 'o' },
  { "list", 'l' },
};

ProgramInterface::ProgramInterface(std::string name, std::string shortDescription, std::string version)
    : m_programName(name),
      m_shortProgramDescription(shortDescription),
      m_programVersion(version)
{
  addIncrementalOptionArgument(m_displayHelp, 'h', "help", "Prints this help message. Use -hh to show advanced options.", "About");
  addOptionArgument(m_displayVersion, 'V', "version", "Display program version information.", "About");
  // addOptionArgument(m_negateNextOption, 'n', "negate-next", "Set the next (no-argument) option to false.", true);
  addOptionArgument(m_printJsonParameters, "print-json-parameters", "Print Infomap parameters in JSON.", "About").setHidden(true);
}

ProgramInterface::~ProgramInterface()
{
  for (unsigned int i = 0; i < m_nonOptionArguments.size(); ++i)
    delete m_nonOptionArguments[i];
  for (unsigned int i = 0; i < m_optionArguments.size(); ++i)
    delete m_optionArguments[i];
}

void ProgramInterface::exitWithUsage(bool showAdvanced)
{
  Log() << "Name:" << std::endl;
  Log() << "        " << m_programName << " - " << m_shortProgramDescription << std::endl;
  Log() << "\nUsage:" << std::endl;
  Log() << "        " << m_executableName;
  for (unsigned int i = 0; i < m_nonOptionArguments.size(); ++i)
    if (showAdvanced || !m_nonOptionArguments[i]->isAdvanced)
      Log() << " " << m_nonOptionArguments[i]->variableName;
  if (!m_optionArguments.empty())
    Log() << " [options]";
  Log() << std::endl;

  if (m_programDescription != "")
    Log() << "\nDescription:\n        " << m_programDescription << std::endl;

  for (unsigned int i = 0; i < m_nonOptionArguments.size(); ++i)
    if (showAdvanced || !m_nonOptionArguments[i]->isAdvanced)
      Log() << "\n[" << m_nonOptionArguments[i]->variableName << "]\n    " << m_nonOptionArguments[i]->description << std::endl;

  if (!m_optionArguments.empty())
    Log() << "\n[options]" << std::endl;

  // First stringify the options part to get the maximum length
  std::deque<std::string> optionStrings(m_optionArguments.size());
  std::string::size_type maxLength = 0;
  for (unsigned int i = 0; i < m_optionArguments.size(); ++i) {
    Option& opt = *m_optionArguments[i];
    bool haveShort = opt.shortName != '\0';
    std::string optArgShort = opt.requireArgument ? (io::Str() << "<" << ArgType::toShort.at(opt.argumentName) << ">") : opt.incrementalArgument ? "[+]" : std::string(3, ' ');
    std::string optArgLong = opt.requireArgument ? (io::Str() << "<" << opt.argumentName << ">") : opt.incrementalArgument ? "[+]" : std::string(3, ' ');
    std::string shortOption = haveShort ? (io::Str() << "  -" << opt.shortName << optArgShort) : std::string(7, ' ');
    optionStrings[i] = io::Str() << shortOption << " --" << opt.longName << " " << optArgLong;
    if (optionStrings[i].length() > maxLength)
      maxLength = optionStrings[i].length();
  }

  std::vector<std::string> groups { "About" };
  for (auto& group : m_groups) {
    if (group != "About")
      groups.push_back(group);
  }
  if (m_groups.empty())
    groups.push_back("All");

  for (auto group : groups) {
    if (group != "All") {
      Log() << "\n"
            << group << "\n";
      Log() << std::string(group.length(), '-') << "\n";
    }
    for (unsigned int i = 0; i < m_optionArguments.size(); ++i) {
      Option& opt = *m_optionArguments[i];
      if (group == "All" || opt.group == group) {
        std::string::size_type numSpaces = maxLength + 3 - optionStrings[i].length();
        if (showAdvanced || !opt.isAdvanced) {
          Log() << optionStrings[i] << std::string(numSpaces, ' ') << opt.description;
          if (!opt.printNumericValue().empty())
            Log() << " (Default: " << opt.printNumericValue() << ")";
          Log() << "\n";
        }
      }
    }
  }
  Log() << std::endl;
  std::exit(0);
}

void ProgramInterface::exitWithVersionInformation()
{
  Log() << m_programName << " version " << m_programVersion << std::endl;
  Log() << "See www.mapequation.org for terms of use." << std::endl;
  std::exit(0);
}

void ProgramInterface::exitWithError(std::string message)
{
  Log() << m_programName << " version " << m_programVersion << std::endl;
  std::cerr << message << std::endl;
  Log() << "Usage: " << m_executableName;
  for (unsigned int i = 0; i < m_nonOptionArguments.size(); ++i)
    if (!m_nonOptionArguments[i]->isAdvanced)
      Log() << " " << m_nonOptionArguments[i]->variableName;
  if (!m_optionArguments.empty())
    Log() << " [options]";
  Log() << ". Run with option '-h' for more information." << std::endl;
  std::exit(1);
}

void ProgramInterface::exitWithJsonParameters()
{
  Log() << "{\n  \"parameters\": [\n";

  for (unsigned int i = 0; i < m_optionArguments.size(); ++i) {
    Option& opt = *m_optionArguments[i];
    if (opt.hidden)
      continue;
    Log() << "    " << toJson(opt);
    if (i < m_optionArguments.size() - 1) {
      Log() << ",\n";
    } else {
      Log() << "\n";
    }
  }
  Log() << "  ]\n}";

  std::exit(0);
}

std::string ProgramInterface::toJson(std::string key, std::string value) const
{
  return io::Str() << "\"" << key << "\": \"" << value << "\"";
}

std::string ProgramInterface::toJson(std::string key, int value) const
{
  return io::Str() << "\"" << key << "\": " << value;
}

std::string ProgramInterface::toJson(std::string key, unsigned int value) const
{
  return io::Str() << "\"" << key << "\": " << value;
}

std::string ProgramInterface::toJson(std::string key, double value) const
{
  return io::Str() << "\"" << key << "\": " << value;
}

std::string ProgramInterface::toJson(std::string key, bool value) const
{
  return io::Str() << "\"" << key << "\": " << (value ? "true" : "false");
}

std::string ProgramInterface::toJson(const Option& opt) const
{
  return io::Str() << "{ " << toJson("long", io::Str() << "--" << opt.longName) << ", " << toJson("short", opt.shortName != '\0' ? std::string(io::Str() << "-" << opt.shortName) : "") << ", " << toJson("description", opt.description) << ", " << toJson("group", opt.group) << ", " << toJson("required", opt.requireArgument) << ", " << toJson("advanced", opt.isAdvanced) << ", " << toJson("incremental", opt.incrementalArgument) << ", " << (opt.requireArgument ? (io::Str() << toJson("longType", opt.argumentName) << ", " << toJson("shortType", std::string(1, ArgType::toShort.at(opt.argumentName))) << ", " << toJson("default", opt.printValue())) : toJson("default", false)) << " }";
}

void ProgramInterface::parseArgs(const std::string& args)
{
  // Map the options on short and long name, and check for duplication
  std::map<char, Option*> shortOptionMap;
  std::map<std::string, Option*> longOptionMap;
  for (unsigned int i = 0; i < m_optionArguments.size(); ++i) {
    Option& opt = *m_optionArguments[i];
    if (opt.shortName != '\0') {
      std::map<char, Option*>::iterator it = shortOptionMap.find(opt.shortName);
      if (it != shortOptionMap.end())
        throw OptionConflictError(io::Str() << "Duplication of option '" << opt.shortName << "'");
      shortOptionMap.insert(std::make_pair(opt.shortName, &opt));
    }

    std::map<std::string, Option*>::iterator it = longOptionMap.find(opt.longName);
    if (it != longOptionMap.end())
      throw OptionConflictError(io::Str() << "Duplication of option \"" << opt.longName << "\"");
    longOptionMap.insert(std::make_pair(opt.longName, &opt));
  }

  // Split the flags on whitespace
  std::vector<std::string> flags;
  std::istringstream argStream(args);
  std::string arg;
  while (!(argStream >> arg).fail())
    flags.push_back(arg);

  std::deque<std::string> nonOpts;
  try {
    for (unsigned int i = 0; i < flags.size(); ++i) {
      //bool negate = m_negateNextOption;
      m_negateNextOption = false;
      bool flagValue = true;
      unsigned int numArgsLeft = flags.size() - i - 1;

      const std::string& arg = flags[i];
      if (arg.length() == 0)
        throw InputSyntaxError("Illegal argument ''");

      if (arg[0] != '-') {
        nonOpts.push_back(arg);
      } else {
        if (arg.length() < 2)
          throw InputSyntaxError("Illegal argument '-'");

        if (arg[1] == '-') {
          // Long option
          if (arg.length() < 3)
            throw InputSyntaxError("Illegal argument '--'");
          std::string longOpt = arg.substr(2);
          std::map<std::string, Option*>::iterator it = longOptionMap.find(longOpt);
          if (it == longOptionMap.end()) {
            // Unrecognized option, check if it negates a recognised option with the '--no-' prefix
            if (longOpt.compare(0, 3, "no-") == 0 && longOptionMap.find(std::string(longOpt, 3)) != longOptionMap.end()) {
              longOpt = std::string(longOpt, 3);
              it = longOptionMap.find(longOpt);
              flagValue = false;
            } else {
              throw InputDomainError(io::Str() << "Unrecognized option: '--" << longOpt << "'");
            }
          }
          Option& opt = *it->second;
          if (!opt.requireArgument || opt.incrementalArgument)
            opt.set(flagValue);
          else {
            if (numArgsLeft == 0)
              throw InputDomainError(io::Str() << "Option '" << opt.longName << "' requires argument");
            ++i;
            if (!opt.parse(flags[i]))
              throw InputDomainError(io::Str() << "Cannot parse '" << flags[i] << "' as argument to option '" << opt.longName << "'. ");
          }
        } else {
          // Short option(s)
          for (unsigned int j = 1; j < arg.length(); ++j) {
            //negate = m_negateNextOption;
            m_negateNextOption = false;
            char o = arg[j];
            unsigned int numCharsLeft = arg.length() - j - 1;
            std::map<char, Option*>::iterator it = shortOptionMap.find(o);
            if (it == shortOptionMap.end())
              throw InputDomainError(io::Str() << "Unrecognized option: '-" << o << "'");
            Option& opt = *it->second;
            if (!opt.requireArgument || opt.incrementalArgument)
              opt.set(flagValue);
            else {
              std::string optArg;
              if (numCharsLeft > 0) {
                optArg = arg.substr(j + 1);
                j = arg.length() - 1;
              } else if (numArgsLeft) {
                ++i;
                optArg = flags[i];
              } else
                throw InputDomainError(io::Str() << "Option '" << opt.longName << "' requires argument");

              if (!opt.parse(optArg))
                throw InputDomainError(io::Str() << "Cannot parse '" << optArg << "' as argument to option '" << opt.longName << "'. ");
            }
          }
        }
      }
      if (m_displayHelp > 0)
        exitWithUsage(m_displayHelp > 1);
      if (m_displayVersion)
        exitWithVersionInformation();
      if (m_printJsonParameters)
        exitWithJsonParameters();
    }
  } catch (std::exception& e) {
    exitWithError(e.what());
  }

  if (nonOpts.size() < numRequiredArguments())
    exitWithError("Missing required arguments.");

  unsigned int i = 0;
  unsigned int numVectorArguments = nonOpts.size() - (m_nonOptionArguments.size() - 1);
  while (!nonOpts.empty()) {
    std::string arg = nonOpts.front();
    nonOpts.pop_front();
    if (m_nonOptionArguments[i]->isOptionalVector && numVectorArguments == 0)
      ++i;
    if (!m_nonOptionArguments[i]->parse(arg))
      exitWithError("Argument error.");
    if (!m_nonOptionArguments[i]->isOptionalVector || --numVectorArguments == 0)
      ++i;
  }
}

std::vector<ParsedOption> ProgramInterface::getUsedOptionArguments()
{
  std::vector<ParsedOption> opts;
  unsigned int numFlags = m_optionArguments.size();
  for (unsigned int i = 0; i < numFlags; ++i) {
    Option& opt = *m_optionArguments[i];
    if (opt.used && opt.longName != "negate-next")
      opts.push_back(ParsedOption(opt));
  }
  return opts;
}

} // namespace infomap
<commit_msg>docs: Show OpenMP support with version flag (#136)<commit_after>/**********************************************************************************

 Infomap software package for multi-level network clustering

 Copyright (c) 2013, 2014 Daniel Edler, Martin Rosvall

 For more information, see <http://www.mapequation.org>

 This file is part of Infomap software package.

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

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

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

**********************************************************************************/

#include "ProgramInterface.h"
#include <iostream>
#include <cstdlib>
#include <map>
#include <utility>
#include "convert.h"
#include "../utils/Log.h"

namespace infomap {

const std::string ArgType::integer = "integer";
const std::string ArgType::number = "number";
const std::string ArgType::string = "string";
const std::string ArgType::path = "path";
const std::string ArgType::probability = "probability";
const std::string ArgType::option = "option";
const std::string ArgType::list = "list";

const std::unordered_map<std::string, char> ArgType::toShort = {
  { "integer", 'n' },
  { "number", 'f' },
  { "string", 's' },
  { "path", 'p' },
  { "probability", 'P' },
  { "option", 'o' },
  { "list", 'l' },
};

ProgramInterface::ProgramInterface(std::string name, std::string shortDescription, std::string version)
    : m_programName(name),
      m_shortProgramDescription(shortDescription),
      m_programVersion(version)
{
  addIncrementalOptionArgument(m_displayHelp, 'h', "help", "Prints this help message. Use -hh to show advanced options.", "About");
  addOptionArgument(m_displayVersion, 'V', "version", "Display program version information.", "About");
  // addOptionArgument(m_negateNextOption, 'n', "negate-next", "Set the next (no-argument) option to false.", true);
  addOptionArgument(m_printJsonParameters, "print-json-parameters", "Print Infomap parameters in JSON.", "About").setHidden(true);
}

ProgramInterface::~ProgramInterface()
{
  for (unsigned int i = 0; i < m_nonOptionArguments.size(); ++i)
    delete m_nonOptionArguments[i];
  for (unsigned int i = 0; i < m_optionArguments.size(); ++i)
    delete m_optionArguments[i];
}

void ProgramInterface::exitWithUsage(bool showAdvanced)
{
  Log() << "Name:" << std::endl;
  Log() << "        " << m_programName << " - " << m_shortProgramDescription << std::endl;
  Log() << "\nUsage:" << std::endl;
  Log() << "        " << m_executableName;
  for (unsigned int i = 0; i < m_nonOptionArguments.size(); ++i)
    if (showAdvanced || !m_nonOptionArguments[i]->isAdvanced)
      Log() << " " << m_nonOptionArguments[i]->variableName;
  if (!m_optionArguments.empty())
    Log() << " [options]";
  Log() << std::endl;

  if (m_programDescription != "")
    Log() << "\nDescription:\n        " << m_programDescription << std::endl;

  for (unsigned int i = 0; i < m_nonOptionArguments.size(); ++i)
    if (showAdvanced || !m_nonOptionArguments[i]->isAdvanced)
      Log() << "\n[" << m_nonOptionArguments[i]->variableName << "]\n    " << m_nonOptionArguments[i]->description << std::endl;

  if (!m_optionArguments.empty())
    Log() << "\n[options]" << std::endl;

  // First stringify the options part to get the maximum length
  std::deque<std::string> optionStrings(m_optionArguments.size());
  std::string::size_type maxLength = 0;
  for (unsigned int i = 0; i < m_optionArguments.size(); ++i) {
    Option& opt = *m_optionArguments[i];
    bool haveShort = opt.shortName != '\0';
    std::string optArgShort = opt.requireArgument ? (io::Str() << "<" << ArgType::toShort.at(opt.argumentName) << ">") : opt.incrementalArgument ? "[+]" : std::string(3, ' ');
    std::string optArgLong = opt.requireArgument ? (io::Str() << "<" << opt.argumentName << ">") : opt.incrementalArgument ? "[+]" : std::string(3, ' ');
    std::string shortOption = haveShort ? (io::Str() << "  -" << opt.shortName << optArgShort) : std::string(7, ' ');
    optionStrings[i] = io::Str() << shortOption << " --" << opt.longName << " " << optArgLong;
    if (optionStrings[i].length() > maxLength)
      maxLength = optionStrings[i].length();
  }

  std::vector<std::string> groups { "About" };
  for (auto& group : m_groups) {
    if (group != "About")
      groups.push_back(group);
  }
  if (m_groups.empty())
    groups.push_back("All");

  for (auto group : groups) {
    if (group != "All") {
      Log() << "\n"
            << group << "\n";
      Log() << std::string(group.length(), '-') << "\n";
    }
    for (unsigned int i = 0; i < m_optionArguments.size(); ++i) {
      Option& opt = *m_optionArguments[i];
      if (group == "All" || opt.group == group) {
        std::string::size_type numSpaces = maxLength + 3 - optionStrings[i].length();
        if (showAdvanced || !opt.isAdvanced) {
          Log() << optionStrings[i] << std::string(numSpaces, ' ') << opt.description;
          if (!opt.printNumericValue().empty())
            Log() << " (Default: " << opt.printNumericValue() << ")";
          Log() << "\n";
        }
      }
    }
  }
  Log() << std::endl;
  std::exit(0);
}

void ProgramInterface::exitWithVersionInformation()
{
  Log() << m_programName << " version " << m_programVersion;
#ifdef _OPENMP
  Log() << " compiled with OpenMP";
#endif
  Log() << std::endl;
  Log() << "See www.mapequation.org for terms of use." << std::endl;
  std::exit(0);
}

void ProgramInterface::exitWithError(std::string message)
{
  Log() << m_programName << " version " << m_programVersion;
#ifdef _OPENMP
  Log() << " compiled with OpenMP";
#endif
  Log() << std::endl;
  std::cerr << message << std::endl;
  Log() << "Usage: " << m_executableName;
  for (unsigned int i = 0; i < m_nonOptionArguments.size(); ++i)
    if (!m_nonOptionArguments[i]->isAdvanced)
      Log() << " " << m_nonOptionArguments[i]->variableName;
  if (!m_optionArguments.empty())
    Log() << " [options]";
  Log() << ". Run with option '-h' for more information." << std::endl;
  std::exit(1);
}

void ProgramInterface::exitWithJsonParameters()
{
  Log() << "{\n  \"parameters\": [\n";

  for (unsigned int i = 0; i < m_optionArguments.size(); ++i) {
    Option& opt = *m_optionArguments[i];
    if (opt.hidden)
      continue;
    Log() << "    " << toJson(opt);
    if (i < m_optionArguments.size() - 1) {
      Log() << ",\n";
    } else {
      Log() << "\n";
    }
  }
  Log() << "  ]\n}";

  std::exit(0);
}

std::string ProgramInterface::toJson(std::string key, std::string value) const
{
  return io::Str() << "\"" << key << "\": \"" << value << "\"";
}

std::string ProgramInterface::toJson(std::string key, int value) const
{
  return io::Str() << "\"" << key << "\": " << value;
}

std::string ProgramInterface::toJson(std::string key, unsigned int value) const
{
  return io::Str() << "\"" << key << "\": " << value;
}

std::string ProgramInterface::toJson(std::string key, double value) const
{
  return io::Str() << "\"" << key << "\": " << value;
}

std::string ProgramInterface::toJson(std::string key, bool value) const
{
  return io::Str() << "\"" << key << "\": " << (value ? "true" : "false");
}

std::string ProgramInterface::toJson(const Option& opt) const
{
  return io::Str() << "{ " << toJson("long", io::Str() << "--" << opt.longName) << ", " << toJson("short", opt.shortName != '\0' ? std::string(io::Str() << "-" << opt.shortName) : "") << ", " << toJson("description", opt.description) << ", " << toJson("group", opt.group) << ", " << toJson("required", opt.requireArgument) << ", " << toJson("advanced", opt.isAdvanced) << ", " << toJson("incremental", opt.incrementalArgument) << ", " << (opt.requireArgument ? (io::Str() << toJson("longType", opt.argumentName) << ", " << toJson("shortType", std::string(1, ArgType::toShort.at(opt.argumentName))) << ", " << toJson("default", opt.printValue())) : toJson("default", false)) << " }";
}

void ProgramInterface::parseArgs(const std::string& args)
{
  // Map the options on short and long name, and check for duplication
  std::map<char, Option*> shortOptionMap;
  std::map<std::string, Option*> longOptionMap;
  for (unsigned int i = 0; i < m_optionArguments.size(); ++i) {
    Option& opt = *m_optionArguments[i];
    if (opt.shortName != '\0') {
      std::map<char, Option*>::iterator it = shortOptionMap.find(opt.shortName);
      if (it != shortOptionMap.end())
        throw OptionConflictError(io::Str() << "Duplication of option '" << opt.shortName << "'");
      shortOptionMap.insert(std::make_pair(opt.shortName, &opt));
    }

    std::map<std::string, Option*>::iterator it = longOptionMap.find(opt.longName);
    if (it != longOptionMap.end())
      throw OptionConflictError(io::Str() << "Duplication of option \"" << opt.longName << "\"");
    longOptionMap.insert(std::make_pair(opt.longName, &opt));
  }

  // Split the flags on whitespace
  std::vector<std::string> flags;
  std::istringstream argStream(args);
  std::string arg;
  while (!(argStream >> arg).fail())
    flags.push_back(arg);

  std::deque<std::string> nonOpts;
  try {
    for (unsigned int i = 0; i < flags.size(); ++i) {
      //bool negate = m_negateNextOption;
      m_negateNextOption = false;
      bool flagValue = true;
      unsigned int numArgsLeft = flags.size() - i - 1;

      const std::string& arg = flags[i];
      if (arg.length() == 0)
        throw InputSyntaxError("Illegal argument ''");

      if (arg[0] != '-') {
        nonOpts.push_back(arg);
      } else {
        if (arg.length() < 2)
          throw InputSyntaxError("Illegal argument '-'");

        if (arg[1] == '-') {
          // Long option
          if (arg.length() < 3)
            throw InputSyntaxError("Illegal argument '--'");
          std::string longOpt = arg.substr(2);
          std::map<std::string, Option*>::iterator it = longOptionMap.find(longOpt);
          if (it == longOptionMap.end()) {
            // Unrecognized option, check if it negates a recognised option with the '--no-' prefix
            if (longOpt.compare(0, 3, "no-") == 0 && longOptionMap.find(std::string(longOpt, 3)) != longOptionMap.end()) {
              longOpt = std::string(longOpt, 3);
              it = longOptionMap.find(longOpt);
              flagValue = false;
            } else {
              throw InputDomainError(io::Str() << "Unrecognized option: '--" << longOpt << "'");
            }
          }
          Option& opt = *it->second;
          if (!opt.requireArgument || opt.incrementalArgument)
            opt.set(flagValue);
          else {
            if (numArgsLeft == 0)
              throw InputDomainError(io::Str() << "Option '" << opt.longName << "' requires argument");
            ++i;
            if (!opt.parse(flags[i]))
              throw InputDomainError(io::Str() << "Cannot parse '" << flags[i] << "' as argument to option '" << opt.longName << "'. ");
          }
        } else {
          // Short option(s)
          for (unsigned int j = 1; j < arg.length(); ++j) {
            //negate = m_negateNextOption;
            m_negateNextOption = false;
            char o = arg[j];
            unsigned int numCharsLeft = arg.length() - j - 1;
            std::map<char, Option*>::iterator it = shortOptionMap.find(o);
            if (it == shortOptionMap.end())
              throw InputDomainError(io::Str() << "Unrecognized option: '-" << o << "'");
            Option& opt = *it->second;
            if (!opt.requireArgument || opt.incrementalArgument)
              opt.set(flagValue);
            else {
              std::string optArg;
              if (numCharsLeft > 0) {
                optArg = arg.substr(j + 1);
                j = arg.length() - 1;
              } else if (numArgsLeft) {
                ++i;
                optArg = flags[i];
              } else
                throw InputDomainError(io::Str() << "Option '" << opt.longName << "' requires argument");

              if (!opt.parse(optArg))
                throw InputDomainError(io::Str() << "Cannot parse '" << optArg << "' as argument to option '" << opt.longName << "'. ");
            }
          }
        }
      }
      if (m_displayHelp > 0)
        exitWithUsage(m_displayHelp > 1);
      if (m_displayVersion)
        exitWithVersionInformation();
      if (m_printJsonParameters)
        exitWithJsonParameters();
    }
  } catch (std::exception& e) {
    exitWithError(e.what());
  }

  if (nonOpts.size() < numRequiredArguments())
    exitWithError("Missing required arguments.");

  unsigned int i = 0;
  unsigned int numVectorArguments = nonOpts.size() - (m_nonOptionArguments.size() - 1);
  while (!nonOpts.empty()) {
    std::string arg = nonOpts.front();
    nonOpts.pop_front();
    if (m_nonOptionArguments[i]->isOptionalVector && numVectorArguments == 0)
      ++i;
    if (!m_nonOptionArguments[i]->parse(arg))
      exitWithError("Argument error.");
    if (!m_nonOptionArguments[i]->isOptionalVector || --numVectorArguments == 0)
      ++i;
  }
}

std::vector<ParsedOption> ProgramInterface::getUsedOptionArguments()
{
  std::vector<ParsedOption> opts;
  unsigned int numFlags = m_optionArguments.size();
  for (unsigned int i = 0; i < numFlags; ++i) {
    Option& opt = *m_optionArguments[i];
    if (opt.used && opt.longName != "negate-next")
      opts.push_back(ParsedOption(opt));
  }
  return opts;
}

} // namespace infomap
<|endoftext|>


<commit_before>#pragma once
#include <cmath>

#include "global_config.hpp"

namespace mocc {

    union float_int {
        float f;
        int32_t i;
    };

    union double_int {
        double f;
        int64_t i;
    };

    inline bool fp_equiv_ulp(float v1, float v2) {
        float_int i1;
        i1.f = v1;
        if (i1.i < 0) {
            i1.i = 0x80000000 - i1.i;
        }

        float_int i2;
        i2.f = v2;
        if (i2.i < 0) {
            i2.i = 0x80000000 - i2.i;
        }

        return std::abs(i1.i - i2.i) < 100;
    }

    inline bool fp_equiv_ulp(double v1, double v2) {
        double_int i1;
        i1.f = v1;
        if (i1.i < 0) {
            i1.i = 0x80000000 - i1.i;
        }

        double_int i2;
        i2.f = v2;
        if (i2.i < 0) {
            i2.i = 0x80000000 - i2.i;
        }

        return std::abs(i1.i - i2.i) < 100;
    }

    inline bool fp_equiv_rel(float_t v1, float_t v2) {
        return fabs(v1-v2)/fabs(v1) < FLOAT_EPS;
    }
    inline bool fp_equiv_abs(float_t v1, float_t v2) {
        return fabs(v1-v2) < FLOAT_EPS;
    }
}
<commit_msg>Hide the unions in fp_utils in their own namespace<commit_after>#pragma once
#include <cmath>

#include "global_config.hpp"

namespace mocc {

    namespace fp_utils {
        union float_int {
            float f;
            int32_t i;
        };

        union double_int {
            double f;
            int64_t i;
        };
    }

    inline bool fp_equiv_ulp(float v1, float v2) {
        fp_utils::float_int i1;
        i1.f = v1;
        if (i1.i < 0) {
            i1.i = 0x80000000 - i1.i;
        }

        fp_utils::float_int i2;
        i2.f = v2;
        if (i2.i < 0) {
            i2.i = 0x80000000 - i2.i;
        }

        return std::abs(i1.i - i2.i) < 100;
    }

    inline bool fp_equiv_ulp(double v1, double v2) {
        fp_utils::double_int i1;
        i1.f = v1;
        if (i1.i < 0) {
            i1.i = 0x80000000 - i1.i;
        }

        fp_utils::double_int i2;
        i2.f = v2;
        if (i2.i < 0) {
            i2.i = 0x80000000 - i2.i;
        }

        return std::abs(i1.i - i2.i) < 100;
    }

    inline bool fp_equiv_rel(float_t v1, float_t v2) {
        return fabs(v1-v2)/fabs(v1) < FLOAT_EPS;
    }
    inline bool fp_equiv_abs(float_t v1, float_t v2) {
        return fabs(v1-v2) < FLOAT_EPS;
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright 2007-2018 Content Management AG
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "FileIstream.hxx"
#include "istream.hxx"
#include "New.hxx"
#include "Result.hxx"
#include "io/Buffered.hxx"
#include "io/Open.hxx"
#include "io/UniqueFileDescriptor.hxx"
#include "pool/pool.hxx"
#include "fb_pool.hxx"
#include "SliceFifoBuffer.hxx"
#include "system/Error.hxx"
#include "event/TimerEvent.hxx"
#include "util/RuntimeError.hxx"

#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <limits.h>

/**
 * If EAGAIN occurs (on NFS), we try again after 100ms.  We can't
 * check SocketEvent::READ, because the kernel always indicates VFS files as
 * "readable without blocking".
 */
static const struct timeval file_retry_timeout = {
    .tv_sec = 0,
    .tv_usec = 100000,
};

class FileIstream final : public Istream {
    FileDescriptor fd;

    FdType fd_type;

    /**
     * A timer to retry reading after EAGAIN.
     */
    TimerEvent retry_event;

    off_t rest;
    SliceFifoBuffer buffer;
    const char *path;

public:
    FileIstream(struct pool &p, EventLoop &event_loop,
                UniqueFileDescriptor &&_fd, FdType _fd_type, off_t _length,
                const char *_path) noexcept
        :Istream(p),
         fd(_fd.Steal()), fd_type(_fd_type),
         retry_event(event_loop, BIND_THIS_METHOD(EventCallback)),
         rest(_length),
         path(_path) {}

    ~FileIstream() noexcept {
        retry_event.Cancel();
    }

    FileDescriptor GetFileDescriptor() const noexcept {
        assert(fd.IsDefined());
        return fd;
    }

    bool SetRange(off_t start, off_t end) noexcept {
        assert(start >= 0);
        assert(end >= start);
        assert(fd.IsDefined());
        assert(rest >= 0);
        assert(buffer.IsNull());
        assert(end <= rest);

        if (start > 0 && fd.Skip(start) < 0)
            return false;

        rest = end - start;
        return true;
    }

private:
    void CloseHandle() noexcept {
        if (!fd.IsDefined())
            return;

        retry_event.Cancel();

        fd.Close();

        buffer.FreeIfDefined();
    }

    void Abort(std::exception_ptr ep) noexcept {
        CloseHandle();
        DestroyError(ep);
    }

    /**
     * @return the number of bytes still in the buffer
     */
    size_t SubmitBuffer() noexcept {
        return ConsumeFromBuffer(buffer);
    }

    void EofDetected() noexcept {
        assert(fd.IsDefined());

        CloseHandle();
        DestroyEof();
    }

    gcc_pure
    size_t GetMaxRead() const noexcept {
        if (rest != (off_t)-1 && rest < (off_t)INT_MAX)
            return (size_t)rest;
        else
            return INT_MAX;
    }

    void TryData() noexcept;
    void TryDirect() noexcept;

    void TryRead() noexcept {
        if (CheckDirect(fd_type))
            TryDirect();
        else
            TryData();
    }

    void EventCallback() noexcept {
        TryRead();
    }

    /* virtual methods from class Istream */

    off_t _GetAvailable(bool partial) noexcept override;
    off_t _Skip(gcc_unused off_t length) noexcept override;

    void _Read() noexcept override {
        retry_event.Cancel();
        TryRead();
    }

    int _AsFd() noexcept override;
    void _Close() noexcept override {
        CloseHandle();
        Destroy();
    }
};

inline void
FileIstream::TryData() noexcept
{
    size_t buffer_rest = 0;

    if (buffer.IsNull()) {
        if (rest != 0)
            buffer.Allocate(fb_pool_get());
    } else {
        const size_t available = buffer.GetAvailable();
        if (available > 0) {
            buffer_rest = SubmitBuffer();
            if (buffer_rest == available)
                /* not a single byte was consumed: we may have been
                   closed, and we must bail out now */
                return;
        }
    }

    if (rest == 0) {
        if (buffer_rest == 0)
            EofDetected();
        return;
    }

    ssize_t nbytes = read_to_buffer(fd.Get(), buffer, GetMaxRead());
    if (nbytes == 0) {
        if (rest == (off_t)-1) {
            rest = 0;
            if (buffer_rest == 0)
                EofDetected();
        } else {
            Abort(std::make_exception_ptr(FormatRuntimeError("premature end of file in '%s'",
                                                             path)));
        }
        return;
    } else if (nbytes == -1) {
        Abort(std::make_exception_ptr(FormatErrno("Failed to read from '%s'",
                                                  path)));
        return;
    } else if (nbytes > 0 && rest != (off_t)-1) {
        rest -= (off_t)nbytes;
        assert(rest >= 0);
    }

    assert(!buffer.empty());

    buffer_rest = SubmitBuffer();
    if (buffer_rest == 0 && rest == 0)
        EofDetected();
}

inline void
FileIstream::TryDirect() noexcept
{
    /* first consume the rest of the buffer */
    if (SubmitBuffer() > 0)
        return;

    if (rest == 0) {
        EofDetected();
        return;
    }

    ssize_t nbytes = InvokeDirect(fd_type, fd.Get(), GetMaxRead());
    if (nbytes == ISTREAM_RESULT_CLOSED)
        /* this stream was closed during the direct() callback */
        return;

    if (nbytes > 0 || nbytes == ISTREAM_RESULT_BLOCKING) {
        /* -2 means the callback wasn't able to consume any data right
           now */
        if (nbytes > 0 && rest != (off_t)-1) {
            rest -= (off_t)nbytes;
            assert(rest >= 0);
            if (rest == 0)
                EofDetected();
        }
    } else if (nbytes == ISTREAM_RESULT_EOF) {
        if (rest == (off_t)-1) {
            EofDetected();
        } else {
            Abort(std::make_exception_ptr(FormatRuntimeError("premature end of file in '%s'",
                                                             path)));
        }
    } else if (errno == EAGAIN) {
        /* this should only happen for splice(SPLICE_F_NONBLOCK) from
           NFS files - unfortunately we cannot use SocketEvent::READ
           here, so we just install a timer which retries after
           100ms */

        retry_event.Add(file_retry_timeout);
    } else {
        /* XXX */
        Abort(std::make_exception_ptr(FormatErrno("Failed to read from '%s'",
                                                  path)));
    }
}

/*
 * istream implementation
 *
 */

off_t
FileIstream::_GetAvailable(bool partial) noexcept
{
    off_t available;
    if (rest != (off_t)-1)
        available = rest;
    else if (!partial)
        return (off_t)-1;
    else
        available = 0;

    available += buffer.GetAvailable();
    return available;
}

off_t
FileIstream::_Skip(off_t length) noexcept
{
    retry_event.Cancel();

    if (rest == (off_t)-1)
        return (off_t)-1;

    if (length == 0)
        return 0;

    const size_t buffer_available = buffer.GetAvailable();
    if (length < off_t(buffer_available)) {
        buffer.Consume(length);
        Consumed(length);
        return length;
    }

    length -= buffer_available;
    buffer.Clear();

    if (length >= rest) {
        /* skip beyond EOF */

        length = rest;
        rest = 0;
    } else {
        /* seek the file descriptor */

        if (fd.Skip(length) < 0)
            return -1;
        rest -= length;
    }

    off_t result = buffer_available + length;
    Consumed(result);
    return result;
}

int
FileIstream::_AsFd() noexcept
{
    int result_fd = fd.Steal();

    Destroy();

    return result_fd;
}

/*
 * constructor and public methods
 *
 */

Istream *
istream_file_fd_new(EventLoop &event_loop, struct pool &pool,
                    const char *path,
                    UniqueFileDescriptor fd, FdType fd_type, off_t length) noexcept
{
    assert(fd.IsDefined());
    assert(length >= -1);

    return NewIstream<FileIstream>(pool, event_loop,
                                   std::move(fd), fd_type,
                                   length, path);
}

Istream *
istream_file_stat_new(EventLoop &event_loop, struct pool &pool,
                      const char *path, struct stat &st)
{
    assert(path != nullptr);

    auto fd = OpenReadOnly(path);

    if (fstat(fd.Get(), &st) < 0)
        throw FormatErrno("Failed to stat %s", path);

    FdType fd_type = FdType::FD_FILE;
    off_t size = st.st_size;

    if (S_ISCHR(st.st_mode)) {
        fd_type = FdType::FD_CHARDEV;
        size = -1;
    }

    return istream_file_fd_new(event_loop, pool, path,
                               std::move(fd), fd_type, size);
}

Istream *
istream_file_new(EventLoop &event_loop, struct pool &pool,
                 const char *path, off_t length)
{
    assert(length >= -1);

    return istream_file_fd_new(event_loop, pool, path,
                               OpenReadOnly(path), FdType::FD_FILE, length);
}

FileDescriptor
istream_file_fd(Istream &istream) noexcept
{
    auto &file = (FileIstream &)istream;
    return file.GetFileDescriptor();
}

bool
istream_file_set_range(Istream &istream, off_t start, off_t end) noexcept
{
    auto &file = (FileIstream &)istream;
    return file.SetRange(start, end);
}
<commit_msg>istream/file: use TimerEvent::Schedule()<commit_after>/*
 * Copyright 2007-2018 Content Management AG
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "FileIstream.hxx"
#include "istream.hxx"
#include "New.hxx"
#include "Result.hxx"
#include "io/Buffered.hxx"
#include "io/Open.hxx"
#include "io/UniqueFileDescriptor.hxx"
#include "pool/pool.hxx"
#include "fb_pool.hxx"
#include "SliceFifoBuffer.hxx"
#include "system/Error.hxx"
#include "event/TimerEvent.hxx"
#include "util/RuntimeError.hxx"

#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <limits.h>

/**
 * If EAGAIN occurs (on NFS), we try again after 100ms.  We can't
 * check SocketEvent::READ, because the kernel always indicates VFS files as
 * "readable without blocking".
 */
static constexpr Event::Duration file_retry_timeout = std::chrono::milliseconds(100);

class FileIstream final : public Istream {
    FileDescriptor fd;

    FdType fd_type;

    /**
     * A timer to retry reading after EAGAIN.
     */
    TimerEvent retry_event;

    off_t rest;
    SliceFifoBuffer buffer;
    const char *path;

public:
    FileIstream(struct pool &p, EventLoop &event_loop,
                UniqueFileDescriptor &&_fd, FdType _fd_type, off_t _length,
                const char *_path) noexcept
        :Istream(p),
         fd(_fd.Steal()), fd_type(_fd_type),
         retry_event(event_loop, BIND_THIS_METHOD(EventCallback)),
         rest(_length),
         path(_path) {}

    ~FileIstream() noexcept {
        retry_event.Cancel();
    }

    FileDescriptor GetFileDescriptor() const noexcept {
        assert(fd.IsDefined());
        return fd;
    }

    bool SetRange(off_t start, off_t end) noexcept {
        assert(start >= 0);
        assert(end >= start);
        assert(fd.IsDefined());
        assert(rest >= 0);
        assert(buffer.IsNull());
        assert(end <= rest);

        if (start > 0 && fd.Skip(start) < 0)
            return false;

        rest = end - start;
        return true;
    }

private:
    void CloseHandle() noexcept {
        if (!fd.IsDefined())
            return;

        retry_event.Cancel();

        fd.Close();

        buffer.FreeIfDefined();
    }

    void Abort(std::exception_ptr ep) noexcept {
        CloseHandle();
        DestroyError(ep);
    }

    /**
     * @return the number of bytes still in the buffer
     */
    size_t SubmitBuffer() noexcept {
        return ConsumeFromBuffer(buffer);
    }

    void EofDetected() noexcept {
        assert(fd.IsDefined());

        CloseHandle();
        DestroyEof();
    }

    gcc_pure
    size_t GetMaxRead() const noexcept {
        if (rest != (off_t)-1 && rest < (off_t)INT_MAX)
            return (size_t)rest;
        else
            return INT_MAX;
    }

    void TryData() noexcept;
    void TryDirect() noexcept;

    void TryRead() noexcept {
        if (CheckDirect(fd_type))
            TryDirect();
        else
            TryData();
    }

    void EventCallback() noexcept {
        TryRead();
    }

    /* virtual methods from class Istream */

    off_t _GetAvailable(bool partial) noexcept override;
    off_t _Skip(gcc_unused off_t length) noexcept override;

    void _Read() noexcept override {
        retry_event.Cancel();
        TryRead();
    }

    int _AsFd() noexcept override;
    void _Close() noexcept override {
        CloseHandle();
        Destroy();
    }
};

inline void
FileIstream::TryData() noexcept
{
    size_t buffer_rest = 0;

    if (buffer.IsNull()) {
        if (rest != 0)
            buffer.Allocate(fb_pool_get());
    } else {
        const size_t available = buffer.GetAvailable();
        if (available > 0) {
            buffer_rest = SubmitBuffer();
            if (buffer_rest == available)
                /* not a single byte was consumed: we may have been
                   closed, and we must bail out now */
                return;
        }
    }

    if (rest == 0) {
        if (buffer_rest == 0)
            EofDetected();
        return;
    }

    ssize_t nbytes = read_to_buffer(fd.Get(), buffer, GetMaxRead());
    if (nbytes == 0) {
        if (rest == (off_t)-1) {
            rest = 0;
            if (buffer_rest == 0)
                EofDetected();
        } else {
            Abort(std::make_exception_ptr(FormatRuntimeError("premature end of file in '%s'",
                                                             path)));
        }
        return;
    } else if (nbytes == -1) {
        Abort(std::make_exception_ptr(FormatErrno("Failed to read from '%s'",
                                                  path)));
        return;
    } else if (nbytes > 0 && rest != (off_t)-1) {
        rest -= (off_t)nbytes;
        assert(rest >= 0);
    }

    assert(!buffer.empty());

    buffer_rest = SubmitBuffer();
    if (buffer_rest == 0 && rest == 0)
        EofDetected();
}

inline void
FileIstream::TryDirect() noexcept
{
    /* first consume the rest of the buffer */
    if (SubmitBuffer() > 0)
        return;

    if (rest == 0) {
        EofDetected();
        return;
    }

    ssize_t nbytes = InvokeDirect(fd_type, fd.Get(), GetMaxRead());
    if (nbytes == ISTREAM_RESULT_CLOSED)
        /* this stream was closed during the direct() callback */
        return;

    if (nbytes > 0 || nbytes == ISTREAM_RESULT_BLOCKING) {
        /* -2 means the callback wasn't able to consume any data right
           now */
        if (nbytes > 0 && rest != (off_t)-1) {
            rest -= (off_t)nbytes;
            assert(rest >= 0);
            if (rest == 0)
                EofDetected();
        }
    } else if (nbytes == ISTREAM_RESULT_EOF) {
        if (rest == (off_t)-1) {
            EofDetected();
        } else {
            Abort(std::make_exception_ptr(FormatRuntimeError("premature end of file in '%s'",
                                                             path)));
        }
    } else if (errno == EAGAIN) {
        /* this should only happen for splice(SPLICE_F_NONBLOCK) from
           NFS files - unfortunately we cannot use SocketEvent::READ
           here, so we just install a timer which retries after
           100ms */

        retry_event.Schedule(file_retry_timeout);
    } else {
        /* XXX */
        Abort(std::make_exception_ptr(FormatErrno("Failed to read from '%s'",
                                                  path)));
    }
}

/*
 * istream implementation
 *
 */

off_t
FileIstream::_GetAvailable(bool partial) noexcept
{
    off_t available;
    if (rest != (off_t)-1)
        available = rest;
    else if (!partial)
        return (off_t)-1;
    else
        available = 0;

    available += buffer.GetAvailable();
    return available;
}

off_t
FileIstream::_Skip(off_t length) noexcept
{
    retry_event.Cancel();

    if (rest == (off_t)-1)
        return (off_t)-1;

    if (length == 0)
        return 0;

    const size_t buffer_available = buffer.GetAvailable();
    if (length < off_t(buffer_available)) {
        buffer.Consume(length);
        Consumed(length);
        return length;
    }

    length -= buffer_available;
    buffer.Clear();

    if (length >= rest) {
        /* skip beyond EOF */

        length = rest;
        rest = 0;
    } else {
        /* seek the file descriptor */

        if (fd.Skip(length) < 0)
            return -1;
        rest -= length;
    }

    off_t result = buffer_available + length;
    Consumed(result);
    return result;
}

int
FileIstream::_AsFd() noexcept
{
    int result_fd = fd.Steal();

    Destroy();

    return result_fd;
}

/*
 * constructor and public methods
 *
 */

Istream *
istream_file_fd_new(EventLoop &event_loop, struct pool &pool,
                    const char *path,
                    UniqueFileDescriptor fd, FdType fd_type, off_t length) noexcept
{
    assert(fd.IsDefined());
    assert(length >= -1);

    return NewIstream<FileIstream>(pool, event_loop,
                                   std::move(fd), fd_type,
                                   length, path);
}

Istream *
istream_file_stat_new(EventLoop &event_loop, struct pool &pool,
                      const char *path, struct stat &st)
{
    assert(path != nullptr);

    auto fd = OpenReadOnly(path);

    if (fstat(fd.Get(), &st) < 0)
        throw FormatErrno("Failed to stat %s", path);

    FdType fd_type = FdType::FD_FILE;
    off_t size = st.st_size;

    if (S_ISCHR(st.st_mode)) {
        fd_type = FdType::FD_CHARDEV;
        size = -1;
    }

    return istream_file_fd_new(event_loop, pool, path,
                               std::move(fd), fd_type, size);
}

Istream *
istream_file_new(EventLoop &event_loop, struct pool &pool,
                 const char *path, off_t length)
{
    assert(length >= -1);

    return istream_file_fd_new(event_loop, pool, path,
                               OpenReadOnly(path), FdType::FD_FILE, length);
}

FileDescriptor
istream_file_fd(Istream &istream) noexcept
{
    auto &file = (FileIstream &)istream;
    return file.GetFileDescriptor();
}

bool
istream_file_set_range(Istream &istream, off_t start, off_t end) noexcept
{
    auto &file = (FileIstream &)istream;
    return file.SetRange(start, end);
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2012 by Glenn Hickey (hickey@soe.ucsc.edu)
 *
 * Released under the MIT license, see LICENSE.txt
 */

#include <deque>
#include <cassert>
#include "halMafExport.h"

using namespace std;
using namespace hal;

MafExport::MafExport() : _maxRefGap(0), _noDupes(false)
{

}

MafExport::~MafExport()
{

}

void MafExport::setMaxRefGap(hal_size_t maxRefGap)
{
  _maxRefGap = maxRefGap;
}

void MafExport::setNoDupes(bool noDupes)
{
  _noDupes = noDupes;
}

void MafExport::setNoAncestors(bool noAncestors)
{
  _noAncestors = noAncestors;
}

void MafExport::setUcscNames(bool ucscNames)
{
  _ucscNames = ucscNames;
}

void MafExport::setUnique(bool unique)
{
  _unique = unique;
}

void MafExport::setAppend(bool append)
{
  _append = append;
}

void MafExport::writeHeader()
{
  assert(_mafStream != NULL);
  if (_mafStream->tellp() == streampos(0))
  {
    *_mafStream << "##maf version=1 scoring=N/A\n"
                << "# hal " << _alignment->getNewickTree() << endl << endl;
  }
}

void MafExport::convertSegmentedSequence(ostream& mafStream,
                                         AlignmentConstPtr alignment,
                                         const SegmentedSequence* seq,
                                         hal_index_t startPosition,
                                         hal_size_t length,
                                         const set<const Genome*>& targets)
{
  assert(seq != NULL);
  if (startPosition >= (hal_index_t)seq->getSequenceLength() ||
      (hal_size_t)startPosition + length > seq->getSequenceLength())
  {
    throw hal_exception("Invalid range specified for convertGenome");
  }
  if (length == 0)
  {
    length = seq->getSequenceLength() - startPosition;
  }
  if (length == 0)
  {
    throw hal_exception("Cannot convert zero length sequence");
  }
  hal_index_t lastPosition = startPosition + (hal_index_t)(length - 1);

  _mafStream = &mafStream;
  _alignment = alignment;
  if (!_append)
  {
    writeHeader();
  }

  ColumnIteratorConstPtr colIt = seq->getColumnIterator(&targets,
                                                        _maxRefGap,
                                                        startPosition,
                                                        lastPosition,
                                                        _noDupes,
                                                        _noAncestors);
  _mafBlock.initBlock(colIt, _ucscNames);
  assert(_mafBlock.canAppendColumn(colIt) == true);
  hal_size_t appendCount = 0;
  if (_unique == false || colIt->isCanonicalOnRef() == true)
  {
    _mafBlock.appendColumn(colIt);
    ++appendCount;
  }
  size_t numBlocks = 0;
  while (colIt->lastColumn() == false)
  {
    colIt->toRight();
    if (_unique == false || colIt->isCanonicalOnRef() == true)
    {
      if (_mafBlock.canAppendColumn(colIt) == false)
      {
        // erase empty entries from the column.  helps when there are
        // millions of sequences (ie from fastas with lots of scaffolds)
        if (numBlocks++ % 1000 == 0)
        {
          colIt->defragment();
        }
        if (appendCount > 0)
        {
          mafStream << _mafBlock << '\n';
        }
        _mafBlock.initBlock(colIt, _ucscNames);
        assert(_mafBlock.canAppendColumn(colIt) == true);
      }
      _mafBlock.appendColumn(colIt);
      ++appendCount;
    }
  }
  mafStream << _mafBlock << endl;
}

<commit_msg>fix unique option<commit_after>/*
 * Copyright (C) 2012 by Glenn Hickey (hickey@soe.ucsc.edu)
 *
 * Released under the MIT license, see LICENSE.txt
 */

#include <deque>
#include <cassert>
#include "halMafExport.h"

using namespace std;
using namespace hal;

MafExport::MafExport() : _maxRefGap(0), _noDupes(false)
{

}

MafExport::~MafExport()
{

}

void MafExport::setMaxRefGap(hal_size_t maxRefGap)
{
  _maxRefGap = maxRefGap;
}

void MafExport::setNoDupes(bool noDupes)
{
  _noDupes = noDupes;
}

void MafExport::setNoAncestors(bool noAncestors)
{
  _noAncestors = noAncestors;
}

void MafExport::setUcscNames(bool ucscNames)
{
  _ucscNames = ucscNames;
}

void MafExport::setUnique(bool unique)
{
  _unique = unique;
}

void MafExport::setAppend(bool append)
{
  _append = append;
}

void MafExport::writeHeader()
{
  assert(_mafStream != NULL);
  if (_mafStream->tellp() == streampos(0))
  {
    *_mafStream << "##maf version=1 scoring=N/A\n"
                << "# hal " << _alignment->getNewickTree() << endl << endl;
  }
}

void MafExport::convertSegmentedSequence(ostream& mafStream,
                                         AlignmentConstPtr alignment,
                                         const SegmentedSequence* seq,
                                         hal_index_t startPosition,
                                         hal_size_t length,
                                         const set<const Genome*>& targets)
{
  assert(seq != NULL);
  if (startPosition >= (hal_index_t)seq->getSequenceLength() ||
      (hal_size_t)startPosition + length > seq->getSequenceLength())
  {
    throw hal_exception("Invalid range specified for convertGenome");
  }
  if (length == 0)
  {
    length = seq->getSequenceLength() - startPosition;
  }
  if (length == 0)
  {
    throw hal_exception("Cannot convert zero length sequence");
  }
  hal_index_t lastPosition = startPosition + (hal_index_t)(length - 1);

  _mafStream = &mafStream;
  _alignment = alignment;
  if (!_append)
  {
    writeHeader();
  }

  ColumnIteratorConstPtr colIt = seq->getColumnIterator(&targets,
                                                        _maxRefGap,
                                                        startPosition,
                                                        lastPosition,
                                                        _noDupes,
                                                        _noAncestors);

  hal_size_t appendCount = 0;
  if (_unique == false || colIt->isCanonicalOnRef() == true)
  {
    _mafBlock.initBlock(colIt, _ucscNames);
    assert(_mafBlock.canAppendColumn(colIt) == true);
    _mafBlock.appendColumn(colIt);
    ++appendCount;
  }
  size_t numBlocks = 0;
  while (colIt->lastColumn() == false)
  {
    colIt->toRight();
    if (_unique == false || colIt->isCanonicalOnRef() == true)
    {
      if (appendCount == 0)
      {
        _mafBlock.initBlock(colIt, _ucscNames);
        assert(_mafBlock.canAppendColumn(colIt) == true);
      }
      if (_mafBlock.canAppendColumn(colIt) == false)
      {
        // erase empty entries from the column.  helps when there are
        // millions of sequences (ie from fastas with lots of scaffolds)
        if (numBlocks++ % 1000 == 0)
        {
          colIt->defragment();
        }
        if (appendCount > 0)
        {
          mafStream << _mafBlock << '\n';
        }
        _mafBlock.initBlock(colIt, _ucscNames);
        assert(_mafBlock.canAppendColumn(colIt) == true);
      }
      _mafBlock.appendColumn(colIt);
      ++appendCount;
    }
  }
  mafStream << _mafBlock << endl;
}

<|endoftext|>


<commit_before>/* The MIT License:

Copyright (c) 2009-2011 Ivan Gagis

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. */

/**
 * @file Zip file reader
 * @author Ivan Gagis <igagis@gmail.com>
 */

#pragma once

#include <unzip/unzip.h>

#include <ting/debug.hpp>
#include <ting/fs/File.hpp>

class ZipFile : public ting::fs::File{
	std::string zipFilePath;

	unzFile zipFile; //ZIP file handle (unzFile is actually a pointer)
public:
	//TODO: should accept ting::File from where to read the zip file data
	ZipFile(const std::string& pathToZipFile = std::string(), const std::string& path = std::string()) :
			File(path),
			zipFilePath(pathToZipFile.c_str()),//copy
			zipFile(0)
	{}

	~ZipFile()throw(){
		this->CloseZipFile();
	}

	void OpenZipFile(){
		if(this->ZipFileIsOpened())
			throw File::Exc("ZipFile::OpenZipFile(): zip file is already opened");

		ASSERT(!this->IsOpened())

		if(this->zipFilePath.size() == 0)
			throw File::Exc("ZipFile::OpenZipFile(): zip file path is not set");

		this->zipFile = unzOpen(this->zipFilePath.c_str());

		if(!this->zipFile)
			throw File::Exc("ZipFile::OpenZipFile(): opening zip file failed");
	}

	void CloseZipFile()throw(){
		if(!this->ZipFileIsOpened()){
			return;
		}

		//make sure there is no file opened inside zip file
		this->Close();

		if(unzClose(this->zipFile) != UNZ_OK){
			ASSERT(false)
		}

		this->zipFile = 0;
	}

	inline bool ZipFileIsOpened()const throw(){
		return this->zipFile != 0;
	}

	inline void SetZipFilePath(const std::string &path){
		if(this->ZipFileIsOpened()){
			throw File::Exc("ZipFile::SetZipFilePath(): cannot set zip file path while the zip file is opened");
		}
		this->zipFilePath = std::string(path.c_str());//immediate copy (we do not want copy-on-write)
	}

	inline std::string GetZipFilePath()const{
		return this->zipFilePath;
	}

	//override
	virtual void Open(EMode mode){
		if(!this->ZipFileIsOpened())
			throw File::Exc("ZipFile::Open(): zip file is not opened");

		if(this->IsOpened())
			throw File::Exc("file already opened");

		if(mode != File::READ)
			throw File::Exc("illegal mode requested, only READ supported inside ZIP file");

		if(unzLocateFile(this->zipFile, this->Path().c_str(), 0) != UNZ_OK)
			throw File::Exc("file not found");

		{
			unz_file_info zipFileInfo;

			if(unzGetCurrentFileInfo(this->zipFile, &zipFileInfo, 0, 0, 0, 0, 0, 0) != UNZ_OK)
				throw File::Exc("failed obtaining file info");
		}

		if(unzOpenCurrentFile(this->zipFile) != UNZ_OK)
			throw File::Exc("file opening failed");

		//set open mode
		this->ioMode = mode;

		this->isOpened = true;//set "opened" flag
	}

	//override
	virtual void Close()throw(){
		if(!this->IsOpened())
			return;

		ASSERT(this->ZipFileIsOpened())

		if(unzCloseCurrentFile(this->zipFile) == UNZ_CRCERROR){
			TRACE(<< "[WARNING] ZipFile::Close(): CRC is not good" << std::endl)
		}

		this->isOpened = false;
	}

	//override
	virtual size_t ReadInternal(ting::Buffer<ting::u8>& buf){
		int numBytesRead = unzReadCurrentFile(this->zipFile, buf.Begin(), buf.Size());
		if(numBytesRead < 0){
			throw File::Exc("ZipFile::Read(): file reading failed");
		}

		ASSERT(numBytesRead >= 0)
		return size_t(numBytesRead);
	}

	//override
	//returns number of bytes actually written
	virtual size_t WriteInternal(const ting::Buffer<ting::u8>& buf){
		if(this->ioMode != WRITE){
			throw File::Exc("file is opened, but not in WRITE mode");
		}

		ASSERT_INFO(false, "writing is not supported for zip files")
	}

	//override
	virtual bool Exists()const{
		if(this->Path().size() == 0)
			return false;

		if(this->IsOpened())
			return true;

		//if it is a directory, check directory existance
		if(this->Path()[this->Path().size() - 1] == '/'){
			ASSERT(false)
		}else{
			return unzLocateFile(this->zipFile, this->Path().c_str(), 0) == UNZ_OK;
		}
	}

	//override
	virtual ting::Array<std::string> ListDirContents(size_t maxEntries = 0){
		if(!this->IsDir())
			throw File::Exc("ZipFile::ListDirContents(): this is not a directory");

		//if path refers to directory then there should be no files opened
		ASSERT(!this->IsOpened())

		if(!this->zipFile)
			throw File::Exc("ZipFile::ListDirContents(): zip file is not opened");

		std::vector<std::string> files;

		//for every file, check if it is in the current directory
		{
			//move to first file
			int ret = unzGoToFirstFile(this->zipFile);

			if(ret != UNZ_OK)
				throw File::Exc("ZipFile::ListDirContents(): unzGoToFirstFile() failed.");

			do{
				ting::StaticBuffer<char, 255> fileNameBuf;

				if(unzGetCurrentFileInfo(
						this->zipFile,
						NULL,
						fileNameBuf.Begin(),
						fileNameBuf.Size(),
						NULL,
						0,
						NULL,
						0
					) != UNZ_OK)
				{
					throw File::Exc("ZipFile::ListDirContents(): unzGetCurrentFileInfo() failed.");
				}

				fileNameBuf[fileNameBuf.Size() - 1] = 0;//null-terminate, just to be on a safe side

				std::string fn(fileNameBuf.Begin());//filename

				if(fn.size() <= this->Path().size())
					continue;

				//check if full file path starts with the this->Path() string
				if(fn.compare(0, this->Path().size(), this->Path()) != 0)
					continue;

				ASSERT(fn.size() > this->Path().size())
				std::string subfn(fn, this->Path().size(), fn.size() - this->Path().size());//subfilename

				size_t slashPos = subfn.find_first_of('/');

				//check if file is listed
				if(slashPos == std::string::npos){
					files.push_back(subfn);
					continue;
				}

				//if we get here then we need to add a directory
				ASSERT(subfn.size() >= slashPos + 1)
				files.push_back(
						std::string(subfn, 0, slashPos + 1)
					);

				if(files.size() == maxEntries){
					break;
				}
			}while((ret = unzGoToNextFile(this->zipFile)) == UNZ_OK);

			if(ret != UNZ_END_OF_LIST_OF_FILE && ret != UNZ_OK){
				throw File::Exc("ZipFile::ListDirContents(): unzGoToNextFile() failed.");
			}
		}

		ting::Array<std::string> filesArray(files.size());
		for(unsigned i = 0; i < files.size(); ++i)
			filesArray[i] = files[i];

		return filesArray;
	}
};

<commit_msg>curly braces for one line ifs<commit_after>/* The MIT License:

Copyright (c) 2009-2011 Ivan Gagis

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. */

/**
 * @file Zip file reader
 * @author Ivan Gagis <igagis@gmail.com>
 */

#pragma once

#include <unzip/unzip.h>

#include <ting/debug.hpp>
#include <ting/fs/File.hpp>

class ZipFile : public ting::fs::File{
	std::string zipFilePath;

	unzFile zipFile; //ZIP file handle (unzFile is actually a pointer)
public:
	//TODO: should accept ting::File from where to read the zip file data
	ZipFile(const std::string& pathToZipFile = std::string(), const std::string& path = std::string()) :
			File(path),
			zipFilePath(pathToZipFile.c_str()),//copy
			zipFile(0)
	{}

	~ZipFile()throw(){
		this->CloseZipFile();
	}

	void OpenZipFile(){
		if(this->ZipFileIsOpened()){
			throw File::Exc("ZipFile::OpenZipFile(): zip file is already opened");
		}

		ASSERT(!this->IsOpened())

		if(this->zipFilePath.size() == 0){
			throw File::Exc("ZipFile::OpenZipFile(): zip file path is not set");
		}

		this->zipFile = unzOpen(this->zipFilePath.c_str());

		if(!this->zipFile){
			throw File::Exc("ZipFile::OpenZipFile(): opening zip file failed");
		}
	}

	void CloseZipFile()throw(){
		if(!this->ZipFileIsOpened()){
			return;
		}

		//make sure there is no file opened inside zip file
		this->Close();

		if(unzClose(this->zipFile) != UNZ_OK){
			ASSERT(false)
		}

		this->zipFile = 0;
	}

	inline bool ZipFileIsOpened()const throw(){
		return this->zipFile != 0;
	}

	inline void SetZipFilePath(const std::string &path){
		if(this->ZipFileIsOpened()){
			throw File::Exc("ZipFile::SetZipFilePath(): cannot set zip file path while the zip file is opened");
		}
		this->zipFilePath = std::string(path.c_str());//immediate copy (we do not want copy-on-write)
	}

	inline std::string GetZipFilePath()const{
		return this->zipFilePath;
	}

	//override
	virtual void Open(EMode mode){
		if(!this->ZipFileIsOpened()){
			throw File::Exc("ZipFile::Open(): zip file is not opened");
		}

		if(this->IsOpened()){
			throw File::Exc("file already opened");
		}

		if(mode != File::READ){
			throw File::Exc("illegal mode requested, only READ supported inside ZIP file");
		}

		if(unzLocateFile(this->zipFile, this->Path().c_str(), 0) != UNZ_OK){
			throw File::Exc("file not found");
		}

		{
			unz_file_info zipFileInfo;

			if(unzGetCurrentFileInfo(this->zipFile, &zipFileInfo, 0, 0, 0, 0, 0, 0) != UNZ_OK)
				throw File::Exc("failed obtaining file info");
		}

		if(unzOpenCurrentFile(this->zipFile) != UNZ_OK){
			throw File::Exc("file opening failed");
		}

		//set open mode
		this->ioMode = mode;

		this->isOpened = true;//set "opened" flag
	}

	//override
	virtual void Close()throw(){
		if(!this->IsOpened()){
			return;
		}

		ASSERT(this->ZipFileIsOpened())

		if(unzCloseCurrentFile(this->zipFile) == UNZ_CRCERROR){
			TRACE(<< "[WARNING] ZipFile::Close(): CRC is not good" << std::endl)
		}

		this->isOpened = false;
	}

	//override
	virtual size_t ReadInternal(ting::Buffer<ting::u8>& buf){
		int numBytesRead = unzReadCurrentFile(this->zipFile, buf.Begin(), buf.Size());
		if(numBytesRead < 0){
			throw File::Exc("ZipFile::Read(): file reading failed");
		}

		ASSERT(numBytesRead >= 0)
		return size_t(numBytesRead);
	}

	//override
	//returns number of bytes actually written
	virtual size_t WriteInternal(const ting::Buffer<ting::u8>& buf){
		if(this->ioMode != WRITE){
			throw File::Exc("file is opened, but not in WRITE mode");
		}

		ASSERT_INFO(false, "writing is not supported for zip files")
	}

	//override
	virtual bool Exists()const{
		if(this->Path().size() == 0){
			return false;
		}

		if(this->IsOpened()){
			return true;
		}

		//if it is a directory, check directory existance
		if(this->Path()[this->Path().size() - 1] == '/'){
			ASSERT(false)
		}else{
			return unzLocateFile(this->zipFile, this->Path().c_str(), 0) == UNZ_OK;
		}
	}

	//override
	virtual ting::Array<std::string> ListDirContents(size_t maxEntries = 0){
		if(!this->IsDir()){
			throw File::Exc("ZipFile::ListDirContents(): this is not a directory");
		}

		//if path refers to directory then there should be no files opened
		ASSERT(!this->IsOpened())

		if(!this->zipFile){
			throw File::Exc("ZipFile::ListDirContents(): zip file is not opened");
		}

		std::vector<std::string> files;

		//for every file, check if it is in the current directory
		{
			//move to first file
			int ret = unzGoToFirstFile(this->zipFile);

			if(ret != UNZ_OK){
				throw File::Exc("ZipFile::ListDirContents(): unzGoToFirstFile() failed.");
			}

			do{
				ting::StaticBuffer<char, 255> fileNameBuf;

				if(unzGetCurrentFileInfo(
						this->zipFile,
						NULL,
						fileNameBuf.Begin(),
						fileNameBuf.Size(),
						NULL,
						0,
						NULL,
						0
					) != UNZ_OK)
				{
					throw File::Exc("ZipFile::ListDirContents(): unzGetCurrentFileInfo() failed.");
				}

				fileNameBuf[fileNameBuf.Size() - 1] = 0;//null-terminate, just to be on a safe side

				std::string fn(fileNameBuf.Begin());//filename

				if(fn.size() <= this->Path().size()){
					continue;
				}

				//check if full file path starts with the this->Path() string
				if(fn.compare(0, this->Path().size(), this->Path()) != 0){
					continue;
				}

				ASSERT(fn.size() > this->Path().size())
				std::string subfn(fn, this->Path().size(), fn.size() - this->Path().size());//subfilename

				size_t slashPos = subfn.find_first_of('/');

				//check if file is listed
				if(slashPos == std::string::npos){
					files.push_back(subfn);
					continue;
				}

				//if we get here then we need to add a directory
				ASSERT(subfn.size() >= slashPos + 1)
				files.push_back(
						std::string(subfn, 0, slashPos + 1)
					);

				if(files.size() == maxEntries){
					break;
				}
			}while((ret = unzGoToNextFile(this->zipFile)) == UNZ_OK);

			if(ret != UNZ_END_OF_LIST_OF_FILE && ret != UNZ_OK){
				throw File::Exc("ZipFile::ListDirContents(): unzGoToNextFile() failed.");
			}
		}

		ting::Array<std::string> filesArray(files.size());
		for(unsigned i = 0; i < files.size(); ++i){
			filesArray[i] = files[i];
		}

		return filesArray;
	}
};

<|endoftext|>


<commit_before>#include <fstream>
#include <iostream>
#include <string>
#include <cstring>
#include <vector>

#include "mugen_item_content.h"
#include "mugen_section.h"
#include "mugen_reader.h"
#include "globals.h"

// Check for Clsn
static bool checkClsn( const std::string &clsn ){
  return ( clsn.find("Clsn") != std::string::npos );
}

MugenReader::MugenReader( const char * file ){
    Global::debug(1) << "[mugen reader] Opening file '" << file << "'" << endl;
    ifile.open( file );
    myfile = string( file );
}

MugenReader::MugenReader( const string & file ){
    Global::debug(1) << "[mugen reader] Opening file '" << file << "'" << endl;
    ifile.open( file.c_str() );
    myfile = file;
}

MugenReader::~MugenReader(){
    ifile.close();

    for( std::vector< MugenSection * >::iterator i = collection.begin() ; i != collection.end() ; ++i ){
        delete (*i);
    }

}

const std::vector< MugenSection * > & MugenReader::getCollection() throw(MugenException){

  if ( !ifile ){
      perror("cant open file");
      throw MugenException( std::string("Could not open file: ") + myfile );
  }

  std::string line;

  const char openbracket = '[';
  const char closebracket = ']';
  const char comment = ';';
  const char seperator = ',';
  const char colon = ':';
  const char equal = '=';
  const char quote = '"';
  const char * ignored = "\r\n";

  SearchState state = Section;
  // Our section and items
  MugenSection * sectionHolder = 0;
  // Marker for areas
  bool beginSection = false;

  while( !ifile.eof() ){
      getline( ifile, line );
      // Use to hold section or content in the options
      std::string contentHolder = "";
      // Place holder to put back all the grabbed content
      MugenItemContent *itemHolder = new MugenItemContent();
      // Needed to kill loop
      bool breakLoop = false;
      bool inQuote = false;
      bool getExpression = false;

      for( unsigned int i = 0; i < line.size(); ++i ){
	    // Go to work
	    switch( state ){
	      case Section:{
		// Done with this
		if( line[i] == comment ){
		  breakLoop = true;
		  break;
		}
		else if ( line[i] == ' ' && !beginSection )continue;
		//Start grabbing our section
		else if( line[i] == openbracket){
		  beginSection = true;
		}
		//End of our section store and go to ContentGet
		else if( line[i] == closebracket){
		  sectionHolder = new MugenSection();
		  sectionHolder->setHeader( contentHolder );
		  state = ContentGet;
		  beginSection = false;
		  breakLoop = true;
		  break;
		}
		else if( beginSection )contentHolder += line[i];
	      }
	      break;
	      case ContentGet:
	      default:{
		// Done with this
		if( line[i] == comment ){
		  if( itemHolder->hasItems() ){
		    if( !contentHolder.empty() ){
		      *itemHolder << contentHolder;
		    }
		    *sectionHolder << itemHolder;
		  }
		  breakLoop = true;
		  break;
		}
		// Check if we are near the end to kill it
		if( i+1 == line.size() && !contentHolder.empty() ){
		    if (line[i] != ' ' && !strchr(ignored, line[i])){
                        contentHolder += line[i];
                    }
		    *itemHolder << contentHolder;
		    *sectionHolder << itemHolder;
		    breakLoop = true;
		    break;
		}
		// Buh bye spaces
		if( line[i] == ' ' && !inQuote ){
		  continue;
		}
		// Start getting expression
		if( line[i] != ' ' && getExpression ){
		  inQuote = true;
		}
		// Check if this section is done, push it on the stack and reset everything
		if( line[i] == openbracket && !checkClsn( contentHolder ) && !itemHolder->hasItems() ){
		  if( sectionHolder->hasItems() )addSection( sectionHolder );
		  beginSection = true;
		  state = Section;
		  contentHolder = "";
		  break;
		}
		// We got one push back the other and reset the holder to get the next
		else if( line[i] == colon || line[i] == seperator ){
		  if( !contentHolder.empty() ) *itemHolder << contentHolder;
		  contentHolder = "";
		}
		// Equal
		else if(line[i] == equal && !inQuote ){
		  if( !contentHolder.empty() ) *itemHolder << contentHolder;
		  getExpression = true;
		  contentHolder = "";
		}
		// We has a quote begin or end it
		else if( line[i] == quote ){
		  inQuote = !inQuote;
		}
		//Start grabbing our item
		else if (! strchr(ignored, line[i])){
                    contentHolder += line[i];
                }
	      }
	      break;
	    }
	    if( breakLoop )break;
      }
  }
  // Add in last section
  if( sectionHolder->hasItems() )addSection( sectionHolder );

  return collection;
}

void MugenReader::addSection( MugenSection * section ){
  collection.push_back ( section );
}

<commit_msg>move perror<commit_after>#include <fstream>
#include <iostream>
#include <string>
#include <cstring>
#include <vector>

#include "mugen_item_content.h"
#include "mugen_section.h"
#include "mugen_reader.h"
#include "globals.h"

// Check for Clsn
static bool checkClsn( const std::string &clsn ){
  return ( clsn.find("Clsn") != std::string::npos );
}

MugenReader::MugenReader( const char * file ){
    Global::debug(1) << "[mugen reader] Opening file '" << file << "'" << endl;
    ifile.open( file );
    if (!ifile){
        perror("cant open file");
    }
    myfile = string( file );
}

MugenReader::MugenReader( const string & file ){
    Global::debug(1) << "[mugen reader] Opening file '" << file << "'" << endl;
    ifile.open( file.c_str() );
    if (!ifile){
        perror("cant open file");
    }
    myfile = file;
}

MugenReader::~MugenReader(){
    ifile.close();

    for( std::vector< MugenSection * >::iterator i = collection.begin() ; i != collection.end() ; ++i ){
        delete (*i);
    }

}

const std::vector< MugenSection * > & MugenReader::getCollection() throw(MugenException){

  if ( !ifile ){
      throw MugenException( std::string("Could not open file: ") + myfile );
  }

  std::string line;

  const char openbracket = '[';
  const char closebracket = ']';
  const char comment = ';';
  const char seperator = ',';
  const char colon = ':';
  const char equal = '=';
  const char quote = '"';
  const char * ignored = "\r\n";

  SearchState state = Section;
  // Our section and items
  MugenSection * sectionHolder = 0;
  // Marker for areas
  bool beginSection = false;

  while( !ifile.eof() ){
      getline( ifile, line );
      // Use to hold section or content in the options
      std::string contentHolder = "";
      // Place holder to put back all the grabbed content
      MugenItemContent *itemHolder = new MugenItemContent();
      // Needed to kill loop
      bool breakLoop = false;
      bool inQuote = false;
      bool getExpression = false;

      for( unsigned int i = 0; i < line.size(); ++i ){
	    // Go to work
	    switch( state ){
	      case Section:{
		// Done with this
		if( line[i] == comment ){
		  breakLoop = true;
		  break;
		}
		else if ( line[i] == ' ' && !beginSection )continue;
		//Start grabbing our section
		else if( line[i] == openbracket){
		  beginSection = true;
		}
		//End of our section store and go to ContentGet
		else if( line[i] == closebracket){
		  sectionHolder = new MugenSection();
		  sectionHolder->setHeader( contentHolder );
		  state = ContentGet;
		  beginSection = false;
		  breakLoop = true;
		  break;
		}
		else if( beginSection )contentHolder += line[i];
	      }
	      break;
	      case ContentGet:
	      default:{
		// Done with this
		if( line[i] == comment ){
		  if( itemHolder->hasItems() ){
		    if( !contentHolder.empty() ){
		      *itemHolder << contentHolder;
		    }
		    *sectionHolder << itemHolder;
		  }
		  breakLoop = true;
		  break;
		}
		// Check if we are near the end to kill it
		if( i+1 == line.size() && !contentHolder.empty() ){
		    if (line[i] != ' ' && !strchr(ignored, line[i])){
                        contentHolder += line[i];
                    }
		    *itemHolder << contentHolder;
		    *sectionHolder << itemHolder;
		    breakLoop = true;
		    break;
		}
		// Buh bye spaces
		if( line[i] == ' ' && !inQuote ){
		  continue;
		}
		// Start getting expression
		if( line[i] != ' ' && getExpression ){
		  inQuote = true;
		}
		// Check if this section is done, push it on the stack and reset everything
		if( line[i] == openbracket && !checkClsn( contentHolder ) && !itemHolder->hasItems() ){
		  if( sectionHolder->hasItems() )addSection( sectionHolder );
		  beginSection = true;
		  state = Section;
		  contentHolder = "";
		  break;
		}
		// We got one push back the other and reset the holder to get the next
		else if( line[i] == colon || line[i] == seperator ){
		  if( !contentHolder.empty() ) *itemHolder << contentHolder;
		  contentHolder = "";
		}
		// Equal
		else if(line[i] == equal && !inQuote ){
		  if( !contentHolder.empty() ) *itemHolder << contentHolder;
		  getExpression = true;
		  contentHolder = "";
		}
		// We has a quote begin or end it
		else if( line[i] == quote ){
		  inQuote = !inQuote;
		}
		//Start grabbing our item
		else if (! strchr(ignored, line[i])){
                    contentHolder += line[i];
                }
	      }
	      break;
	    }
	    if( breakLoop )break;
      }
  }
  // Add in last section
  if( sectionHolder->hasItems() )addSection( sectionHolder );

  return collection;
}

void MugenReader::addSection( MugenSection * section ){
  collection.push_back ( section );
}

<|endoftext|>