<commit_before>// Copyright (C) 2015 - 2016 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., University of Heidelberg, and The University
// of Manchester.
// All rights reserved.

#include <math.h>
#include <string.h>
//#include <algorithm>

#include "copasi/utilities/CUnitDefinition.h"
//#include "copasi/utilities/CUnitParser.h"
#include "copasi/report/CKeyFactory.h"
#include "copasi/report/CCopasiRootContainer.h"
//#include "copasi/model/CModel.h"
#include "copasi/xml/CCopasiXMLInterface.h"

//#include "CCopasiException.h"

// SI Name, Symbol, Definition
struct SIUnit
{
  const char * name;
  const char * symbol;
  const char * expression;
};

SIUnit SIUnits[] =
{
  //SI base
  {"meter",      "m",        "m"},
  {"gram",       "g",        "g"},
  {"second",     "s",        "s"},
  {"ampere",     "A",        "A"},
  {"kelvin",     "K",        "K"},
  {"mole",      "mol",      "mol"},
  {"candela",   "cd",       "cd"},

  //SI derived
  {"becquerel",  "Bq",       "s^-1"},
  {"coulomb",    "C",        "s*A"},
  {"farad",      "F",        "m^-2*kg^-1*s^4*A^2"},
  {"gray",       "Gy",       "m^2*s^-2"},
  {"henry",      "H",        "m^2*kg*s^-2*A^-2"},
  {"hertz",      "Hz",       "s^-1"},
  {"joule",      "J",        "m^2*kg*s^-2"},
  {"katal",      "kat",      "s^-1*mol"},
  {"liter",      "l",        "0.001*m^3"},
  {"lumen",      "lm",       "cd"},
  {"lux",        "lx",       "m^-2*cd"},
  {"mole",       "mol",      "Avogadro*#"},
  {"newton",     "N",        "m*kg*s^-2"},
  {"ohm",        "\xCE\xA9", "m^2*kg*s^-3*A^-2"},
  {"pascal",     "Pa",       "m^-1*kg*s^-2"},
  {"siemens",    "S",        "m^-2*kg^-1*s^3*A^2"},
  {"sievert",    "Sv",       "m^2*s^-2"},
  {"tesla",      "T",        "kg*s^-2*A^-1"},
  {"volt",       "V",        "m^2*kg*s^-3*A^-1"},
  {"watt",       "W",        "m^2*kg*s^-3"},
  {"weber",      "Wb",       "m^2*kg*s^-2*A^-1"},

  {"dimensionless", "1",      "1"},
  {"item",       "#",        "#"},
  {"minute",     "min",      "60*s"},
  {"hour",       "h",        "3600*s"},
  {"day",        "d",        "86400*s"},

  // This must be the last element of the SI unit list! Do not delete!
  {NULL,         NULL,        NULL}
};

// static

CUnit CUnitDefinition::getSIUnit(const std::string & symbol,
                                 const C_FLOAT64 & avogadro)
{
  SIUnit * pSIUnit = SIUnits;

  while (pSIUnit->name && strcmp(pSIUnit->symbol, symbol.c_str()) != 0)
    ++pSIUnit;

  if (!pSIUnit->name)
    fatalError();

  std::ostringstream buffer;

  if (strcmp(pSIUnit->symbol, "mol"))
    {
      buffer << pSIUnit->expression;
    }
  else
    {
      buffer << CCopasiXMLInterface::DBL(avogadro) << "*#";
    }

  CUnit SIunit = CUnit();
  SIunit.setExpression(buffer.str(), avogadro);

  return SIunit;
}

// static
void CUnitDefinition::updateSIUnitDefinitions(CUnitDefinitionDB * Units,
    const C_FLOAT64 & avogadro)
{
  SIUnit * pSIUnit = SIUnits;

  while (pSIUnit->name)
    {
      CUnitDefinition * pUnitDef = NULL;
      size_t Index = Units->getIndex(pSIUnit->name);

      if (Index != C_INVALID_INDEX)
        {
          pUnitDef = Units->operator [](Index);
        }
      else
        {
          pUnitDef = new CUnitDefinition(pSIUnit->name, Units);
          pUnitDef->setSymbol(pSIUnit->symbol);
        }

      std::ostringstream buffer;

      if (strcmp(pSIUnit->symbol, "mol"))
        {
          buffer << pSIUnit->expression;
        }
      else
        {
          buffer << CCopasiXMLInterface::DBL(avogadro) << "*#";
        }

      pUnitDef->setExpression(buffer.str(), avogadro);

      pSIUnit++;
    }
}

// constructors
// default
CUnitDefinition::CUnitDefinition(const std::string & name,
                                 const CCopasiContainer * pParent):
  CCopasiContainer(name, pParent, "Unit"),
  CUnit(),
  CAnnotation(),
  mSymbol("symbol")
{
  setup();
}

// kind
CUnitDefinition::CUnitDefinition(const CBaseUnit::Kind & kind,
                                 const CCopasiContainer * pParent):
  CCopasiContainer(CBaseUnit::Name[kind], pParent, "Unit"),
  CUnit(kind),
  CAnnotation(),
  mSymbol(CBaseUnit::getSymbol(kind))
{
  setup();
}

// copy
CUnitDefinition::CUnitDefinition(const CUnitDefinition &src,
                                 const C_FLOAT64 & avogadro,
                                 const CCopasiContainer * pParent):
  CCopasiContainer(src, pParent),
  CUnit(src, avogadro),
  CAnnotation(src),
  mSymbol(src.mSymbol)
{
  setup();
}

CUnitDefinition::~CUnitDefinition()
{
  CCopasiRootContainer::getKeyFactory()->remove(mKey);

  CCopasiContainer * pParent = getObjectParent();

  if (pParent != NULL)
    {
      pParent->remove(this);
    }
}

void CUnitDefinition::setup()
{
  CCopasiContainer * pParent = getObjectParent();

  if (pParent != NULL)
    {
      pParent->add(this, true);
    }

  mKey = CCopasiRootContainer::getKeyFactory()->add("Unit", this);

  // The following ought to trigger the exception for
  // a symbol already in the CUnitDefinitionDB
  std::ostringstream Symbol;

  Symbol.str(mSymbol.c_str());
  int i = 1;

  while (!setSymbol(Symbol.str()))
    {
      Symbol.str("");
      Symbol << mSymbol << "_" << i++;
    }
}

// virtual
const std::string & CUnitDefinition::getKey() const
{
  return CAnnotation::getKey();
}

bool CUnitDefinition::setSymbol(const std::string & symbol)
{
  CUnitDefinitionDB * pUnitDefinitionDB = dynamic_cast < CUnitDefinitionDB * >(getObjectParent());

  if (pUnitDefinitionDB == NULL ||
      pUnitDefinitionDB->changeSymbol(this, symbol))
    {
      mSymbol = symbol;

      return true;
    }

  CCopasiMessage(CCopasiMessage::ERROR, MCUnitDefinition + 2, symbol.c_str());

  return false;
}

const std::string & CUnitDefinition::getSymbol() const
{
  return mSymbol;
}

CUnitDefinition & CUnitDefinition::operator=(const CUnitDefinition & src)
{
   if (this == &src) return *this;

  // All CUnitDefinition symbols in a CUnitDefinitionDB should be unique
  // This should protect that for cases like this:
  // *aCunitDefDB[i] = someCunitDef;

   CUnitDefinitionDB * pDB =
       dynamic_cast < CUnitDefinitionDB * >(getObjectParent());

     if (pDB != NULL &&
         pDB->containsSymbol(src.getSymbol()) &&
         pDB->getIndex(src.getObjectName()) != C_INVALID_INDEX)
       CCopasiMessage ex(CCopasiMessage::EXCEPTION, MCUnitDefinition + 2);

  *this = src;

  return *this;
}

//static
bool CUnitDefinition::isBuiltinUnitSymbol(std::string symbol)
{
  SIUnit * pSIUnit = SIUnits;

  while (pSIUnit->symbol && strcmp(pSIUnit->symbol, symbol.c_str()) != 0)
    ++pSIUnit;

  return (pSIUnit->symbol != NULL);
}

bool CUnitDefinition::isReadOnly() const
{
  SIUnit * pSIUnit = SIUnits;

  while (pSIUnit->name && getObjectName() != pSIUnit->name)
    ++pSIUnit;

  return (pSIUnit->name != NULL);
}
<commit_msg>Finally fixed the CUnitDefinition assignment operator.<commit_after>// Copyright (C) 2015 - 2016 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., University of Heidelberg, and The University
// of Manchester.
// All rights reserved.

#include <math.h>
#include <string.h>
//#include <algorithm>

#include "copasi/utilities/CUnitDefinition.h"
//#include "copasi/utilities/CUnitParser.h"
#include "copasi/report/CKeyFactory.h"
#include "copasi/report/CCopasiRootContainer.h"
//#include "copasi/model/CModel.h"
#include "copasi/xml/CCopasiXMLInterface.h"

//#include "CCopasiException.h"

// SI Name, Symbol, Definition
struct SIUnit
{
  const char * name;
  const char * symbol;
  const char * expression;
};

SIUnit SIUnits[] =
{
  //SI base
  {"meter",      "m",        "m"},
  {"gram",       "g",        "g"},
  {"second",     "s",        "s"},
  {"ampere",     "A",        "A"},
  {"kelvin",     "K",        "K"},
  {"mole",      "mol",      "mol"},
  {"candela",   "cd",       "cd"},

  //SI derived
  {"becquerel",  "Bq",       "s^-1"},
  {"coulomb",    "C",        "s*A"},
  {"farad",      "F",        "m^-2*kg^-1*s^4*A^2"},
  {"gray",       "Gy",       "m^2*s^-2"},
  {"henry",      "H",        "m^2*kg*s^-2*A^-2"},
  {"hertz",      "Hz",       "s^-1"},
  {"joule",      "J",        "m^2*kg*s^-2"},
  {"katal",      "kat",      "s^-1*mol"},
  {"liter",      "l",        "0.001*m^3"},
  {"lumen",      "lm",       "cd"},
  {"lux",        "lx",       "m^-2*cd"},
  {"mole",       "mol",      "Avogadro*#"},
  {"newton",     "N",        "m*kg*s^-2"},
  {"ohm",        "\xCE\xA9", "m^2*kg*s^-3*A^-2"},
  {"pascal",     "Pa",       "m^-1*kg*s^-2"},
  {"siemens",    "S",        "m^-2*kg^-1*s^3*A^2"},
  {"sievert",    "Sv",       "m^2*s^-2"},
  {"tesla",      "T",        "kg*s^-2*A^-1"},
  {"volt",       "V",        "m^2*kg*s^-3*A^-1"},
  {"watt",       "W",        "m^2*kg*s^-3"},
  {"weber",      "Wb",       "m^2*kg*s^-2*A^-1"},

  {"dimensionless", "1",      "1"},
  {"item",       "#",        "#"},
  {"minute",     "min",      "60*s"},
  {"hour",       "h",        "3600*s"},
  {"day",        "d",        "86400*s"},

  // This must be the last element of the SI unit list! Do not delete!
  {NULL,         NULL,        NULL}
};

// static

CUnit CUnitDefinition::getSIUnit(const std::string & symbol,
                                 const C_FLOAT64 & avogadro)
{
  SIUnit * pSIUnit = SIUnits;

  while (pSIUnit->name && strcmp(pSIUnit->symbol, symbol.c_str()) != 0)
    ++pSIUnit;

  if (!pSIUnit->name)
    fatalError();

  std::ostringstream buffer;

  if (strcmp(pSIUnit->symbol, "mol"))
    {
      buffer << pSIUnit->expression;
    }
  else
    {
      buffer << CCopasiXMLInterface::DBL(avogadro) << "*#";
    }

  CUnit SIunit = CUnit();
  SIunit.setExpression(buffer.str(), avogadro);

  return SIunit;
}

// static
void CUnitDefinition::updateSIUnitDefinitions(CUnitDefinitionDB * Units,
    const C_FLOAT64 & avogadro)
{
  SIUnit * pSIUnit = SIUnits;

  while (pSIUnit->name)
    {
      CUnitDefinition * pUnitDef = NULL;
      size_t Index = Units->getIndex(pSIUnit->name);

      if (Index != C_INVALID_INDEX)
        {
          pUnitDef = Units->operator [](Index);
        }
      else
        {
          pUnitDef = new CUnitDefinition(pSIUnit->name, Units);
          pUnitDef->setSymbol(pSIUnit->symbol);
        }

      std::ostringstream buffer;

      if (strcmp(pSIUnit->symbol, "mol"))
        {
          buffer << pSIUnit->expression;
        }
      else
        {
          buffer << CCopasiXMLInterface::DBL(avogadro) << "*#";
        }

      pUnitDef->setExpression(buffer.str(), avogadro);

      pSIUnit++;
    }
}

// constructors
// default
CUnitDefinition::CUnitDefinition(const std::string & name,
                                 const CCopasiContainer * pParent):
  CCopasiContainer(name, pParent, "Unit"),
  CUnit(),
  CAnnotation(),
  mSymbol("symbol")
{
  setup();
}

// kind
CUnitDefinition::CUnitDefinition(const CBaseUnit::Kind & kind,
                                 const CCopasiContainer * pParent):
  CCopasiContainer(CBaseUnit::Name[kind], pParent, "Unit"),
  CUnit(kind),
  CAnnotation(),
  mSymbol(CBaseUnit::getSymbol(kind))
{
  setup();
}

// copy
CUnitDefinition::CUnitDefinition(const CUnitDefinition &src,
                                 const C_FLOAT64 & avogadro,
                                 const CCopasiContainer * pParent):
  CCopasiContainer(src, pParent),
  CUnit(src, avogadro),
  CAnnotation(src),
  mSymbol(src.mSymbol)
{
  setup();
}

CUnitDefinition::~CUnitDefinition()
{
  CCopasiRootContainer::getKeyFactory()->remove(mKey);

  CCopasiContainer * pParent = getObjectParent();

  if (pParent != NULL)
    {
      pParent->remove(this);
    }
}

void CUnitDefinition::setup()
{
  CCopasiContainer * pParent = getObjectParent();

  if (pParent != NULL)
    {
      pParent->add(this, true);
    }

  mKey = CCopasiRootContainer::getKeyFactory()->add("Unit", this);

  // The following ought to trigger the exception for
  // a symbol already in the CUnitDefinitionDB
  std::ostringstream Symbol;

  Symbol.str(mSymbol.c_str());
  int i = 1;

  while (!setSymbol(Symbol.str()))
    {
      Symbol.str("");
      Symbol << mSymbol << "_" << i++;
    }
}

// virtual
const std::string & CUnitDefinition::getKey() const
{
  return CAnnotation::getKey();
}

bool CUnitDefinition::setSymbol(const std::string & symbol)
{
  CUnitDefinitionDB * pUnitDefinitionDB = dynamic_cast < CUnitDefinitionDB * >(getObjectParent());

  if (pUnitDefinitionDB == NULL ||
      pUnitDefinitionDB->changeSymbol(this, symbol))
    {
      mSymbol = symbol;

      return true;
    }

  CCopasiMessage(CCopasiMessage::ERROR, MCUnitDefinition + 2, symbol.c_str());

  return false;
}

const std::string & CUnitDefinition::getSymbol() const
{
  return mSymbol;
}

CUnitDefinition & CUnitDefinition::operator=(const CUnitDefinition & src)
{
  if (this == &src) return *this;

  // All CUnitDefinition symbols in a CUnitDefinitionDB should be unique
  // This should protect that for cases like this:
  // *aCunitDefDB[i] = someCunitDef;

  CUnitDefinitionDB * pDB = dynamic_cast < CUnitDefinitionDB * >(getObjectParent());

  if (pDB != NULL &&
      pDB->containsSymbol(src.getSymbol()) &&
      pDB->getIndex(src.getObjectName()) != C_INVALID_INDEX)
    CCopasiMessage ex(CCopasiMessage::EXCEPTION, MCUnitDefinition + 2);

  CUnit::operator = (src);

  setObjectName(src.getObjectName());
  setSymbol(src.mSymbol);

  return *this;
}

//static
bool CUnitDefinition::isBuiltinUnitSymbol(std::string symbol)
{
  SIUnit * pSIUnit = SIUnits;

  while (pSIUnit->symbol && strcmp(pSIUnit->symbol, symbol.c_str()) != 0)
    ++pSIUnit;

  return (pSIUnit->symbol != NULL);
}

bool CUnitDefinition::isReadOnly() const
{
  SIUnit * pSIUnit = SIUnits;

  while (pSIUnit->name && getObjectName() != pSIUnit->name)
    ++pSIUnit;

  return (pSIUnit->name != NULL);
}
<|endoftext|>


<commit_before>#include "BasicTest.hpp"
#include "../Register.hpp"

#include <boost/static_assert.hpp>

#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>

#include <boost/archive/xml_iarchive.hpp>
#include <boost/archive/xml_oarchive.hpp>

CPPUNIT_TEST_SUITE_REGISTRATION(BasicTest);

class point
{
public:
  virtual void dummy() {};
  int x;
  int y;
};

class colored_point : public point
{
public:
  virtual void dummy() {};
  std::string color;
};

struct label
{
  std::string name;
  double value;
};

class line
{
private:
  point* _p1;
  point* _p2;

  template<class Archive>
  friend void siconos_io(Archive&, line&, const unsigned int);

public:
  line() {};
  line(point* a, point*b) : _p1(a), _p2(b) {};

  const point& p1() const
  {
    return *_p1;
  };
  const point& p2() const
  {
    return *_p2;
  };

  void setp1Ptr(point* v)
  {
    _p1 = v;
  };
  void setp2Ptr(point* v)
  {
    _p2 = v;
  };
};

BOOST_CLASS_EXPORT_GUID(point, "point")
BOOST_CLASS_EXPORT_GUID(colored_point, "colored_point")
SICONOS_IO_REGISTER(point, (x)(y));
SICONOS_IO_REGISTER_WITH_BASE(colored_point, point, (color));

SICONOS_IO_REGISTER(label, (name)(value))

SICONOS_IO_REGISTER(line, (_p1)(_p2));

void BasicTest::setUp() {};
void BasicTest::tearDown() {};

void BasicTest::t0()
{
  point p0;
  p0.x = 3.;
  p0.y = 4.;

  point p1;

  std::ostringstream os;
  {
    boost::archive::binary_oarchive oa(os);
    oa << BOOST_SERIALIZATION_NVP(p0);
  }
  std::istringstream is(os.str());
  {
    boost::archive::binary_iarchive ia(is);
    ia >> BOOST_SERIALIZATION_NVP(p1);
  }

  CPPUNIT_ASSERT((p0.x == p1.x));
  CPPUNIT_ASSERT((p0.y == p1.y));

}

void BasicTest::t1()
{
  label l0 = { "l0", 1.0 };
  label l1;

  std::ofstream ofs("t1.xml");
  CPPUNIT_ASSERT(ofs.good());
  {
    boost::archive::xml_oarchive oa(ofs);
    boost::serialization::serialize(oa, l0, 0);
  }
  std::ifstream ifs("t1.xml");
  CPPUNIT_ASSERT(ifs.good());
  {
    boost::archive::xml_iarchive ia(ifs);
    boost::serialization::serialize(ia, l1, 0);
  }

  CPPUNIT_ASSERT((l0.name == l1.name));
  CPPUNIT_ASSERT((l0.value == l1.value));

}

void BasicTest::t2()
{

  colored_point p0, p1;
  p0.color = "red";
  p0.x = 10;
  p0.y = 99;

  std::ofstream ofs("t2.xml");
  CPPUNIT_ASSERT(ofs.good());
  {
    boost::archive::xml_oarchive oa(ofs);
    oa << boost::serialization::make_nvp("colored_point", p0);
  }
  std::ifstream ifs("t2.xml");
  CPPUNIT_ASSERT(ifs.good());
  {
    boost::archive::xml_iarchive ia(ifs);
    ia >> boost::serialization::make_nvp("colored_point", p1);
  }

  CPPUNIT_ASSERT((p0.color == p1.color));
  CPPUNIT_ASSERT((p0.x == p1.x));
  CPPUNIT_ASSERT((p0.y == p1.y));

}

void BasicTest::t3()
{

  point *p;

  point *pn;

  p = new colored_point();
  pn = new colored_point();

  p->x = 1.;
  p->y = 2.;
  static_cast<colored_point *>(p)->color = "red";

  std::ofstream ofs("t3.xml");
  CPPUNIT_ASSERT(ofs.good());
  {
    boost::archive::xml_oarchive oa(ofs);
    oa.register_type(static_cast<colored_point*>(NULL));
    oa << BOOST_SERIALIZATION_NVP(p);
  }

  std::ifstream ifs("t3.xml");
  CPPUNIT_ASSERT(ifs.good());
  {
    boost::archive::xml_iarchive ia(ifs);
    ia.register_type(static_cast<colored_point*>(NULL));
    ia >> BOOST_SERIALIZATION_NVP(pn);
  }

}

void BasicTest::t4()
{

  colored_point p;

  colored_point p1, p2;

  p1.x = 32.33444;
  p1.y = 45.34434;
  p2.x = 36.33443;
  p2.y = 34.34345;

  p1.color = "red";
  p2.color = "black";

  line l0(&p1, &p2);
  line l1(&p, &p);

  std::ofstream ofs("t4.xml");
  CPPUNIT_ASSERT(ofs.good());
  {
    boost::archive::xml_oarchive oa(ofs);
    boost::serialization::serialize(oa, l0, 0);
  }

  std::ifstream ifs("t4.xml");
  CPPUNIT_ASSERT(ifs.good());
  {
    boost::archive::xml_iarchive ia(ifs);
    boost::serialization::serialize(ia, l1, 0);
  }

  CPPUNIT_ASSERT((l0.p1().x == l1.p1().x));
  CPPUNIT_ASSERT((l0.p1().y == l1.p1().y));

  CPPUNIT_ASSERT((l0.p2().x == l1.p2().x));
  CPPUNIT_ASSERT((l0.p2().y == l1.p2().y));

  CPPUNIT_ASSERT((static_cast<const colored_point*>(&l0.p2())->color ==
                  static_cast<const colored_point*>(&l1.p2())->color));

}

class A
{
public:
  virtual void get() = 0;

  int labelA;
};

class B : public A
{
public:
  void get() { };
  int labelB;
};

SICONOS_IO_REGISTER(A, (labelA));
SICONOS_IO_REGISTER_WITH_BASE(B, A, (labelB));

void BasicTest::t5()
{

  B b, bl;
  b.labelA = 1;
  b.labelB = 2;

  std::ofstream ofs("t5.xml");
  CPPUNIT_ASSERT(ofs.good());
  {
    boost::archive::xml_oarchive oa(ofs);
    boost::serialization::serialize(oa, b, 0);
  }

  std::ifstream ifs("t5.xml");
  CPPUNIT_ASSERT(ifs.good());
  {
    boost::archive::xml_iarchive ia(ifs);
    boost::serialization::serialize(ia, bl, 0);
  }

  CPPUNIT_ASSERT((bl.labelA == b.labelA));
  CPPUNIT_ASSERT((bl.labelB == b.labelB));

}
<commit_msg>[io] try to fix tests<commit_after>#include "BasicTest.hpp"
#include "../Register.hpp"

#include <boost/static_assert.hpp>

#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>

#include <boost/archive/xml_iarchive.hpp>
#include <boost/archive/xml_oarchive.hpp>

CPPUNIT_TEST_SUITE_REGISTRATION(BasicTest);

class point
{
public:
  virtual void dummy() {};
  virtual ~point() {};
  int x;
  int y;
};

class colored_point : public point
{
public:
  virtual void dummy() {};
  virtual ~colored_point() {};
  std::string color;
};

struct label
{
  std::string name;
  double value;
};

class line
{
private:
  point* _p1;
  point* _p2;

  template<class Archive>
  friend void siconos_io(Archive&, line&, const unsigned int);

public:
  line() {};
  line(point* a, point*b) : _p1(a), _p2(b) {};

  const point& p1() const
  {
    return *_p1;
  };
  const point& p2() const
  {
    return *_p2;
  };

  void setp1Ptr(point* v)
  {
    _p1 = v;
  };
  void setp2Ptr(point* v)
  {
    _p2 = v;
  };
};

BOOST_CLASS_EXPORT_GUID(point, "point")
BOOST_CLASS_EXPORT_GUID(colored_point, "colored_point")
SICONOS_IO_REGISTER(point, (x)(y));
SICONOS_IO_REGISTER_WITH_BASE(colored_point, point, (color));

SICONOS_IO_REGISTER(label, (name)(value))

SICONOS_IO_REGISTER(line, (_p1)(_p2));

void BasicTest::setUp() {};
void BasicTest::tearDown() {};

void BasicTest::t0()
{
  point p0;
  p0.x = 3.;
  p0.y = 4.;

  point p1;

  std::ostringstream os;
  {
    boost::archive::binary_oarchive oa(os);
    oa << BOOST_SERIALIZATION_NVP(p0);
  }
  std::istringstream is(os.str());
  {
    boost::archive::binary_iarchive ia(is);
    ia >> BOOST_SERIALIZATION_NVP(p1);
  }

  CPPUNIT_ASSERT((p0.x == p1.x));
  CPPUNIT_ASSERT((p0.y == p1.y));

}

void BasicTest::t1()
{
  label l0 = { "l0", 1.0 };
  label l1;

  std::ofstream ofs("t1.xml");
  CPPUNIT_ASSERT(ofs.good());
  {
    boost::archive::xml_oarchive oa(ofs);
    boost::serialization::serialize(oa, l0, 0);
  }
  std::ifstream ifs("t1.xml");
  CPPUNIT_ASSERT(ifs.good());
  {
    boost::archive::xml_iarchive ia(ifs);
    boost::serialization::serialize(ia, l1, 0);
  }

  CPPUNIT_ASSERT((l0.name == l1.name));
  CPPUNIT_ASSERT((l0.value == l1.value));

}

void BasicTest::t2()
{

  colored_point p0, p1;
  p0.color = "red";
  p0.x = 10;
  p0.y = 99;

  std::ofstream ofs("t2.xml");
  CPPUNIT_ASSERT(ofs.good());
  {
    boost::archive::xml_oarchive oa(ofs);
    oa << boost::serialization::make_nvp("colored_point", p0);
  }
  std::ifstream ifs("t2.xml");
  CPPUNIT_ASSERT(ifs.good());
  {
    boost::archive::xml_iarchive ia(ifs);
    ia >> boost::serialization::make_nvp("colored_point", p1);
  }

  CPPUNIT_ASSERT((p0.color == p1.color));
  CPPUNIT_ASSERT((p0.x == p1.x));
  CPPUNIT_ASSERT((p0.y == p1.y));

}

void BasicTest::t3()
{

  point *p;

  point *pn;

  p = new colored_point();
  pn = new colored_point();

  p->x = 1.;
  p->y = 2.;
  static_cast<colored_point *>(p)->color = "red";

  std::ofstream ofs("t3.xml");
  CPPUNIT_ASSERT(ofs.good());
  {
    boost::archive::xml_oarchive oa(ofs);
    oa.register_type(static_cast<colored_point*>(NULL));
    oa << BOOST_SERIALIZATION_NVP(p);
  }

  std::ifstream ifs("t3.xml");
  CPPUNIT_ASSERT(ifs.good());
  {
    boost::archive::xml_iarchive ia(ifs);
    ia.register_type(static_cast<colored_point*>(NULL));
    ia >> BOOST_SERIALIZATION_NVP(pn);
  }

}

void BasicTest::t4()
{

  colored_point p;

  colored_point p1, p2;

  p1.x = 32.33444;
  p1.y = 45.34434;
  p2.x = 36.33443;
  p2.y = 34.34345;

  p1.color = "red";
  p2.color = "black";

  line l0(&p1, &p2);
  line l1(&p, &p);

  std::ofstream ofs("t4.xml");
  CPPUNIT_ASSERT(ofs.good());
  {
    boost::archive::xml_oarchive oa(ofs);
    boost::serialization::serialize(oa, l0, 0);
  }

  std::ifstream ifs("t4.xml");
  CPPUNIT_ASSERT(ifs.good());
  {
    boost::archive::xml_iarchive ia(ifs);
    boost::serialization::serialize(ia, l1, 0);
  }

  CPPUNIT_ASSERT((l0.p1().x == l1.p1().x));
  CPPUNIT_ASSERT((l0.p1().y == l1.p1().y));

  CPPUNIT_ASSERT((l0.p2().x == l1.p2().x));
  CPPUNIT_ASSERT((l0.p2().y == l1.p2().y));

  CPPUNIT_ASSERT((static_cast<const colored_point*>(&l0.p2())->color ==
                  static_cast<const colored_point*>(&l1.p2())->color));

}

class A
{
public:
  virtual void get() = 0;
  virtual ~A() {};

  int labelA;
};

class B : public A
{
public:
  void get() { };
  int labelB;
  virtual ~B() {};
};

SICONOS_IO_REGISTER(A, (labelA));
SICONOS_IO_REGISTER_WITH_BASE(B, A, (labelB));

void BasicTest::t5()
{

  B b, bl;
  b.labelA = 1;
  b.labelB = 2;

  std::ofstream ofs("t5.xml");
  CPPUNIT_ASSERT(ofs.good());
  {
    boost::archive::xml_oarchive oa(ofs);
    boost::serialization::serialize(oa, b, 0);
  }

  std::ifstream ifs("t5.xml");
  CPPUNIT_ASSERT(ifs.good());
  {
    boost::archive::xml_iarchive ia(ifs);
    boost::serialization::serialize(ia, bl, 0);
  }

  CPPUNIT_ASSERT((bl.labelA == b.labelA));
  CPPUNIT_ASSERT((bl.labelB == b.labelB));

}
<|endoftext|>


<commit_before>/*
	This is a library for the SW01
	DIGITAL HUMIDITY, PRESSURE AND TEMPERATURE SENSOR

	The board uses I2C for communication.

	The board communicates with the following I2C device:
	-	BME280

	Data Sheets:
	BME280 - https://ae-bst.resource.bosch.com/media/_tech/media/datasheets/BST-BME280_DS001-11.pdf
*/

#include "xSW01.h"
#include <math.h>

/*--Public Class Function--*/

/********************************************************
 	Constructor
*********************************************************/
xSW01::xSW01(void)
{
	tempcal = 0.0;
    temperature = 0.0;
    humidity = 0.0;
    pressure = 0.0;
	altitude = 0.0;
}

/********************************************************
 	Configure Sensor
*********************************************************/
bool xSW01::begin(void)
{
	readSensorCoefficients();
	xCore.write8(BME280_I2C_ADDRESS, BME280_REG_CONTROLHUMID, 0x01);
	xCore.write8(BME280_I2C_ADDRESS, BME280_REG_CONTROLMEASURE, 0x3F);
	return true;
}

/********************************************************
 	Read Data from BME280 Sensor
*********************************************************/
void xSW01::poll(void)
{
	readTemperature();
    readHumidity();
    readPressure();
}

/********************************************************
 	Read Pressure from BME280 Sensor in Pa
*********************************************************/
float xSW01::getPressure(void)
{
	return pressure;
}

/********************************************************
 	Read Altitude from BME280 Sensor
*********************************************************/
float xSW01::getAltitude(void)
{
	float atmospheric = pressure / 100.0F;
	altitude = 44330.0 * (1.0 - pow(atmospheric / 1013.25, 0.1903));
    return altitude;
}

/********************************************************
 	Convert Temperature from BME280 Sensor to Celcuis
*********************************************************/
float xSW01::getTemperature_C(void)
{
    temperature = temperature + tempcal;
    return temperature;
}

/********************************************************
 	Convert Temperature from BME280 Sensor to Farenhied
*********************************************************/
float xSW01::getTemperature_F(void)
{
    temperature = temperature + tempcal;
    return temperature * 1.8 + 32;
}

/********************************************************
 	Read Humidity from BME280 Sensor
*********************************************************/
float xSW01::getHumidity(void)
{
	return humidity;
}

/********************************************************
 	Set temperature calibration data
*********************************************************/
void xSW01::setTempCal(float offset)
{
	tempcal = offset;
}

/*--Private Class Function--*/

/********************************************************
 	Read Temperature from BME280 Sensor
*********************************************************/
void xSW01::readTemperature(void)
{
    int32_t var1, var2;

    int32_t rawTemp = xCore.read24(BME280_I2C_ADDRESS, BME280_REG_TEMP);

    rawTemp >>= 4;

    var1  = ((((rawTemp >>3) - ((int32_t)cal_data.dig_T1 <<1))) *

             ((int32_t)cal_data.dig_T2)) >> 11;

    var2  = (((((rawTemp >>4) - ((int32_t)cal_data.dig_T1)) *

               ((rawTemp >>4) - ((int32_t)cal_data.dig_T1))) >> 12) *

             ((int32_t)cal_data.dig_T3)) >> 14;

    t_fine = var1 + var2;

    temperature  = (t_fine * 5 + 128) >> 8;

    temperature = temperature / 100;
}

/********************************************************
 	Read Pressure from BME280 Sensor
*********************************************************/
void xSW01::readPressure(void)
{
	int64_t var1, var2, p;

    int32_t rawPressure = xCore.read24(BME280_I2C_ADDRESS, BME280_REG_PRESSURE);
    rawPressure >>= 4;

    var1 = 	((int64_t)t_fine) - 128000;

    var2 = 	var1 * var1 * (int64_t)cal_data.dig_P6;

    var2 = 	var2 + ((var1*(int64_t)cal_data.dig_P5)<<17);

    var2 = 	var2 + (((int64_t)cal_data.dig_P4)<<35);

    var1 = 	((var1 * var1 * (int64_t)cal_data.dig_P3)>>8) +
			((var1 * (int64_t)cal_data.dig_P2)<<12);

	var1 = 	(((((int64_t)1)<<47)+var1))*((int64_t)cal_data.dig_P1)>>33;

    if (var1 == 0) {
        pressure = 0.0;
    }

    p = 1048576 - rawPressure;
    p = (((p<<31) - var2)*3125) / var1;
    var1 = (((int64_t)cal_data.dig_P9) * (p>>13) * (p>>13)) >> 25;
    var2 = (((int64_t)cal_data.dig_P8) * p) >> 19;

    p = ((p + var1 + var2) >> 8) + (((int64_t)cal_data.dig_P7)<<4);

    pressure = (float)p/256;
}

/********************************************************
 	Read Humidity from BME280 Sensor
*********************************************************/
void xSW01::readHumidity(void)
{

    int32_t rawHumidity = xCore.read16(BME280_I2C_ADDRESS, BME280_REG_HUMID);

    int32_t v_x1_u32r;

    v_x1_u32r = (t_fine - ((int32_t)76800));

    v_x1_u32r = (((((rawHumidity << 14) - (((int32_t)cal_data.dig_H4) << 20) -
				(((int32_t)cal_data.dig_H5) * v_x1_u32r)) + ((int32_t)16384)) >> 15) *
				(((((((v_x1_u32r * ((int32_t)cal_data.dig_H6)) >> 10) * (((v_x1_u32r *
				((int32_t)cal_data.dig_H3)) >> 11) + ((int32_t)32768))) >> 10) +
				((int32_t)2097152)) * ((int32_t)cal_data.dig_H2) + 8192) >> 14));

	v_x1_u32r = (v_x1_u32r - (((((v_x1_u32r >> 15) * (v_x1_u32r >> 15)) >> 7) *
				((int32_t)cal_data.dig_H1)) >> 4));

    v_x1_u32r = (v_x1_u32r < 0) ? 0 : v_x1_u32r;

    v_x1_u32r = (v_x1_u32r > 419430400) ? 419430400 : v_x1_u32r;

    float h = (v_x1_u32r>>12);

    humidity = h / 1024.0;
}

/********************************************************
 	Read Sensor Cailbration Data from BME280 Sensor
*********************************************************/
void xSW01::readSensorCoefficients(void)
{
    cal_data.dig_T1 = xCore.read16_LE(BME280_I2C_ADDRESS, BME280_DIG_T1_REG);
    cal_data.dig_T2 = xCore.readS16_LE(BME280_I2C_ADDRESS, BME280_DIG_T2_REG);
    cal_data.dig_T3 = xCore.readS16_LE(BME280_I2C_ADDRESS, BME280_DIG_T3_REG);
    cal_data.dig_P1 = xCore.read16_LE(BME280_I2C_ADDRESS, BME280_DIG_P1_REG);
    cal_data.dig_P2 = xCore.readS16_LE(BME280_I2C_ADDRESS, BME280_DIG_P2_REG);
    cal_data.dig_P3 = xCore.readS16_LE(BME280_I2C_ADDRESS, BME280_DIG_P3_REG);
    cal_data.dig_P4 = xCore.readS16_LE(BME280_I2C_ADDRESS, BME280_DIG_P4_REG);
    cal_data.dig_P5 = xCore.readS16_LE(BME280_I2C_ADDRESS, BME280_DIG_P5_REG);
    cal_data.dig_P6 = xCore.readS16_LE(BME280_I2C_ADDRESS, BME280_DIG_P6_REG);
    cal_data.dig_P7 = xCore.readS16_LE(BME280_I2C_ADDRESS, BME280_DIG_P7_REG);
    cal_data.dig_P8 = xCore.readS16_LE(BME280_I2C_ADDRESS, BME280_DIG_P8_REG);
    cal_data.dig_P9 = xCore.readS16_LE(BME280_I2C_ADDRESS, BME280_DIG_P9_REG);
    cal_data.dig_H1 = xCore.read8(BME280_I2C_ADDRESS, BME280_DIG_H1_REG);
    cal_data.dig_H2 = xCore.readS16_LE(BME280_I2C_ADDRESS, BME280_DIG_H2_REG);
    cal_data.dig_H3 = xCore.read8(BME280_I2C_ADDRESS, BME280_DIG_H3_REG);
    cal_data.dig_H4 = (xCore.read8(BME280_I2C_ADDRESS, BME280_DIG_H4_REG) << 4) | (xCore.read8(BME280_I2C_ADDRESS, BME280_DIG_H4_REG+1) & 0xF);
    cal_data.dig_H5 = (xCore.read8(BME280_I2C_ADDRESS, BME280_DIG_H5_REG+1) << 4) | (xCore.read8(BME280_I2C_ADDRESS, BME280_DIG_H5_REG) >> 4);
    cal_data.dig_H6 = (int8_t)xCore.read8(BME280_I2C_ADDRESS, BME280_DIG_H6_REG);
}

xSW01 SW01 = xSW01();
<commit_msg>Update xSW01.cpp<commit_after>/*
	This is a library for the SW01
	DIGITAL HUMIDITY, PRESSURE AND TEMPERATURE SENSOR

	The board uses I2C for communication.

	The board communicates with the following I2C device:
	-	BME280

	Data Sheets:
	BME280 - https://ae-bst.resource.bosch.com/media/_tech/media/datasheets/BST-BME280_DS001-11.pdf
*/

#include "xSW01.h"
#include <math.h>

/*--Public Class Function--*/

/********************************************************
 	Constructor
*********************************************************/
xSW01::xSW01(void)
{
	tempcal = 0.0;
  temperature = 0.0;
  humidity = 0.0;
  ressure = 0.0;
	altitude = 0.0;
}

/********************************************************
 	Configure Sensor
*********************************************************/
bool xSW01::begin(void)
{
	readSensorCoefficients();
	xCore.write8(BME280_I2C_ADDRESS, BME280_REG_CONTROLHUMID, 0x01);
	xCore.write8(BME280_I2C_ADDRESS, BME280_REG_CONTROLMEASURE, 0x3F);
	return true;
}

/********************************************************
 	Read Data from BME280 Sensor
*********************************************************/
void xSW01::poll(void)
{
	readTemperature();
  readHumidity();
  readPressure();
}

/********************************************************
 	Read Pressure from BME280 Sensor in Pa
*********************************************************/
float xSW01::getPressure(void)
{
	return pressure;
}

/********************************************************
 	Read Altitude from BME280 Sensor
*********************************************************/
float xSW01::getAltitude(void)
{
	float atmospheric = pressure / 100.0F;
	altitude = 44330.0 * (1.0 - pow(atmospheric / 1013.25, 0.1903));
  return altitude;
}

/********************************************************
 	Convert Temperature from BME280 Sensor to Celcuis
*********************************************************/
float xSW01::getTemperature_C(void)
{
	temperature = temperature + tempcal;
  return temperature;
}

/********************************************************
 	Convert Temperature from BME280 Sensor to Farenhied
*********************************************************/
float xSW01::getTemperature_F(void)
{
	temperature = temperature + tempcal;
  return temperature * 1.8 + 32;
}

/********************************************************
 	Read Humidity from BME280 Sensor
*********************************************************/
float xSW01::getHumidity(void)
{
	return humidity;
}

/********************************************************
 	Set temperature calibration data
*********************************************************/
void xSW01::setTempCal(float offset)
{
	tempcal = offset;
}

/*--Private Class Function--*/

/********************************************************
 	Read Temperature from BME280 Sensor
*********************************************************/
void xSW01::readTemperature(void)
{
	int32_t var1, var2;

  int32_t rawTemp = xCore.read24(BME280_I2C_ADDRESS, BME280_REG_TEMP);

  rawTemp >>= 4;

  var1  = ((((rawTemp >>3) - ((int32_t)cal_data.dig_T1 <<1))) *

          ((int32_t)cal_data.dig_T2)) >> 11;

  var2  = (((((rawTemp >>4) - ((int32_t)cal_data.dig_T1)) *

          ((rawTemp >>4) - ((int32_t)cal_data.dig_T1))) >> 12) *

          ((int32_t)cal_data.dig_T3)) >> 14;

  t_fine = var1 + var2;

  temperature  = (t_fine * 5 + 128) >> 8;

	temperature = temperature / 100;
}

/********************************************************
 	Read Pressure from BME280 Sensor
*********************************************************/
void xSW01::readPressure(void)
{
	int64_t var1, var2, p;

  int32_t rawPressure = xCore.read24(BME280_I2C_ADDRESS, BME280_REG_PRESSURE);
  rawPressure >>= 4;

  var1 = 	((int64_t)t_fine) - 128000;

  var2 = 	var1 * var1 * (int64_t)cal_data.dig_P6;

  var2 = 	var2 + ((var1*(int64_t)cal_data.dig_P5)<<17);

	var2 = 	var2 + (((int64_t)cal_data.dig_P4)<<35);

	var1 = 	((var1 * var1 * (int64_t)cal_data.dig_P3)>>8) +
			((var1 * (int64_t)cal_data.dig_P2)<<12);

	var1 = 	(((((int64_t)1)<<47)+var1))*((int64_t)cal_data.dig_P1)>>33;

  if (var1 == 0) {
      pressure = 0.0;
  }

  p = 1048576 - rawPressure;
  p = (((p<<31) - var2)*3125) / var1;
  var1 = (((int64_t)cal_data.dig_P9) * (p>>13) * (p>>13)) >> 25;
  var2 = (((int64_t)cal_data.dig_P8) * p) >> 19;

  p = ((p + var1 + var2) >> 8) + (((int64_t)cal_data.dig_P7)<<4);

  pressure = (float)p/256;
}

/********************************************************
 	Read Humidity from BME280 Sensor
*********************************************************/
void xSW01::readHumidity(void)
{

	int32_t rawHumidity = xCore.read16(BME280_I2C_ADDRESS, BME280_REG_HUMID);

  int32_t v_x1_u32r;

  v_x1_u32r = (t_fine - ((int32_t)76800));

  v_x1_u32r = (((((rawHumidity << 14) - (((int32_t)cal_data.dig_H4) << 20) -
				(((int32_t)cal_data.dig_H5) * v_x1_u32r)) + ((int32_t)16384)) >> 15) *
				(((((((v_x1_u32r * ((int32_t)cal_data.dig_H6)) >> 10) * (((v_x1_u32r *
				((int32_t)cal_data.dig_H3)) >> 11) + ((int32_t)32768))) >> 10) +
				((int32_t)2097152)) * ((int32_t)cal_data.dig_H2) + 8192) >> 14));

	v_x1_u32r = (v_x1_u32r - (((((v_x1_u32r >> 15) * (v_x1_u32r >> 15)) >> 7) *
				((int32_t)cal_data.dig_H1)) >> 4));

  v_x1_u32r = (v_x1_u32r < 0) ? 0 : v_x1_u32r;

  v_x1_u32r = (v_x1_u32r > 419430400) ? 419430400 : v_x1_u32r;

  float h = (v_x1_u32r>>12);

  humidity = h / 1024.0;
}

/********************************************************
 	Read Sensor Cailbration Data from BME280 Sensor
*********************************************************/
void xSW01::readSensorCoefficients(void)
{
    cal_data.dig_T1 = xCore.read16_LE(BME280_I2C_ADDRESS, BME280_DIG_T1_REG);
    cal_data.dig_T2 = xCore.readS16_LE(BME280_I2C_ADDRESS, BME280_DIG_T2_REG);
    cal_data.dig_T3 = xCore.readS16_LE(BME280_I2C_ADDRESS, BME280_DIG_T3_REG);
    cal_data.dig_P1 = xCore.read16_LE(BME280_I2C_ADDRESS, BME280_DIG_P1_REG);
    cal_data.dig_P2 = xCore.readS16_LE(BME280_I2C_ADDRESS, BME280_DIG_P2_REG);
    cal_data.dig_P3 = xCore.readS16_LE(BME280_I2C_ADDRESS, BME280_DIG_P3_REG);
    cal_data.dig_P4 = xCore.readS16_LE(BME280_I2C_ADDRESS, BME280_DIG_P4_REG);
    cal_data.dig_P5 = xCore.readS16_LE(BME280_I2C_ADDRESS, BME280_DIG_P5_REG);
    cal_data.dig_P6 = xCore.readS16_LE(BME280_I2C_ADDRESS, BME280_DIG_P6_REG);
    cal_data.dig_P7 = xCore.readS16_LE(BME280_I2C_ADDRESS, BME280_DIG_P7_REG);
    cal_data.dig_P8 = xCore.readS16_LE(BME280_I2C_ADDRESS, BME280_DIG_P8_REG);
    cal_data.dig_P9 = xCore.readS16_LE(BME280_I2C_ADDRESS, BME280_DIG_P9_REG);
    cal_data.dig_H1 = xCore.read8(BME280_I2C_ADDRESS, BME280_DIG_H1_REG);
    cal_data.dig_H2 = xCore.readS16_LE(BME280_I2C_ADDRESS, BME280_DIG_H2_REG);
    cal_data.dig_H3 = xCore.read8(BME280_I2C_ADDRESS, BME280_DIG_H3_REG);
    cal_data.dig_H4 = (xCore.read8(BME280_I2C_ADDRESS, BME280_DIG_H4_REG) << 4) | (xCore.read8(BME280_I2C_ADDRESS, BME280_DIG_H4_REG+1) & 0xF);
    cal_data.dig_H5 = (xCore.read8(BME280_I2C_ADDRESS, BME280_DIG_H5_REG+1) << 4) | (xCore.read8(BME280_I2C_ADDRESS, BME280_DIG_H5_REG) >> 4);
    cal_data.dig_H6 = (int8_t)xCore.read8(BME280_I2C_ADDRESS, BME280_DIG_H6_REG);
}

xSW01 SW01 = xSW01();
<|endoftext|>


<commit_before>#include <algorithm>
#include <experimental/string_view>
#include <unordered_map>
#include <vector>

#include <fcntl.h>
#include <netdb.h>
#include <netinet/tcp.h>

#include <sys/stat.h>
#include <unistd.h>

#include "core/yta_event_loop.h"
#include "http/yta_http.hpp"

#include "args.h"
#include "picohttpparser/picohttpparser.h"

const std::size_t MAX_URL_SIXE = 512;
const std::size_t MAX_HEADERS = 20;
const std::size_t MAX_BUFFER_SIZE = 1024;

typedef unsigned char byte;

struct parser_data {
    const char* method = nullptr;
    std::size_t method_len = 0;
    const char* path = nullptr;
    std::size_t path_len = 0;
    int pret = 0;
    int minor_version = 0;
    std::array<phr_header, MAX_HEADERS> headers;
    std::size_t num_headers = MAX_HEADERS;
};

struct user_data {
    std::size_t counter;

    std::array<char, MAX_BUFFER_SIZE> buf;
    std::array<char, MAX_BUFFER_SIZE> response_buf;

    bool finalized;

    std::size_t response_size;
    bool content;
    std::experimental::string_view extension;

    int file_fd;
    std::size_t file_size;
    std::size_t offset = 0;

    parser_data parser;

    struct stat file_stat;
};

void return_400(user_data* udata) {
    auto ret = yta::http::serve_400(udata->response_buf.data());
    udata->response_size = ret - udata->response_buf.data();
    udata->content = false;
    udata->finalized = true;
}

void return_404(user_data* udata) {
    auto ret = yta::http::serve_404(udata->response_buf.data());
    udata->response_size = ret - udata->response_buf.data();
    udata->content = false;
    udata->finalized = true;
}

std::unordered_map<std::experimental::string_view, std::experimental::string_view>
    mime_types{ { ".html", "text/html" },
                { ".css", "text/css" },
                { ".png", "image/png" },
                { ".jpg", "image/jpeg" },
                { ".jpeg", "image/jpeg" },
                { ".svg", "image/svg+xml" },
                { ".txt", "text/plain" },
                { ".js", "application/x-javascript" },
                { ".json", "application/json" },
                { ".pdf", "application/pdf" },
                { ".zip", "application/zip" },
                { ".gz", "application/gzip" },
                { ".woff", "application/font-woff" },
                { ".woff2", "application/font-woff2" },
                { ".opus", "audio/opus" },
                { ".mp4", "video/mp4" },
                { ".mpeg", "video/mpeg" },
                { ".mpg", "video/mpeg" },
                { ".mp3", "audio/mpeg" } };

int parse_url(yta_ctx* ctx, const char* path, size_t length) {
    user_data* udata = static_cast<user_data*>(ctx->user_data);

    // parse query string
    auto pos = std::find(path, path + length, '?');
    if (pos != path + length) {
        length = pos - path;
    }

    // clean path buffer is MAX_URL_SICE
    // leave space for appended index.html
    if ((length > (MAX_URL_SIXE - 20)) || (length == 0)) {
        return_404(udata);
        return 0;
    }

    char normalized_path[MAX_URL_SIXE] = { 0 };
    // prepend . for current directory
    normalized_path[0] = '.';
    std::size_t new_length = 1;

    // clean path
    new_length += yta::http::clean_path(path, length, normalized_path + 1);

    // clean_path removes trailing slash except for root;
    // put the trailing slash back if necessary.
    if (path[length - 1] == '/' && new_length != 2) {
        normalized_path[new_length] = '/';
        ++new_length;
    }

    // append index.html to urls with trailing slashes
    if (normalized_path[new_length - 1] == '/') {
        const char index_html[] = "index.html";
        std::copy(std::begin(index_html), std::end(index_html),
                  normalized_path + new_length);
        new_length += 10;
    }

    int ffd = open(normalized_path, O_RDONLY);

    if (ffd == -1) {
        return_404(udata);
        return 0;
    }

    struct stat file_stat;
    int status = fstat(ffd, &file_stat);

    if (status != 0 || !S_ISREG(file_stat.st_mode)) {
        return_404(udata);
        close(ffd);
        return 0;
    }

    std::experimental::string_view path_view(normalized_path, new_length);
    auto filetype_begin = path_view.rfind('.');
    auto file_begin = path_view.rfind('/');

    // we always find . at the beginning because of ./FILENAME
    if (file_begin < filetype_begin) {
        auto it = mime_types.find(path_view.substr(filetype_begin));
        if (it != mime_types.end()) {
            udata->extension = it->second;
        } else {
            udata->extension = { "text/plain" };
        }
    } else {
        udata->extension = { "text/plain" };
    }

    udata->file_fd = ffd;
    udata->file_size = file_stat.st_size;
    udata->file_stat = file_stat;

    return 0;
}

typedef bool (*header_handler)(yta_ctx*, std::experimental::string_view);

bool handle_if_modified_since(yta_ctx* ctx, std::experimental::string_view value) {
    user_data* udata = static_cast<user_data*>(ctx->user_data);

    tm stamp;
    if (strptime(value.data(), yta::http::http_time_format(), &stamp) == NULL) {
        auto end = yta::http::serve_400(udata->response_buf.data());
        udata->response_size = end - udata->response_buf.data();
        udata->content = false;
        udata->finalized = true;
        return true;
    }
    time_t time = timegm(&stamp);

    // not modified
    if (time >= udata->file_stat.st_mtime) {
        auto end = yta::http::serve_304(udata->response_buf.data());
        udata->response_size = end - udata->response_buf.data();
        udata->content = false;
        udata->finalized = true;
        return true;
    }

    return false;
}

bool handle_range(yta_ctx* ctx, std::experimental::string_view value) {
    user_data* udata = static_cast<user_data*>(ctx->user_data);

    // 7 bytes=X-
    if (value.size() < 8) {
        return_400(udata);
        return true;
    }

    auto iter = value.begin();

    if (!std::equal(iter, iter + 6, "bytes=")) {
        return_400(udata);
        return true;
    }

    std::advance(iter, 6);

    auto sep = std::find(iter, value.end(), '-');

    if (sep == value.end()) {
        return_400(udata);
        return true;
    }

    // Range: bytes=-123
    if (sep == iter) {
        // this should be supported by rfc
        return_400(udata);
        return true;
    }

    // TODO: think of something smarter to not create temp std::string
    // boost::lexical_cast would work
    auto val = std::string(iter, sep);
    int start_value = std::stoi(val);
    int end_value = 0;

    if (std::next(sep, 1) == value.end()) { // Range: bytes=123-
        end_value = udata->file_stat.st_size - 1;
    } else { // Range: bytes=123-200
        auto val = std::string(sep + 1, value.end());
        end_value = std::stoi(val);
    }

    // sanity checks
    if (end_value <= start_value) {
        end_value = udata->file_stat.st_size - 1;
    }

    if (start_value < 0) {
        start_value = 0;
    }

    if (end_value >= udata->file_stat.st_size) {
        end_value = udata->file_stat.st_size - 1;
    }

    udata->file_size = end_value - start_value + 1;
    udata->offset = start_value;

    auto end = yta::http::serve_206(udata->response_buf.data(), udata->file_size,
                                    &udata->file_stat.st_mtime, start_value, end_value,
                                    udata->file_stat.st_size);
    udata->response_size = end - udata->response_buf.data();
    udata->content = true;
    udata->finalized = true;

    return true;
}

std::unordered_map<std::experimental::string_view, header_handler> header_callbacks{
    { "If-Modified-Since", handle_if_modified_since }, { "Range", handle_range }
};

int parse_headers(yta_ctx* ctx) {
    user_data* udata = static_cast<user_data*>(ctx->user_data);

    for (std::size_t i = 0; (i < udata->parser.num_headers) && !udata->finalized; ++i) {
        std::experimental::string_view header(udata->parser.headers[i].name,
                                              udata->parser.headers[i].name_len);
        auto it = header_callbacks.find(header);
        if (it != header_callbacks.end()) {
            std::experimental::string_view value(udata->parser.headers[i].value,
                                                 udata->parser.headers[i].value_len);
            auto done = it->second(ctx, value);
            if (done) {
                return 0;
            }
        }
    }

    if (!udata->finalized) {
        auto end = yta::http::serve_200(udata->response_buf.data(), udata->file_size,
                                        &udata->file_stat.st_mtime, udata->extension);
        udata->response_size = end - udata->response_buf.data();
        udata->content = true;
        udata->finalized = true;
    }
    return 0;
}

void accept_logic(yta_ctx* ctx, user_data* udata);

yta_callback_status http_finish_callback(yta_ctx* ctx, void*, size_t) {
    user_data* udata = static_cast<user_data*>(ctx->user_data);

    if (udata->file_fd != 0) {
        close(udata->file_fd);
        udata->file_fd = 0;
    }

    // uncork
    int enable = 0;
    if (setsockopt(ctx->fd, IPPROTO_TCP, TCP_CORK, &enable, sizeof(enable)) < 0) {
        fprintf(stderr, "error setting TCP_CORK");
        exit(1);
    }

    accept_logic(ctx, udata);
    return YTA_OK;
}

yta_callback_status write_header_callback(yta_ctx* ctx, void*, size_t) {
    user_data* udata = static_cast<user_data*>(ctx->user_data);
    if (udata->content) {
        yta_async_sendfile(ctx, http_finish_callback, udata->file_fd, udata->file_size,
                           udata->offset);
        return YTA_OK;
    } else {
        return http_finish_callback(ctx, NULL, 0);
    }
}

yta_callback_status read_callback_http(yta_ctx* ctx, void* buf, size_t read) {
    user_data* udata = static_cast<user_data*>(ctx->user_data);

    std::size_t prev_count = udata->counter;
    udata->counter += read;

    int parsed = phr_parse_request(
        udata->buf.data(), udata->counter, &udata->parser.method,
        &udata->parser.method_len, &udata->parser.path, &udata->parser.path_len,
        &udata->parser.minor_version, udata->parser.headers.data(),
        &udata->parser.num_headers, prev_count);

    if (parsed == -1) {
        return_400(udata);
    } else if (parsed > 0) {
        parse_url(ctx, udata->parser.path, udata->parser.path_len);
        parse_headers(ctx);
    }

    if (udata->finalized) {
        // cork
        int enable = 1;
        if (setsockopt(ctx->fd, IPPROTO_TCP, TCP_CORK, &enable, sizeof(enable)) < 0) {
            fprintf(stderr, "error setting TCP_CORK");
            exit(1);
        }

        yta_async_write(ctx, write_header_callback, udata->response_buf.data(),
                        udata->response_size);
        return YTA_OK;
    }

    if (udata->counter == MAX_BUFFER_SIZE) {
        return http_finish_callback(ctx, NULL, 0);
    }

    yta_async_read(ctx, read_callback_http, (char*)buf + read,
                   MAX_BUFFER_SIZE - udata->counter);
    return YTA_OK;
}

yta_callback_status http_cleanup(yta_ctx* ctx) {
    user_data* udata = static_cast<user_data*>(ctx->user_data);

    if (udata->file_fd != 0) {
        close(udata->file_fd);
        udata->file_fd = 0;
    }

    delete udata;

    return YTA_EXIT;
}

yta_callback_status timer_callback(yta_ctx* /* ctx */) {
    printf("Force closing http connection\n");
    return YTA_EXIT;
}

void accept_logic(yta_ctx* ctx, user_data* udata) {
    udata->parser = parser_data{};
    udata->counter = 0;
    udata->finalized = false;
    udata->file_fd = 0;
    yta_async_read(ctx, read_callback_http, udata->buf.data(), MAX_BUFFER_SIZE);
}

yta_callback_status accept_callback_http(yta_ctx* ctx) {
    user_data* udata = new user_data;
    if (udata == nullptr) {
        return YTA_EXIT;
    }
    ctx->user_data = udata;
    yta_set_close_callback(ctx, http_cleanup);
    yta_async_timer(ctx, timer_callback, 300, 0);
    accept_logic(ctx, udata);
    return YTA_OK;
}

int main(int argc, char** argv) {
    auto opts = get_program_opts(argc, argv);

    yta_run(argv, opts.host.c_str(), opts.port.c_str(), opts.pid_file.c_str(),
            opts.daemonize, opts.workers, accept_callback_http);

    return 0;
}
<commit_msg>Add more content types<commit_after>#include <algorithm>
#include <experimental/string_view>
#include <unordered_map>
#include <vector>

#include <fcntl.h>
#include <netdb.h>
#include <netinet/tcp.h>

#include <sys/stat.h>
#include <unistd.h>

#include "core/yta_event_loop.h"
#include "http/yta_http.hpp"

#include "args.h"
#include "picohttpparser/picohttpparser.h"

const std::size_t MAX_URL_SIXE = 512;
const std::size_t MAX_HEADERS = 20;
const std::size_t MAX_BUFFER_SIZE = 1024;

typedef unsigned char byte;

struct parser_data {
    const char* method = nullptr;
    std::size_t method_len = 0;
    const char* path = nullptr;
    std::size_t path_len = 0;
    int pret = 0;
    int minor_version = 0;
    std::array<phr_header, MAX_HEADERS> headers;
    std::size_t num_headers = MAX_HEADERS;
};

struct user_data {
    std::size_t counter;

    std::array<char, MAX_BUFFER_SIZE> buf;
    std::array<char, MAX_BUFFER_SIZE> response_buf;

    bool finalized;

    std::size_t response_size;
    bool content;
    std::experimental::string_view extension;

    int file_fd;
    std::size_t file_size;
    std::size_t offset = 0;

    parser_data parser;

    struct stat file_stat;
};

void return_400(user_data* udata) {
    auto ret = yta::http::serve_400(udata->response_buf.data());
    udata->response_size = ret - udata->response_buf.data();
    udata->content = false;
    udata->finalized = true;
}

void return_404(user_data* udata) {
    auto ret = yta::http::serve_404(udata->response_buf.data());
    udata->response_size = ret - udata->response_buf.data();
    udata->content = false;
    udata->finalized = true;
}

std::unordered_map<std::experimental::string_view, std::experimental::string_view>
    mime_types{ { ".html", "text/html" },
                { ".css", "text/css" },
                { ".png", "image/png" },
                { ".jpg", "image/jpeg" },
                { ".jpeg", "image/jpeg" },
                { ".svg", "image/svg+xml" },
                { ".gif", "image/gif" },
                { ".ico", "image/x-icon" },
                { ".txt", "text/plain" },
                { ".doc", "application/msword" },
                { ".docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document" },
                { ".csv", "text/csv" },
                { ".js", "application/x-javascript" },
                { ".json", "application/json" },
                { ".pdf", "application/pdf" },
                { ".zip", "application/zip" },
                { ".gz", "application/gzip" },
                { ".woff", "application/font-woff" },
                { ".woff2", "application/font-woff2" },
                { ".opus", "audio/opus" },
                { ".mp4", "video/mp4" },
                { ".mpeg", "video/mpeg" },
                { ".mpg", "video/mpeg" },
                { ".mp3", "audio/mpeg" } };

int parse_url(yta_ctx* ctx, const char* path, size_t length) {
    user_data* udata = static_cast<user_data*>(ctx->user_data);

    // parse query string
    auto pos = std::find(path, path + length, '?');
    if (pos != path + length) {
        length = pos - path;
    }

    // clean path buffer is MAX_URL_SICE
    // leave space for appended index.html
    if ((length > (MAX_URL_SIXE - 20)) || (length == 0)) {
        return_404(udata);
        return 0;
    }

    char normalized_path[MAX_URL_SIXE] = { 0 };
    // prepend . for current directory
    normalized_path[0] = '.';
    std::size_t new_length = 1;

    // clean path
    new_length += yta::http::clean_path(path, length, normalized_path + 1);

    // clean_path removes trailing slash except for root;
    // put the trailing slash back if necessary.
    if (path[length - 1] == '/' && new_length != 2) {
        normalized_path[new_length] = '/';
        ++new_length;
    }

    // append index.html to urls with trailing slashes
    if (normalized_path[new_length - 1] == '/') {
        const char index_html[] = "index.html";
        std::copy(std::begin(index_html), std::end(index_html),
                  normalized_path + new_length);
        new_length += 10;
    }

    int ffd = open(normalized_path, O_RDONLY);

    if (ffd == -1) {
        return_404(udata);
        return 0;
    }

    struct stat file_stat;
    int status = fstat(ffd, &file_stat);

    if (status != 0 || !S_ISREG(file_stat.st_mode)) {
        return_404(udata);
        close(ffd);
        return 0;
    }

    std::experimental::string_view path_view(normalized_path, new_length);
    auto filetype_begin = path_view.rfind('.');
    auto file_begin = path_view.rfind('/');

    // we always find . at the beginning because of ./FILENAME
    if (file_begin < filetype_begin) {
        auto it = mime_types.find(path_view.substr(filetype_begin));
        if (it != mime_types.end()) {
            udata->extension = it->second;
        } else {
            udata->extension = { "text/plain" };
        }
    } else {
        udata->extension = { "text/plain" };
    }

    udata->file_fd = ffd;
    udata->file_size = file_stat.st_size;
    udata->file_stat = file_stat;

    return 0;
}

typedef bool (*header_handler)(yta_ctx*, std::experimental::string_view);

bool handle_if_modified_since(yta_ctx* ctx, std::experimental::string_view value) {
    user_data* udata = static_cast<user_data*>(ctx->user_data);

    tm stamp;
    if (strptime(value.data(), yta::http::http_time_format(), &stamp) == NULL) {
        auto end = yta::http::serve_400(udata->response_buf.data());
        udata->response_size = end - udata->response_buf.data();
        udata->content = false;
        udata->finalized = true;
        return true;
    }
    time_t time = timegm(&stamp);

    // not modified
    if (time >= udata->file_stat.st_mtime) {
        auto end = yta::http::serve_304(udata->response_buf.data());
        udata->response_size = end - udata->response_buf.data();
        udata->content = false;
        udata->finalized = true;
        return true;
    }

    return false;
}

bool handle_range(yta_ctx* ctx, std::experimental::string_view value) {
    user_data* udata = static_cast<user_data*>(ctx->user_data);

    // 7 bytes=X-
    if (value.size() < 8) {
        return_400(udata);
        return true;
    }

    auto iter = value.begin();

    if (!std::equal(iter, iter + 6, "bytes=")) {
        return_400(udata);
        return true;
    }

    std::advance(iter, 6);

    auto sep = std::find(iter, value.end(), '-');

    if (sep == value.end()) {
        return_400(udata);
        return true;
    }

    // Range: bytes=-123
    if (sep == iter) {
        // this should be supported by rfc
        return_400(udata);
        return true;
    }

    // TODO: think of something smarter to not create temp std::string
    // boost::lexical_cast would work
    auto val = std::string(iter, sep);
    int start_value = std::stoi(val);
    int end_value = 0;

    if (std::next(sep, 1) == value.end()) { // Range: bytes=123-
        end_value = udata->file_stat.st_size - 1;
    } else { // Range: bytes=123-200
        auto val = std::string(sep + 1, value.end());
        end_value = std::stoi(val);
    }

    // sanity checks
    if (end_value <= start_value) {
        end_value = udata->file_stat.st_size - 1;
    }

    if (start_value < 0) {
        start_value = 0;
    }

    if (end_value >= udata->file_stat.st_size) {
        end_value = udata->file_stat.st_size - 1;
    }

    udata->file_size = end_value - start_value + 1;
    udata->offset = start_value;

    auto end = yta::http::serve_206(udata->response_buf.data(), udata->file_size,
                                    &udata->file_stat.st_mtime, start_value, end_value,
                                    udata->file_stat.st_size);
    udata->response_size = end - udata->response_buf.data();
    udata->content = true;
    udata->finalized = true;

    return true;
}

std::unordered_map<std::experimental::string_view, header_handler> header_callbacks{
    { "If-Modified-Since", handle_if_modified_since }, { "Range", handle_range }
};

int parse_headers(yta_ctx* ctx) {
    user_data* udata = static_cast<user_data*>(ctx->user_data);

    for (std::size_t i = 0; (i < udata->parser.num_headers) && !udata->finalized; ++i) {
        std::experimental::string_view header(udata->parser.headers[i].name,
                                              udata->parser.headers[i].name_len);
        auto it = header_callbacks.find(header);
        if (it != header_callbacks.end()) {
            std::experimental::string_view value(udata->parser.headers[i].value,
                                                 udata->parser.headers[i].value_len);
            auto done = it->second(ctx, value);
            if (done) {
                return 0;
            }
        }
    }

    if (!udata->finalized) {
        auto end = yta::http::serve_200(udata->response_buf.data(), udata->file_size,
                                        &udata->file_stat.st_mtime, udata->extension);
        udata->response_size = end - udata->response_buf.data();
        udata->content = true;
        udata->finalized = true;
    }
    return 0;
}

void accept_logic(yta_ctx* ctx, user_data* udata);

yta_callback_status http_finish_callback(yta_ctx* ctx, void*, size_t) {
    user_data* udata = static_cast<user_data*>(ctx->user_data);

    if (udata->file_fd != 0) {
        close(udata->file_fd);
        udata->file_fd = 0;
    }

    // uncork
    int enable = 0;
    if (setsockopt(ctx->fd, IPPROTO_TCP, TCP_CORK, &enable, sizeof(enable)) < 0) {
        fprintf(stderr, "error setting TCP_CORK");
        exit(1);
    }

    accept_logic(ctx, udata);
    return YTA_OK;
}

yta_callback_status write_header_callback(yta_ctx* ctx, void*, size_t) {
    user_data* udata = static_cast<user_data*>(ctx->user_data);
    if (udata->content) {
        yta_async_sendfile(ctx, http_finish_callback, udata->file_fd, udata->file_size,
                           udata->offset);
        return YTA_OK;
    } else {
        return http_finish_callback(ctx, NULL, 0);
    }
}

yta_callback_status read_callback_http(yta_ctx* ctx, void* buf, size_t read) {
    user_data* udata = static_cast<user_data*>(ctx->user_data);

    std::size_t prev_count = udata->counter;
    udata->counter += read;

    int parsed = phr_parse_request(
        udata->buf.data(), udata->counter, &udata->parser.method,
        &udata->parser.method_len, &udata->parser.path, &udata->parser.path_len,
        &udata->parser.minor_version, udata->parser.headers.data(),
        &udata->parser.num_headers, prev_count);

    if (parsed == -1) {
        return_400(udata);
    } else if (parsed > 0) {
        parse_url(ctx, udata->parser.path, udata->parser.path_len);
        parse_headers(ctx);
    }

    if (udata->finalized) {
        // cork
        int enable = 1;
        if (setsockopt(ctx->fd, IPPROTO_TCP, TCP_CORK, &enable, sizeof(enable)) < 0) {
            fprintf(stderr, "error setting TCP_CORK");
            exit(1);
        }

        yta_async_write(ctx, write_header_callback, udata->response_buf.data(),
                        udata->response_size);
        return YTA_OK;
    }

    if (udata->counter == MAX_BUFFER_SIZE) {
        return http_finish_callback(ctx, NULL, 0);
    }

    yta_async_read(ctx, read_callback_http, (char*)buf + read,
                   MAX_BUFFER_SIZE - udata->counter);
    return YTA_OK;
}

yta_callback_status http_cleanup(yta_ctx* ctx) {
    user_data* udata = static_cast<user_data*>(ctx->user_data);

    if (udata->file_fd != 0) {
        close(udata->file_fd);
        udata->file_fd = 0;
    }

    delete udata;

    return YTA_EXIT;
}

yta_callback_status timer_callback(yta_ctx* /* ctx */) {
    printf("Force closing http connection\n");
    return YTA_EXIT;
}

void accept_logic(yta_ctx* ctx, user_data* udata) {
    udata->parser = parser_data{};
    udata->counter = 0;
    udata->finalized = false;
    udata->file_fd = 0;
    yta_async_read(ctx, read_callback_http, udata->buf.data(), MAX_BUFFER_SIZE);
}

yta_callback_status accept_callback_http(yta_ctx* ctx) {
    user_data* udata = new user_data;
    if (udata == nullptr) {
        return YTA_EXIT;
    }
    ctx->user_data = udata;
    yta_set_close_callback(ctx, http_cleanup);
    yta_async_timer(ctx, timer_callback, 300, 0);
    accept_logic(ctx, udata);
    return YTA_OK;
}

int main(int argc, char** argv) {
    auto opts = get_program_opts(argc, argv);

    yta_run(argv, opts.host.c_str(), opts.port.c_str(), opts.pid_file.c_str(),
            opts.daemonize, opts.workers, accept_callback_http);

    return 0;
}
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
// Name:      process.cpp
// Purpose:   Implementation of class wxExProcess
// Author:    Anton van Wezenbeek
// Copyright: (c) 2012 Anton van Wezenbeek
////////////////////////////////////////////////////////////////////////////////

#include <wx/wxprec.h>
#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif
#include <wx/config.h>
#include <wx/txtstrm.h> // for wxTextInputStream
#include <wx/utils.h> // for wxGetEnv
#include <wx/extension/process.h>
#include <wx/extension/configdlg.h>
#include <wx/extension/defs.h>
#include <wx/extension/shell.h>
#include <wx/extension/util.h> // for wxExConfigFirstOf

BEGIN_EVENT_TABLE(wxExProcess, wxProcess)
  EVT_MENU(ID_SHELL_COMMAND, wxExProcess::OnCommand)
  EVT_MENU(ID_SHELL_COMMAND_STOP, wxExProcess::OnCommand)
  EVT_TIMER(-1, wxExProcess::OnTimer)
END_EVENT_TABLE()

wxExSTCEntryDialog* wxExProcess::m_Dialog = NULL;
wxString wxExProcess::m_WorkingDirKey = _("Process folder");

wxExProcess::wxExProcess()
  : wxProcess(wxPROCESS_REDIRECT)
  , m_Timer(new wxTimer(this))
  , m_Busy(false)
  , m_Error(false)
  , m_Sync(false)
{
  m_Command = wxExConfigFirstOf(_("Process"));
}

wxExProcess::~wxExProcess()
{
  delete m_Timer;
}

wxExProcess::wxExProcess(const wxExProcess& process)
{
  *this = process;
}

wxExProcess& wxExProcess::operator=(const wxExProcess& p)
{
  m_Busy = p.m_Busy;
  m_Error = p.m_Error;
  m_Output = p.m_Output;
  m_Sync = p.m_Sync;
  m_Timer = new wxTimer(this);

  return *this;
}

bool wxExProcess::CheckInput()
{
  if (m_Busy)
  {
    return false;
  }

  m_Busy = true;

  wxString output;

  if (IsInputAvailable())
  {
    wxTextInputStream tis(*GetInputStream());

    while (IsInputAvailable())
    {
      const wxChar c = tis.GetChar();

      if (c != 0)
      {
        output << c;
      }
    }
  }

  if (IsErrorAvailable())
  {
    wxTextInputStream tis(*GetErrorStream());

    while (IsErrorAvailable())
    {
      const wxChar c = tis.GetChar();

      if (c != 0)
      {
        output << c;
      }
    }
  }

  m_Busy = false;

  if (!output.empty())
  {
    m_Dialog->GetSTCShell()->AddText(output);

    return true;
  }
  else
  {
    return false;
  }
}

int wxExProcess::ConfigDialog(
  wxWindow* parent,
  const wxString& title,
  bool modal)
{
  std::vector<wxExConfigItem> v;

  v.push_back(wxExConfigItem(
    _("Process"),
    CONFIG_COMBOBOX,
    wxEmptyString,
    true));

  v.push_back(wxExConfigItem(
    m_WorkingDirKey,
    CONFIG_COMBOBOXDIR,
    wxEmptyString,
    true,
    1000));

  if (modal)
  {
    return wxExConfigDialog(parent,
      v,
      title).ShowModal();
  }
  else
  {
    wxExConfigDialog* dlg = new wxExConfigDialog(
      parent,
      v,
      title);

    return dlg->Show();
  }
}

bool wxExProcess::Execute(
  const wxString& command_to_execute,
  int flags,
  const wxString& wd)
{
  m_Error = false;

  struct wxExecuteEnv env;

  if (command_to_execute.empty())
  {
    if (wxExConfigFirstOf(_("Process")).empty())
    {
      if (ConfigDialog(wxTheApp->GetTopWindow()) == wxID_CANCEL)
      {
        return false;
      }
    }

    m_Command = wxExConfigFirstOf(_("Process"));
    env.cwd = wxExConfigFirstOf(m_WorkingDirKey);
  }
  else
  {
    m_Command = command_to_execute;
    env.cwd = wd;
  }

  m_Sync = (flags & wxEXEC_SYNC);

  // Construct the dialog.
  // This is necessary both in sync and async mode,
  // as for sync mode the dialog is used for presenting the
  // output member.
  if (m_Dialog == NULL)
  {
    m_Dialog = new wxExSTCEntryDialog(
      wxTheApp->GetTopWindow(),
      wxEmptyString,
      wxEmptyString,
      wxEmptyString,
      wxOK,
      true); // use_shell to force STCShell

    m_Dialog->SetProcess(this);
    m_Dialog->GetSTCShell()->SetEventHandler(this);
  }

  m_Dialog->GetSTCShell()->EnableShell(!m_Sync);

  if (!m_Sync)
  {
    m_Dialog->SetTitle(m_Command);
    m_Dialog->GetSTCShell()->ClearAll();

    // If we have entered a shell, then the shell
    // itself has no prompt. So put one here.
    if (m_Command == "bash" ||
        m_Command == "csh" ||
        m_Command == "ksh" ||
        m_Command == "tcsh" ||
        m_Command == "sh")
    {
      wxString host;
      wxGetEnv("HOST", &host);
      m_Dialog->GetSTCShell()->SetPrompt(host + ">", false);
    }
    else
    {
      m_Dialog->GetSTCShell()->SetPrompt("");
    }

    // For asynchronous execution the return value is the process id and zero
    // value indicates that the command could not be executed.
    if (wxExecute(m_Command, flags, this, &env) > 0)
    {
      m_Dialog->Show();

      if (!CheckInput())
      {
        m_Dialog->GetSTCShell()->Prompt(wxEmptyString, false);
      }

      if (IsRunning())
      {
        m_Timer->Start(100); // each 100 milliseconds
      }
    }
    else
    {
      m_Dialog->Hide();

      m_Error = true;
    }
  }
  else
  {
    wxArrayString output;
    wxArrayString errors;

    // Call wxExecute to execute the command and
    // collect the output and the errors.
    if (wxExecute(
      m_Command,
      output,
      errors,
      flags,
      &env) == -1)
    {
      m_Output.clear();
      m_Error = true;
    }
    else
    {
      // Set output by converting array strings into normal strings.
      m_Output = wxJoin(errors, '\n', '\n') + wxJoin(output, '\n', '\n');
    }
  }

  return !m_Error;
}

bool wxExProcess::IsRunning() const
{
  if (
    // If we executed a sync process, then it always ended,
    // so it is not running.
    m_Sync ||
    GetPid() <= 0)
  {
    return false;
  }

  return Exists(GetPid());
}

wxKillError wxExProcess::Kill(wxSignal sig)
{
  if (!IsRunning())
  {
    return wxKILL_NO_PROCESS;
  }

  const wxKillError result = wxProcess::Kill(GetPid(), sig);

  switch (result)
  {
    case wxKILL_OK:
      wxLogStatus(_("Stopped"));
      DeletePendingEvents();
      m_Timer->Stop();
      m_Dialog->Hide();
      break;

    case wxKILL_BAD_SIGNAL:
      wxLogStatus("no such signal");
      break;

    case wxKILL_ACCESS_DENIED:
    	wxLogStatus("permission denied");
      break;

    case wxKILL_NO_PROCESS:
      wxLogStatus("no such process");
      break;

    case wxKILL_ERROR:
      wxLogStatus("another, unspecified error");
      break;

    default: wxFAIL;
  }

  return result;
}

void wxExProcess::OnCommand(wxCommandEvent& event)
{
  switch (event.GetId())
  {
  case ID_SHELL_COMMAND:
    m_Timer->Stop();
    m_Dialog->GetSTCShell()->LineEnd();

    if (m_Command != "cmd")
    {
      m_Dialog->GetSTCShell()->AddText(m_Dialog->GetSTCShell()->GetEOL());
    }

    if (IsRunning())
    {
      // send command to process
      wxOutputStream* os = GetOutputStream();

      if (os != NULL)
      {
        wxTextOutputStream os(*GetOutputStream());
        os.WriteString(event.GetString() + "\n");
      }

      wxMilliSleep(10);

      CheckInput();

      m_Dialog->GetSTCShell()->Prompt(wxEmptyString, false);

      m_Timer->Start();
    }
    else
    {
      wxLogStatus("Process is not running");
    }
    break;

  case ID_SHELL_COMMAND_STOP:
    if (IsRunning())
    {
      Kill();
    }
    break;

  default: wxFAIL; break;
  }
}

void wxExProcess::OnTerminate(int pid, int status)
{
  m_Timer->Stop();

  wxLogStatus(_("Ready"));
  wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, ID_TERMINATED_PROCESS);
  wxPostEvent(wxTheApp->GetTopWindow(), event);

  // Collect remaining input.
  CheckInput();
}

void wxExProcess::OnTimer(wxTimerEvent& event)
{
  CheckInput();
}

#if wxUSE_GUI
void wxExProcess::ShowOutput(const wxString& caption) const
{
  if (!m_Sync)
  {
    wxLogStatus("Output only available for sync processes");
  }
  else if (!m_Error)
  {
    if (m_Dialog != NULL)
    {
      m_Dialog->GetSTC()->SetText(m_Output);
      m_Dialog->SetTitle(caption.empty() ? m_Command: caption);
      m_Dialog->Show();
    }
    else if (!m_Output.empty())
    {
      wxLogMessage(m_Output);
    }
    else
    {
      wxLogStatus("No output available");
    }
  }
  else
  {
    // Executing command failed, so no output,
    // show failing command.
    wxLogError("Could not execute: " + m_Command);
  }
}
#endif
<commit_msg>let cd set working directory<commit_after>////////////////////////////////////////////////////////////////////////////////
// Name:      process.cpp
// Purpose:   Implementation of class wxExProcess
// Author:    Anton van Wezenbeek
// Copyright: (c) 2012 Anton van Wezenbeek
////////////////////////////////////////////////////////////////////////////////

#include <wx/wxprec.h>
#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif
#include <wx/config.h>
#include <wx/txtstrm.h> // for wxTextInputStream
#include <wx/utils.h> // for wxGetEnv
#include <wx/extension/process.h>
#include <wx/extension/configdlg.h>
#include <wx/extension/defs.h>
#include <wx/extension/shell.h>
#include <wx/extension/util.h> // for wxExConfigFirstOf

BEGIN_EVENT_TABLE(wxExProcess, wxProcess)
  EVT_MENU(ID_SHELL_COMMAND, wxExProcess::OnCommand)
  EVT_MENU(ID_SHELL_COMMAND_STOP, wxExProcess::OnCommand)
  EVT_TIMER(-1, wxExProcess::OnTimer)
END_EVENT_TABLE()

wxExSTCEntryDialog* wxExProcess::m_Dialog = NULL;
wxString wxExProcess::m_WorkingDirKey = _("Process folder");

wxExProcess::wxExProcess()
  : wxProcess(wxPROCESS_REDIRECT)
  , m_Timer(new wxTimer(this))
  , m_Busy(false)
  , m_Error(false)
  , m_Sync(false)
{
  m_Command = wxExConfigFirstOf(_("Process"));
}

wxExProcess::~wxExProcess()
{
  delete m_Timer;
}

wxExProcess::wxExProcess(const wxExProcess& process)
{
  *this = process;
}

wxExProcess& wxExProcess::operator=(const wxExProcess& p)
{
  m_Busy = p.m_Busy;
  m_Error = p.m_Error;
  m_Output = p.m_Output;
  m_Sync = p.m_Sync;
  m_Timer = new wxTimer(this);

  return *this;
}

bool wxExProcess::CheckInput()
{
  if (m_Busy)
  {
    return false;
  }

  m_Busy = true;

  wxString output;

  if (IsInputAvailable())
  {
    wxTextInputStream tis(*GetInputStream());

    while (IsInputAvailable())
    {
      const wxChar c = tis.GetChar();

      if (c != 0)
      {
        output << c;
      }
    }
  }

  if (IsErrorAvailable())
  {
    wxTextInputStream tis(*GetErrorStream());

    while (IsErrorAvailable())
    {
      const wxChar c = tis.GetChar();

      if (c != 0)
      {
        output << c;
      }
    }
  }

  m_Busy = false;

  if (!output.empty())
  {
    m_Dialog->GetSTCShell()->AddText(output);

    return true;
  }
  else
  {
    return false;
  }
}

int wxExProcess::ConfigDialog(
  wxWindow* parent,
  const wxString& title,
  bool modal)
{
  std::vector<wxExConfigItem> v;

  v.push_back(wxExConfigItem(
    _("Process"),
    CONFIG_COMBOBOX,
    wxEmptyString,
    true));

  v.push_back(wxExConfigItem(
    m_WorkingDirKey,
    CONFIG_COMBOBOXDIR,
    wxEmptyString,
    true,
    1000));

  if (modal)
  {
    return wxExConfigDialog(parent,
      v,
      title).ShowModal();
  }
  else
  {
    wxExConfigDialog* dlg = new wxExConfigDialog(
      parent,
      v,
      title);

    return dlg->Show();
  }
}

bool wxExProcess::Execute(
  const wxString& command_to_execute,
  int flags,
  const wxString& wd)
{
  m_Error = false;

  struct wxExecuteEnv env;

  if (command_to_execute.empty())
  {
    if (wxExConfigFirstOf(_("Process")).empty())
    {
      if (ConfigDialog(wxTheApp->GetTopWindow()) == wxID_CANCEL)
      {
        return false;
      }
    }

    m_Command = wxExConfigFirstOf(_("Process"));
    env.cwd = wxExConfigFirstOf(m_WorkingDirKey);
  }
  else
  {
    m_Command = command_to_execute;
    env.cwd = wd;
  }

  m_Sync = (flags & wxEXEC_SYNC);

  // Construct the dialog.
  // This is necessary both in sync and async mode,
  // as for sync mode the dialog is used for presenting the
  // output member.
  if (m_Dialog == NULL)
  {
    m_Dialog = new wxExSTCEntryDialog(
      wxTheApp->GetTopWindow(),
      wxEmptyString,
      wxEmptyString,
      wxEmptyString,
      wxOK,
      true); // use_shell to force STCShell

    m_Dialog->SetProcess(this);
    m_Dialog->GetSTCShell()->SetEventHandler(this);
  }

  m_Dialog->GetSTCShell()->EnableShell(!m_Sync);

  if (!m_Sync)
  {
    m_Dialog->SetTitle(m_Command);
    m_Dialog->GetSTCShell()->ClearAll();

    // If we have entered a shell, then the shell
    // itself has no prompt. So put one here.
    if (m_Command == "bash" ||
        m_Command == "csh" ||
        m_Command == "ksh" ||
        m_Command == "tcsh" ||
        m_Command == "sh")
    {
      wxString host;
      wxGetEnv("HOST", &host);
      m_Dialog->GetSTCShell()->SetPrompt(host + ">", false);
    }
    else
    {
      m_Dialog->GetSTCShell()->SetPrompt("");
    }

    // For asynchronous execution the return value is the process id and zero
    // value indicates that the command could not be executed.
    if (wxExecute(m_Command, flags, this, &env) > 0)
    {
      m_Dialog->Show();

      if (!CheckInput())
      {
        m_Dialog->GetSTCShell()->Prompt(wxEmptyString, false);
      }

      if (IsRunning())
      {
        m_Timer->Start(100); // each 100 milliseconds
      }
    }
    else
    {
      m_Dialog->Hide();

      m_Error = true;
    }
  }
  else
  {
    wxArrayString output;
    wxArrayString errors;

    // Call wxExecute to execute the command and
    // collect the output and the errors.
    if (wxExecute(
      m_Command,
      output,
      errors,
      flags,
      &env) == -1)
    {
      m_Output.clear();
      m_Error = true;
    }
    else
    {
      // Set output by converting array strings into normal strings.
      m_Output = wxJoin(errors, '\n', '\n') + wxJoin(output, '\n', '\n');
    }
  }

  return !m_Error;
}

bool wxExProcess::IsRunning() const
{
  if (
    // If we executed a sync process, then it always ended,
    // so it is not running.
    m_Sync ||
    GetPid() <= 0)
  {
    return false;
  }

  return Exists(GetPid());
}

wxKillError wxExProcess::Kill(wxSignal sig)
{
  if (!IsRunning())
  {
    return wxKILL_NO_PROCESS;
  }

  const wxKillError result = wxProcess::Kill(GetPid(), sig);

  switch (result)
  {
    case wxKILL_OK:
      wxLogStatus(_("Stopped"));
      DeletePendingEvents();
      m_Timer->Stop();
      m_Dialog->Hide();
      break;

    case wxKILL_BAD_SIGNAL:
      wxLogStatus("no such signal");
      break;

    case wxKILL_ACCESS_DENIED:
    	wxLogStatus("permission denied");
      break;

    case wxKILL_NO_PROCESS:
      wxLogStatus("no such process");
      break;

    case wxKILL_ERROR:
      wxLogStatus("another, unspecified error");
      break;

    default: wxFAIL;
  }

  return result;
}

void wxExProcess::OnCommand(wxCommandEvent& event)
{
  switch (event.GetId())
  {
  case ID_SHELL_COMMAND:
    m_Timer->Stop();
    m_Dialog->GetSTCShell()->LineEnd();

    if (m_Command != "cmd")
    {
      m_Dialog->GetSTCShell()->AddText(m_Dialog->GetSTCShell()->GetEOL());
    }

    if (IsRunning())
    {
      // send command to process
      wxOutputStream* os = GetOutputStream();

      if (os != NULL)
      {
        wxTextOutputStream os(*GetOutputStream());
        const wxString command(event.GetString());
        os.WriteString(command + "\n");

        wxString rest;
        if (command.StartsWith("cd", &rest))
        {
          rest.Trim(false);
          wxSetWorkingDirectory(rest);
        }
      }

      wxMilliSleep(10);

      CheckInput();

      m_Dialog->GetSTCShell()->Prompt(wxEmptyString, false);

      m_Timer->Start();
    }
    else
    {
      wxLogStatus("Process is not running");
    }
    break;

  case ID_SHELL_COMMAND_STOP:
    if (IsRunning())
    {
      Kill();
    }
    break;

  default: wxFAIL; break;
  }
}

void wxExProcess::OnTerminate(int pid, int status)
{
  m_Timer->Stop();

  wxLogStatus(_("Ready"));
  wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, ID_TERMINATED_PROCESS);
  wxPostEvent(wxTheApp->GetTopWindow(), event);

  // Collect remaining input.
  CheckInput();
}

void wxExProcess::OnTimer(wxTimerEvent& event)
{
  CheckInput();
}

#if wxUSE_GUI
void wxExProcess::ShowOutput(const wxString& caption) const
{
  if (!m_Sync)
  {
    wxLogStatus("Output only available for sync processes");
  }
  else if (!m_Error)
  {
    if (m_Dialog != NULL)
    {
      m_Dialog->GetSTC()->SetText(m_Output);
      m_Dialog->SetTitle(caption.empty() ? m_Command: caption);
      m_Dialog->Show();
    }
    else if (!m_Output.empty())
    {
      wxLogMessage(m_Output);
    }
    else
    {
      wxLogStatus("No output available");
    }
  }
  else
  {
    // Executing command failed, so no output,
    // show failing command.
    wxLogError("Could not execute: " + m_Command);
  }
}
#endif
<|endoftext|>


<commit_before>#include "ros/ros.h"
#include "geometry_msgs/Wrench.h"
#include "geometry_msgs/Pose.h"
#include <maelstrom_msgs/JoystickMotionCommand.h>
#include <string>
#include "uranus_dp/SetControlMode.h"
#include "control_mode_enum.h"

class SetpointProcessing
{
public:
    SetpointProcessing()
    {
        joystickSub = nh.subscribe("joystick_motion_command", 10, &SetpointProcessing::callback, this);
        wrenchPub   = nh.advertise<geometry_msgs::Wrench>("wrench_setpoints", 10);
        posePub     = nh.advertise<geometry_msgs::Pose>("pose_setpoints", 10);
        modeClient  = nh.serviceClient<uranus_dp::SetControlMode>("set_control_mode");

        control_mode = ControlModes::OPEN_LOOP;
    }

    // void callback(const maelstrom_msgs::DirectionalInput &msg)
    void callback(const maelstrom_msgs::JoystickMotionCommand& msg)
    {
        if (msg.control_mode != control_mode)
        {
            control_mode = static_cast<ControlMode>(msg.control_mode);
            uranus_dp::SetControlMode srv;
            srv.request.mode = control_mode;
            if (!modeClient.call(srv))
            {
                ROS_ERROR_STREAM("Failed to call service set_control_mode. New mode " << control_mode << " not activated.");
            }
        }

        if (control_mode == ControlModes::OPEN_LOOP)
        {
            ROS_INFO("setpoint_processing: Sending open loop setpoints.");
            geometry_msgs::Wrench setpoint_msg;
            // setpoint_msg.force.x  =  msg.strafe_Y * NORMALIZE_16BIT * MAX_FORCE;
            // setpoint_msg.force.y  =  msg.strafe_X * NORMALIZE_16BIT * MAX_FORCE;
            // setpoint_msg.force.z  = -msg.ascend   * NORMALIZE_09BIT * MAX_FORCE;
            // setpoint_msg.torque.x =  0;
            // setpoint_msg.torque.y =  msg.turn_Y * NORMALIZE_16BIT * MAX_TORQUE;
            // setpoint_msg.torque.z =  msg.turn_X * NORMALIZE_16BIT * MAX_TORQUE;
            setpoint_msg.force.x  = msg.forward * MAX_FORCE;
            setpoint_msg.force.y  = msg.right   * MAX_FORCE;
            setpoint_msg.force.z  = msg.down    * MAX_FORCE;
            setpoint_msg.torque.x = 0;
            setpoint_msg.torque.y = msg.tilt_up    * MAX_TORQUE;
            setpoint_msg.torque.z = msg.turn_right * MAX_TORQUE;
            wrenchPub.publish(setpoint_msg);
        }
        else if (control_mode == ControlModes::POSITION_HOLD)
        {
            ROS_INFO("setpoint_processing: Sending position hold setpoints.");
            // Todo: Actually populate the pose message with values
            geometry_msgs::Pose setpoint_msg;
            setpoint_msg.position.x    = 0;
            setpoint_msg.position.y    = 0;
            setpoint_msg.position.z    = 0;
            setpoint_msg.orientation.x = 0;
            setpoint_msg.orientation.y = 0;
            setpoint_msg.orientation.z = 0;
            setpoint_msg.orientation.w = 0;
            posePub.publish(setpoint_msg);
        }
        else
        {
            ROS_ERROR_STREAM("Invalid mode " << control_mode << " detected. Will not send setpoint message.");
        }
    }

private:
    ros::NodeHandle    nh;
    ros::Subscriber    joystickSub;
    ros::Publisher     wrenchPub;
    ros::Publisher     posePub;
    ros::ServiceClient modeClient;

    ControlMode control_mode;

    // static const double NORMALIZE_16BIT = 0.000030517578125; // Scaling from 16 bit signed int to [-1, 1]
    // static const double NORMALIZE_09BIT = 0.00390625;        // Scaling from [-255, 255] to [-1, 1]
    static const double MAX_FORCE       = 10;                // Scale forces up to [-10, 10] (Newton)
    static const double MAX_TORQUE      = 5;                 // Scale torques up to [-5, 5] (Newton meters)
};

int main(int argc, char** argv){
    ros::init(argc, argv, "setpoint_processing");
    ROS_INFO("Launching node setpoint_processing.");
    SetpointProcessing s;
    ros::spin();
    return 0;
}
<commit_msg>Remove old stuff<commit_after>#include "ros/ros.h"
#include "geometry_msgs/Wrench.h"
#include "geometry_msgs/Pose.h"
#include <maelstrom_msgs/JoystickMotionCommand.h>
#include "uranus_dp/SetControlMode.h"
#include "control_mode_enum.h"

class SetpointProcessing
{
public:
    SetpointProcessing()
    {
        joystickSub = nh.subscribe("joystick_motion_command", 10, &SetpointProcessing::callback, this);
        wrenchPub   = nh.advertise<geometry_msgs::Wrench>("wrench_setpoints", 10);
        posePub     = nh.advertise<geometry_msgs::Pose>("pose_setpoints", 10);
        modeClient  = nh.serviceClient<uranus_dp::SetControlMode>("set_control_mode");

        control_mode = ControlModes::OPEN_LOOP;
    }

    void callback(const maelstrom_msgs::JoystickMotionCommand& msg)
    {
        if (msg.control_mode != control_mode)
        {
            control_mode = static_cast<ControlMode>(msg.control_mode);
            uranus_dp::SetControlMode srv;
            srv.request.mode = control_mode;
            if (!modeClient.call(srv))
                ROS_ERROR_STREAM("Failed to call service set_control_mode. New mode " << control_mode << " not activated.");
        }

        if (control_mode == ControlModes::OPEN_LOOP)
        {
            ROS_INFO("setpoint_processing: Sending open loop setpoints.");
            geometry_msgs::Wrench setpoint_msg;
            setpoint_msg.force.x  = msg.forward * MAX_FORCE;
            setpoint_msg.force.y  = msg.right   * MAX_FORCE;
            setpoint_msg.force.z  = msg.down    * MAX_FORCE;
            setpoint_msg.torque.x = 0;
            setpoint_msg.torque.y = msg.tilt_up    * MAX_TORQUE;
            setpoint_msg.torque.z = msg.turn_right * MAX_TORQUE;
            wrenchPub.publish(setpoint_msg);
        }
        else if (control_mode == ControlModes::POSITION_HOLD)
        {
            ROS_INFO("setpoint_processing: Sending position hold setpoints.");
            // Todo: Actually populate the pose message with values
            geometry_msgs::Pose setpoint_msg;
            setpoint_msg.position.x    = 0;
            setpoint_msg.position.y    = 0;
            setpoint_msg.position.z    = 0;
            setpoint_msg.orientation.x = 0;
            setpoint_msg.orientation.y = 0;
            setpoint_msg.orientation.z = 0;
            setpoint_msg.orientation.w = 0;
            posePub.publish(setpoint_msg);
        }
        else
        {
            ROS_ERROR_STREAM("Invalid mode " << control_mode << " detected. Will not send setpoint message.");
        }
    }

private:
    ros::NodeHandle    nh;
    ros::Subscriber    joystickSub;
    ros::Publisher     wrenchPub;
    ros::Publisher     posePub;
    ros::ServiceClient modeClient;

    ControlMode control_mode;

    static const double MAX_FORCE  = 10;                // Scale forces up to [-10, 10] (Newton)
    static const double MAX_TORQUE = 5;                 // Scale torques up to [-5, 5] (Newton meters)
};

int main(int argc, char** argv){
    ros::init(argc, argv, "setpoint_processing");
    ROS_INFO("Launching node setpoint_processing.");
    SetpointProcessing s;
    ros::spin();
    return 0;
}
<|endoftext|>