<commit_before>
#include "physics/geopotential.hpp"

#include "astronomy/fortran_astrodynamics_toolkit.hpp"
#include "astronomy/frames.hpp"
#include "geometry/frame.hpp"
#include "geometry/named_quantities.hpp"
#include "gtest/gtest.h"
#include "numerics/legendre.hpp"
#include "physics/solar_system.hpp"
#include "quantities/parser.hpp"
#include "quantities/quantities.hpp"
#include "quantities/si.hpp"
#include "serialization/geometry.pb.h"
#include "testing_utilities/almost_equals.hpp"
#include "testing_utilities/componentwise.hpp"
#include "testing_utilities/is_near.hpp"
#include "testing_utilities/numerics.hpp"
#include "testing_utilities/vanishes_before.hpp"

namespace principia {
namespace physics {
namespace internal_geopotential {

using astronomy::ICRS;
using astronomy::ITRS;
using geometry::Frame;
using numerics::LegendreNormalizationFactor;
using physics::SolarSystem;
using quantities::Angle;
using quantities::AngularFrequency;
using quantities::Degree2SphericalHarmonicCoefficient;
using quantities::Degree3SphericalHarmonicCoefficient;
using quantities::ParseQuantity;
using quantities::Pow;
using quantities::SIUnit;
using quantities::si::Degree;
using quantities::si::Metre;
using quantities::si::Radian;
using quantities::si::Second;
using testing_utilities::AlmostEquals;
using testing_utilities::Componentwise;
using testing_utilities::IsNear;
using testing_utilities::RelativeError;
using testing_utilities::VanishesBefore;
using ::testing::An;
using ::testing::Gt;
using ::testing::Lt;

class GeopotentialTest : public ::testing::Test {
 protected:
  using World = Frame<serialization::Frame::TestTag,
                      serialization::Frame::TEST, true>;

  GeopotentialTest()
      : massive_body_parameters_(17 * SIUnit<GravitationalParameter>()),
        rotating_body_parameters_(1 * Metre,
                                  3 * Radian,
                                  Instant() + 4 * Second,
                                  angular_frequency_,
                                  right_ascension_of_pole_,
                                  declination_of_pole_) {}

  template<typename Frame>
  Vector<Quotient<Acceleration, GravitationalParameter>, Frame>
  SphericalHarmonicsAcceleration(Geopotential<Frame> const& geopotential,
                                 Instant const& t,
                                 Displacement<Frame> const& r) {
    auto const r² = r.Norm²();
    auto const one_over_r³ = 1.0 / (r² * r.Norm());
    return geopotential.SphericalHarmonicsAcceleration(t, r, r², one_over_r³);
  }

  template<typename Frame>
  Vector<Quotient<Acceleration, GravitationalParameter>, Frame>
  GeneralSphericalHarmonicsAcceleration(Geopotential<Frame> const& geopotential,
                                        Instant const& t,
                                        Displacement<Frame> const& r) {
    auto const r² = r.Norm²();
    auto const one_over_r³ = 1.0 / (r² * r.Norm());
    return geopotential.GeneralSphericalHarmonicsAcceleration(
               t, r, r², one_over_r³);
  }

  // The axis of rotation is along the z axis for ease of testing.
  AngularFrequency const angular_frequency_ = -1.5 * Radian / Second;
  Angle const right_ascension_of_pole_ = 0 * Degree;
  Angle const declination_of_pole_ = 90 * Degree;

  MassiveBody::Parameters const massive_body_parameters_;
  RotatingBody<World>::Parameters const rotating_body_parameters_;
};

TEST_F(GeopotentialTest, J2) {
  OblateBody<World> const body =
      OblateBody<World>(massive_body_parameters_,
                        rotating_body_parameters_,
                        OblateBody<World>::Parameters(/*j2=*/6, 1 * Metre));
  Geopotential<World> const geopotential(&body);

  // The acceleration at a point located on the axis is along the axis.
  {
    auto const acceleration = SphericalHarmonicsAcceleration(
        geopotential,
        Instant(),
        Displacement<World>({0 * Metre, 0 * Metre, 10 * Metre}));
    EXPECT_THAT(acceleration,
                Componentwise(VanishesBefore(1 * Pow<-2>(Metre), 0),
                              VanishesBefore(1 * Pow<-2>(Metre), 0),
                              An<Exponentiation<Length, -2>>()));
  }

  // The acceleration at a point located in the equatorial plane is directed to
  // the centre.
  {
    auto const acceleration = SphericalHarmonicsAcceleration(
        geopotential,
        Instant(),
        Displacement<World>({30 * Metre, 40 * Metre, 0 * Metre}));
    EXPECT_THAT(acceleration.coordinates().x / acceleration.coordinates().y,
                AlmostEquals(0.75, 0));
    EXPECT_THAT(acceleration.coordinates().z,
                VanishesBefore(1 * Pow<-2>(Metre), 0));
  }

  // The acceleration at a random point nudges the overall force away from the
  // centre and towards the equatorial plane.
  {
    auto const acceleration = SphericalHarmonicsAcceleration(
        geopotential,
        Instant(),
        Displacement<World>({1e2 * Metre, 0 * Metre, 1e2 * Metre}));
    EXPECT_THAT(acceleration.coordinates().x, Gt(0 * Pow<-2>(Metre)));
    EXPECT_THAT(acceleration.coordinates().z, Lt(0 * Pow<-2>(Metre)));
  }
}

TEST_F(GeopotentialTest, C22S22) {
  serialization::OblateBody::Geopotential message;
  {
    auto* const degree2 = message.add_row();
    degree2->set_degree(2);
    auto* const order0 = degree2->add_column();
    order0->set_order(0);
    order0->set_cos(-6 / LegendreNormalizationFactor(2, 0));
    order0->set_sin(0);
    auto* const order2 = degree2->add_column();
    order2->set_order(2);
    order2->set_cos(10 / LegendreNormalizationFactor(2, 2));
    order2->set_sin(-13 / LegendreNormalizationFactor(2, 2));
  }
  OblateBody<World> const body =
      OblateBody<World>(massive_body_parameters_,
                        rotating_body_parameters_,
                        OblateBody<World>::Parameters::ReadFromMessage(
                            message, 1 * Metre));
  Geopotential<World> const geopotential(&body);

  // The acceleration at a point located on the axis is along the axis for the
  // (2, 2) harmonics.
  {
    auto const acceleration = GeneralSphericalHarmonicsAcceleration(
        geopotential,
        Instant(),
        Displacement<World>({0 * Metre, 0 * Metre, 10 * Metre}));
    EXPECT_THAT(acceleration,
                Componentwise(VanishesBefore(1 * Pow<-2>(Metre), 0),
                              VanishesBefore(1 * Pow<-2>(Metre), 0),
                              An<Exponentiation<Length, -2>>()));
  }

  // The acceleration at a point located in the equatorial plane is in the plane
  // but not directed to the centre.
  {
    auto const acceleration = GeneralSphericalHarmonicsAcceleration(
        geopotential,
        Instant(),
        Displacement<World>({30 * Metre, 40 * Metre, 0 * Metre}));
    EXPECT_THAT(acceleration.coordinates().x / acceleration.coordinates().y,
                Not(IsNear(0.75)));
    EXPECT_THAT(acceleration.coordinates().z,
                VanishesBefore(1 * Pow<-2>(Metre), 0));
  }
}

TEST_F(GeopotentialTest, J3) {
  serialization::OblateBody::Geopotential message;
  {
    auto* const degree2 = message.add_row();
    degree2->set_degree(2);
    auto* const order0 = degree2->add_column();
    order0->set_order(0);
    order0->set_cos(-6 / LegendreNormalizationFactor(2, 0));
    order0->set_sin(0);
    auto* const order2 = degree2->add_column();
    order2->set_order(2);
    order2->set_cos(1e-20 / LegendreNormalizationFactor(2, 2));
    order2->set_sin(1e-20 / LegendreNormalizationFactor(2, 2));
  }
  {
    auto* const degree3 = message.add_row();
    degree3->set_degree(3);
    auto* const order0 = degree3->add_column();
    order0->set_order(0);
    order0->set_cos(5 / LegendreNormalizationFactor(3, 0));
  }
  OblateBody<World> const body =
      OblateBody<World>(massive_body_parameters_,
                        rotating_body_parameters_,
                        OblateBody<World>::Parameters::ReadFromMessage(
                            message, 1 * Metre));
  Geopotential<World> const geopotential(&body);

  // The acceleration at a point located on the axis is along the axis.
  {
    auto const acceleration = GeneralSphericalHarmonicsAcceleration(
        geopotential,
        Instant(),
        Displacement<World>({0 * Metre, 0 * Metre, 10 * Metre}));
    EXPECT_THAT(acceleration,
                Componentwise(VanishesBefore(1 * Pow<-2>(Metre), 0),
                              VanishesBefore(1 * Pow<-2>(Metre), 0),
                              An<Exponentiation<Length, -2>>()));
  }

  // The acceleration at a point located in the equatorial plane points towards
  // the north, as it does on Earth (I think).
  // TODO(phl): I don't know what I think anymore.  Oh the humanity!
  {
    auto const acceleration = GeneralSphericalHarmonicsAcceleration(
        geopotential,
        Instant(),
        Displacement<World>({30 * Metre, 40 * Metre, 0 * Metre}));
    EXPECT_THAT(acceleration.coordinates().x / acceleration.coordinates().y,
                AlmostEquals(0.75, 2));
    EXPECT_THAT(acceleration.coordinates().z,
                Not(VanishesBefore(1 * Pow<-2>(Metre), 0)));
    EXPECT_THAT(acceleration.coordinates().z, Lt(0 * Pow<-2>(Metre)));
  }
}

TEST_F(GeopotentialTest, TestVector) {
  SolarSystem<ICRS> solar_system_2000(
            SOLUTION_DIR / "astronomy" / "sol_gravity_model.proto.txt",
            SOLUTION_DIR / "astronomy" /
                "sol_initial_state_jd_2451545_000000000.proto.txt");
  auto earth_message = solar_system_2000.gravity_model_message("Earth");
  earth_message.mutable_geopotential()->set_max_degree(9);

  auto const earth_μ = solar_system_2000.gravitational_parameter("Earth");
  auto const earth_reference_radius =
      ParseQuantity<Length>(earth_message.reference_radius());
  MassiveBody::Parameters const massive_body_parameters(earth_μ);
  RotatingBody<ICRS>::Parameters rotating_body_parameters(
      /*mean_radius=*/solar_system_2000.mean_radius("Earth"),
      /*reference_angle=*/0 * Radian,
      /*reference_instant=*/Instant(),
      /*angular_frequency=*/1e-20 * Radian / Second,
      right_ascension_of_pole_,
      declination_of_pole_);
  OblateBody<ICRS> const earth = OblateBody<ICRS>(
      massive_body_parameters,
      rotating_body_parameters,
      OblateBody<ICRS>::Parameters::ReadFromMessage(
          earth_message.geopotential(), earth_reference_radius));
  Geopotential<ICRS> const geopotential(&earth);

  // This test vector is from Kuga & Carrara, "Fortran- and C-codes for higher
  // order and degree geopotential computation",
  // www.dem.inpe.br/~hkk/software/high_geopot.html.  They use EGM2008, so their
  // actual results are expected to differ a bit from ours.
  Displacement<ITRS> const displacement(
      {6000000 * Metre, -4000000 * Metre, 5000000 * Metre});
  Vector<Acceleration, ITRS> const expected_acceleration(
      {-3.5377058876337 * Metre / Second / Second,
       2.3585194144421 * Metre / Second / Second,
       -2.9531441870790 * Metre / Second / Second});

  Vector<Acceleration, ITRS> actual_acceleration_cpp;
  Vector<Acceleration, ITRS> actual_acceleration_f90;

  {
    Displacement<ICRS> const icrs_displacement =
        earth.FromSurfaceFrame<ITRS>(Instant())(
            Displacement<ITRS>(displacement));
    auto const icrs_acceleration =
        earth_μ * (GeneralSphericalHarmonicsAcceleration(
                       geopotential, Instant(), icrs_displacement) -
                   icrs_displacement / Pow<3>(icrs_displacement.Norm()));
    actual_acceleration_cpp =
        earth.ToSurfaceFrame<ITRS>(Instant())(icrs_acceleration);
    EXPECT_THAT(RelativeError(actual_acceleration_cpp, expected_acceleration),
                IsNear(1.3e-8));
  }
  {
    double mu = earth_μ / SIUnit<GravitationalParameter>();
    double rbar = earth_reference_radius / Metre;
    numerics::FixedMatrix<double, 10, 10> cnm;
    numerics::FixedMatrix<double, 10, 10> snm;
    for (int n = 0; n <= 9; ++n) {
      for (int m = 0; m <= n; ++m) {
        cnm[n][m] = earth.cos()[n][m] * LegendreNormalizationFactor(n, m);
        snm[n][m] = earth.sin()[n][m] * LegendreNormalizationFactor(n, m);
      }
    }
    actual_acceleration_f90 = Vector<Acceleration, ITRS>(
        SIUnit<Acceleration>() *
        astronomy::fortran_astrodynamics_toolkit::
            ComputeGravityAccelerationLear<9, 9>(
                displacement.coordinates() / Metre, mu, rbar, cnm, snm));
    EXPECT_THAT(RelativeError(actual_acceleration_f90, expected_acceleration),
                IsNear(1.3e-8));
  }
  EXPECT_THAT(actual_acceleration_cpp,
              AlmostEquals(actual_acceleration_f90, 4));
}

}  // namespace internal_geopotential
}  // namespace physics
}  // namespace principia
<commit_msg>Test compilation error.<commit_after>
#include "physics/geopotential.hpp"

#include "astronomy/fortran_astrodynamics_toolkit.hpp"
#include "astronomy/frames.hpp"
#include "geometry/frame.hpp"
#include "geometry/named_quantities.hpp"
#include "gtest/gtest.h"
#include "numerics/legendre.hpp"
#include "physics/solar_system.hpp"
#include "quantities/parser.hpp"
#include "quantities/quantities.hpp"
#include "quantities/si.hpp"
#include "serialization/geometry.pb.h"
#include "testing_utilities/almost_equals.hpp"
#include "testing_utilities/componentwise.hpp"
#include "testing_utilities/is_near.hpp"
#include "testing_utilities/numerics.hpp"
#include "testing_utilities/vanishes_before.hpp"

namespace principia {
namespace physics {
namespace internal_geopotential {

using astronomy::ICRS;
using astronomy::ITRS;
using geometry::Frame;
using numerics::LegendreNormalizationFactor;
using physics::SolarSystem;
using quantities::Angle;
using quantities::AngularFrequency;
using quantities::Degree2SphericalHarmonicCoefficient;
using quantities::Degree3SphericalHarmonicCoefficient;
using quantities::ParseQuantity;
using quantities::Pow;
using quantities::SIUnit;
using quantities::si::Degree;
using quantities::si::Metre;
using quantities::si::Radian;
using quantities::si::Second;
using testing_utilities::AlmostEquals;
using testing_utilities::Componentwise;
using testing_utilities::IsNear;
using testing_utilities::RelativeError;
using testing_utilities::VanishesBefore;
using ::testing::An;
using ::testing::Gt;
using ::testing::Lt;

class GeopotentialTest : public ::testing::Test {
 protected:
  using World = Frame<serialization::Frame::TestTag,
                      serialization::Frame::TEST, true>;

  GeopotentialTest()
      : massive_body_parameters_(17 * SIUnit<GravitationalParameter>()),
        rotating_body_parameters_(1 * Metre,
                                  3 * Radian,
                                  Instant() + 4 * Second,
                                  angular_frequency_,
                                  right_ascension_of_pole_,
                                  declination_of_pole_) {}

  template<typename Frame>
  Vector<Quotient<Acceleration, GravitationalParameter>, Frame>
  SphericalHarmonicsAcceleration(Geopotential<Frame> const& geopotential,
                                 Instant const& t,
                                 Displacement<Frame> const& r) {
    auto const r² = r.Norm²();
    auto const one_over_r³ = 1.0 / (r² * r.Norm());
    return geopotential.SphericalHarmonicsAcceleration(t, r, r², one_over_r³);
  }

  template<typename Frame>
  Vector<Quotient<Acceleration, GravitationalParameter>, Frame>
  GeneralSphericalHarmonicsAcceleration(Geopotential<Frame> const& geopotential,
                                        Instant const& t,
                                        Displacement<Frame> const& r) {
    auto const r² = r.Norm²();
    return geopotential.GeneralSphericalHarmonicsAcceleration(t, r, r²);
  }

  // The axis of rotation is along the z axis for ease of testing.
  AngularFrequency const angular_frequency_ = -1.5 * Radian / Second;
  Angle const right_ascension_of_pole_ = 0 * Degree;
  Angle const declination_of_pole_ = 90 * Degree;

  MassiveBody::Parameters const massive_body_parameters_;
  RotatingBody<World>::Parameters const rotating_body_parameters_;
};

TEST_F(GeopotentialTest, J2) {
  OblateBody<World> const body =
      OblateBody<World>(massive_body_parameters_,
                        rotating_body_parameters_,
                        OblateBody<World>::Parameters(/*j2=*/6, 1 * Metre));
  Geopotential<World> const geopotential(&body);

  // The acceleration at a point located on the axis is along the axis.
  {
    auto const acceleration = SphericalHarmonicsAcceleration(
        geopotential,
        Instant(),
        Displacement<World>({0 * Metre, 0 * Metre, 10 * Metre}));
    EXPECT_THAT(acceleration,
                Componentwise(VanishesBefore(1 * Pow<-2>(Metre), 0),
                              VanishesBefore(1 * Pow<-2>(Metre), 0),
                              An<Exponentiation<Length, -2>>()));
  }

  // The acceleration at a point located in the equatorial plane is directed to
  // the centre.
  {
    auto const acceleration = SphericalHarmonicsAcceleration(
        geopotential,
        Instant(),
        Displacement<World>({30 * Metre, 40 * Metre, 0 * Metre}));
    EXPECT_THAT(acceleration.coordinates().x / acceleration.coordinates().y,
                AlmostEquals(0.75, 0));
    EXPECT_THAT(acceleration.coordinates().z,
                VanishesBefore(1 * Pow<-2>(Metre), 0));
  }

  // The acceleration at a random point nudges the overall force away from the
  // centre and towards the equatorial plane.
  {
    auto const acceleration = SphericalHarmonicsAcceleration(
        geopotential,
        Instant(),
        Displacement<World>({1e2 * Metre, 0 * Metre, 1e2 * Metre}));
    EXPECT_THAT(acceleration.coordinates().x, Gt(0 * Pow<-2>(Metre)));
    EXPECT_THAT(acceleration.coordinates().z, Lt(0 * Pow<-2>(Metre)));
  }
}

TEST_F(GeopotentialTest, C22S22) {
  serialization::OblateBody::Geopotential message;
  {
    auto* const degree2 = message.add_row();
    degree2->set_degree(2);
    auto* const order0 = degree2->add_column();
    order0->set_order(0);
    order0->set_cos(-6 / LegendreNormalizationFactor(2, 0));
    order0->set_sin(0);
    auto* const order2 = degree2->add_column();
    order2->set_order(2);
    order2->set_cos(10 / LegendreNormalizationFactor(2, 2));
    order2->set_sin(-13 / LegendreNormalizationFactor(2, 2));
  }
  OblateBody<World> const body =
      OblateBody<World>(massive_body_parameters_,
                        rotating_body_parameters_,
                        OblateBody<World>::Parameters::ReadFromMessage(
                            message, 1 * Metre));
  Geopotential<World> const geopotential(&body);

  // The acceleration at a point located on the axis is along the axis for the
  // (2, 2) harmonics.
  {
    auto const acceleration = GeneralSphericalHarmonicsAcceleration(
        geopotential,
        Instant(),
        Displacement<World>({0 * Metre, 0 * Metre, 10 * Metre}));
    EXPECT_THAT(acceleration,
                Componentwise(VanishesBefore(1 * Pow<-2>(Metre), 0),
                              VanishesBefore(1 * Pow<-2>(Metre), 0),
                              An<Exponentiation<Length, -2>>()));
  }

  // The acceleration at a point located in the equatorial plane is in the plane
  // but not directed to the centre.
  {
    auto const acceleration = GeneralSphericalHarmonicsAcceleration(
        geopotential,
        Instant(),
        Displacement<World>({30 * Metre, 40 * Metre, 0 * Metre}));
    EXPECT_THAT(acceleration.coordinates().x / acceleration.coordinates().y,
                Not(IsNear(0.75)));
    EXPECT_THAT(acceleration.coordinates().z,
                VanishesBefore(1 * Pow<-2>(Metre), 0));
  }
}

TEST_F(GeopotentialTest, J3) {
  serialization::OblateBody::Geopotential message;
  {
    auto* const degree2 = message.add_row();
    degree2->set_degree(2);
    auto* const order0 = degree2->add_column();
    order0->set_order(0);
    order0->set_cos(-6 / LegendreNormalizationFactor(2, 0));
    order0->set_sin(0);
    auto* const order2 = degree2->add_column();
    order2->set_order(2);
    order2->set_cos(1e-20 / LegendreNormalizationFactor(2, 2));
    order2->set_sin(1e-20 / LegendreNormalizationFactor(2, 2));
  }
  {
    auto* const degree3 = message.add_row();
    degree3->set_degree(3);
    auto* const order0 = degree3->add_column();
    order0->set_order(0);
    order0->set_cos(5 / LegendreNormalizationFactor(3, 0));
  }
  OblateBody<World> const body =
      OblateBody<World>(massive_body_parameters_,
                        rotating_body_parameters_,
                        OblateBody<World>::Parameters::ReadFromMessage(
                            message, 1 * Metre));
  Geopotential<World> const geopotential(&body);

  // The acceleration at a point located on the axis is along the axis.
  {
    auto const acceleration = GeneralSphericalHarmonicsAcceleration(
        geopotential,
        Instant(),
        Displacement<World>({0 * Metre, 0 * Metre, 10 * Metre}));
    EXPECT_THAT(acceleration,
                Componentwise(VanishesBefore(1 * Pow<-2>(Metre), 0),
                              VanishesBefore(1 * Pow<-2>(Metre), 0),
                              An<Exponentiation<Length, -2>>()));
  }

  // The acceleration at a point located in the equatorial plane points towards
  // the north, as it does on Earth (I think).
  // TODO(phl): I don't know what I think anymore.  Oh the humanity!
  {
    auto const acceleration = GeneralSphericalHarmonicsAcceleration(
        geopotential,
        Instant(),
        Displacement<World>({30 * Metre, 40 * Metre, 0 * Metre}));
    EXPECT_THAT(acceleration.coordinates().x / acceleration.coordinates().y,
                AlmostEquals(0.75, 2));
    EXPECT_THAT(acceleration.coordinates().z,
                Not(VanishesBefore(1 * Pow<-2>(Metre), 0)));
    EXPECT_THAT(acceleration.coordinates().z, Lt(0 * Pow<-2>(Metre)));
  }
}

TEST_F(GeopotentialTest, TestVector) {
  SolarSystem<ICRS> solar_system_2000(
            SOLUTION_DIR / "astronomy" / "sol_gravity_model.proto.txt",
            SOLUTION_DIR / "astronomy" /
                "sol_initial_state_jd_2451545_000000000.proto.txt");
  auto earth_message = solar_system_2000.gravity_model_message("Earth");
  earth_message.mutable_geopotential()->set_max_degree(9);

  auto const earth_μ = solar_system_2000.gravitational_parameter("Earth");
  auto const earth_reference_radius =
      ParseQuantity<Length>(earth_message.reference_radius());
  MassiveBody::Parameters const massive_body_parameters(earth_μ);
  RotatingBody<ICRS>::Parameters rotating_body_parameters(
      /*mean_radius=*/solar_system_2000.mean_radius("Earth"),
      /*reference_angle=*/0 * Radian,
      /*reference_instant=*/Instant(),
      /*angular_frequency=*/1e-20 * Radian / Second,
      right_ascension_of_pole_,
      declination_of_pole_);
  OblateBody<ICRS> const earth = OblateBody<ICRS>(
      massive_body_parameters,
      rotating_body_parameters,
      OblateBody<ICRS>::Parameters::ReadFromMessage(
          earth_message.geopotential(), earth_reference_radius));
  Geopotential<ICRS> const geopotential(&earth);

  // This test vector is from Kuga & Carrara, "Fortran- and C-codes for higher
  // order and degree geopotential computation",
  // www.dem.inpe.br/~hkk/software/high_geopot.html.  They use EGM2008, so their
  // actual results are expected to differ a bit from ours.
  Displacement<ITRS> const displacement(
      {6000000 * Metre, -4000000 * Metre, 5000000 * Metre});
  Vector<Acceleration, ITRS> const expected_acceleration(
      {-3.5377058876337 * Metre / Second / Second,
       2.3585194144421 * Metre / Second / Second,
       -2.9531441870790 * Metre / Second / Second});

  Vector<Acceleration, ITRS> actual_acceleration_cpp;
  Vector<Acceleration, ITRS> actual_acceleration_f90;

  {
    Displacement<ICRS> const icrs_displacement =
        earth.FromSurfaceFrame<ITRS>(Instant())(
            Displacement<ITRS>(displacement));
    auto const icrs_acceleration =
        earth_μ * (GeneralSphericalHarmonicsAcceleration(
                       geopotential, Instant(), icrs_displacement) -
                   icrs_displacement / Pow<3>(icrs_displacement.Norm()));
    actual_acceleration_cpp =
        earth.ToSurfaceFrame<ITRS>(Instant())(icrs_acceleration);
    EXPECT_THAT(RelativeError(actual_acceleration_cpp, expected_acceleration),
                IsNear(1.3e-8));
  }
  {
    double mu = earth_μ / SIUnit<GravitationalParameter>();
    double rbar = earth_reference_radius / Metre;
    numerics::FixedMatrix<double, 10, 10> cnm;
    numerics::FixedMatrix<double, 10, 10> snm;
    for (int n = 0; n <= 9; ++n) {
      for (int m = 0; m <= n; ++m) {
        cnm[n][m] = earth.cos()[n][m] * LegendreNormalizationFactor(n, m);
        snm[n][m] = earth.sin()[n][m] * LegendreNormalizationFactor(n, m);
      }
    }
    actual_acceleration_f90 = Vector<Acceleration, ITRS>(
        SIUnit<Acceleration>() *
        astronomy::fortran_astrodynamics_toolkit::
            ComputeGravityAccelerationLear<9, 9>(
                displacement.coordinates() / Metre, mu, rbar, cnm, snm));
    EXPECT_THAT(RelativeError(actual_acceleration_f90, expected_acceleration),
                IsNear(1.3e-8));
  }
  EXPECT_THAT(actual_acceleration_cpp,
              AlmostEquals(actual_acceleration_f90, 4));
}

}  // namespace internal_geopotential
}  // namespace physics
}  // namespace principia
<|endoftext|>


<commit_before>/*
 * This file is part of telepathy-accounts-kcm
 *
 * Copyright (C) 2009 Collabora Ltd. <http://www.collabora.co.uk/>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "server-settings-widget.h"

#include "ui_server-settings-widget.h"

#include <KCMTelepathyAccounts/ProtocolParameterValue>

#include <KDebug>
#include <KMessageBox>

class ServerSettingsWidget::Private
{
public:
    Private()
            : ui(0)
    {
        kDebug();
    }

    Ui::ServerSettingsWidget *ui;
};

ServerSettingsWidget::ServerSettingsWidget(ParameterEditModel *model,
                                                     QWidget *parent)
 : AbstractAccountParametersWidget(model, parent),
   d(new Private)
{
    kDebug();

    // Set up the UI.
    d->ui = new Ui::ServerSettingsWidget;
    d->ui->setupUi(this);

    handleParameter("server", QVariant::String, d->ui->serverLineEdit, d->ui->serverLabel);
    handleParameter("port", QVariant::UInt, d->ui->portSpinBox, d->ui->portLabel);
    handleParameter("keepalive-interval", QVariant::UInt, d->ui->keepaliveIntervalSpinBox, 0);
    handleParameter("low-bandwith", QVariant::Bool, d->ui->lowBandwidthCheckBox, 0);
    handleParameter("require-encryption", QVariant::Bool, d->ui->requireEncryptionCheckBox, 0);
    handleParameter("ignore-ssl-errors", QVariant::Bool, d->ui->ignoreSslErrorsCheckBox, 0);
    handleParameter("old-ssl", QVariant::Bool, d->ui->oldSslCheckBox, 0);
}

ServerSettingsWidget::~ServerSettingsWidget()
{
    kDebug();

    delete d;
}

#include "server-settings-widget.moc"

<commit_msg>Low bandwidth parameter got hidden<commit_after>/*
 * This file is part of telepathy-accounts-kcm
 *
 * Copyright (C) 2009 Collabora Ltd. <http://www.collabora.co.uk/>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "server-settings-widget.h"

#include "ui_server-settings-widget.h"

#include <KCMTelepathyAccounts/ProtocolParameterValue>

#include <KDebug>
#include <KMessageBox>

class ServerSettingsWidget::Private
{
public:
    Private()
            : ui(0)
    {
        kDebug();
    }

    Ui::ServerSettingsWidget *ui;
};

ServerSettingsWidget::ServerSettingsWidget(ParameterEditModel *model,
                                                     QWidget *parent)
 : AbstractAccountParametersWidget(model, parent),
   d(new Private)
{
    kDebug();

    // Set up the UI.
    d->ui = new Ui::ServerSettingsWidget;
    d->ui->setupUi(this);

    handleParameter("server", QVariant::String, d->ui->serverLineEdit, d->ui->serverLabel);
    handleParameter("port", QVariant::UInt, d->ui->portSpinBox, d->ui->portLabel);
    handleParameter("keepalive-interval", QVariant::UInt, d->ui->keepaliveIntervalSpinBox, 0);
    handleParameter("low-bandwidth", QVariant::Bool, d->ui->lowBandwidthCheckBox, 0);
    handleParameter("require-encryption", QVariant::Bool, d->ui->requireEncryptionCheckBox, 0);
    handleParameter("ignore-ssl-errors", QVariant::Bool, d->ui->ignoreSslErrorsCheckBox, 0);
    handleParameter("old-ssl", QVariant::Bool, d->ui->oldSslCheckBox, 0);
}

ServerSettingsWidget::~ServerSettingsWidget()
{
    kDebug();

    delete d;
}

#include "server-settings-widget.moc"

<|endoftext|>


<commit_before>#include <Arduino.h>
#include <stdio.h>

#define PIN_OUT_EN 9

#define PIN_OUT1 8
#define PIN_OUT2 7

#define PIN_POT_PULSE 3
#define PIN_POT_TIMING 4

#define PULSE_WIDTH_MIN_MS 10
#define PULSE_WIDTH_MAX_MS 100

#define TIMING_DELTA_MIN_MS 100
#define TIMING_DELTA_MAX_MS 2000

#define POT_MIN_VAL 10
#define POT_MAX_VAL 1000

#define MSG_MAX_LEN 20

char g_msg[MSG_MAX_LEN] = {'\0'};
int g_pot_in = 0;

int g_pulse_ms = 30;
int g_dt_ms = 1000;

inline int scale_int(const int in_min, const int in_max,
              const int out_min, const int out_max,
              int in) {

    if (in < in_min) {
        in = in_min;
    } else if  (in > in_max) {
        in = in_max;
    }
    float scale = ((float) (in - in_min)) / ((float) (in_max - in_min));
    return ((int) ((float) (out_max - out_min)) * scale) + out_min;

}

void loop() {

    // g_ef = digitalRead(PIN_IN_EF);   // read ef
    digitalWrite(PIN_OUT1, LOW);   // Set the LED on
    delay(g_pulse_ms);              // Wait
    digitalWrite(PIN_OUT1, HIGH);   // Set the LED on

    Serial.println("Switch state 1");
    // if (!g_ef) {
    //     Serial.println("EF Error!");
    // }
    delay(g_dt_ms);              // Wait for three seconds

    // g_ef = digitalRead(PIN_IN_EF);   // read ef
    digitalWrite(PIN_OUT2, LOW);   // Set the LED on
    delay(g_pulse_ms);              // Wait for three seconds
    digitalWrite(PIN_OUT2, HIGH);   // Set the LED on

    // snprintf(g_msg, MSG_MAX_LEN, "EF code: %d", g_val);
    // Serial.println(g_msg);
    Serial.println("Switch state 2");
    // if (!g_ef) {
    //     Serial.println("EF Error!");
    // }
    delay(g_dt_ms);              // Wait for three seconds

    // scale potentiometers
    g_pot_in = analogRead(PIN_POT_PULSE);    // read the value from the sensor
    g_pulse_ms = scale_int(POT_MIN_VAL, POT_MAX_VAL,
                           PULSE_WIDTH_MIN_MS, PULSE_WIDTH_MAX_MS,
                           g_pot_in);

    g_pot_in = analogRead(PIN_POT_TIMING);    // read the value from the sensor
    g_dt_ms = scale_int(POT_MIN_VAL, POT_MAX_VAL,
                        TIMING_DELTA_MIN_MS, TIMING_DELTA_MAX_MS,
                        g_pot_in);

    // if (g_pot_in < POT_MIN_VAL) {
    //     g_pot_in = POT_MIN_VAL;
    // } else if  (g_pot_in > POT_MAX_VAL) {
    //     g_pot_in = POT_MAX_VAL;
    // }
    // g_pulse_scale = ((float) (g_pot_in - POT_MIN_VAL)) / ((float) (POT_MAX_VAL - POT_MIN_VAL));
    // g_pulse_ms = ((int) ((float) (PULSE_WIDTH_MAX_MS - PULSE_WIDTH_MIN_MS)) * g_pulse_scale)
    //              + PULSE_WIDTH_MIN_MS;

    snprintf(g_msg, MSG_MAX_LEN, "Pot: %d", g_pot_in);
    Serial.println(g_msg);
    snprintf(g_msg, MSG_MAX_LEN, "Pulse: %d", g_pulse_ms);
    Serial.println(g_msg);

}

int main(void)
{
    // Mandatory init
    init();

    Serial.begin(115200);

    // Pin 13 has an LED connected on most Arduino boards
    pinMode(PIN_OUT1, OUTPUT);
    pinMode(PIN_OUT2, OUTPUT);
    pinMode(PIN_OUT_EN, OUTPUT);

    digitalWrite(PIN_OUT2, HIGH);   // Set the LED on
    digitalWrite(PIN_OUT1, HIGH);   // Set the LED on
    digitalWrite(PIN_OUT_EN, HIGH);

    while (true)
        loop();

    return 0;
}
<commit_msg>revert to blink<commit_after>#include <Arduino.h>

void loop() {
    Serial.println("LED on");
    digitalWrite(13, HIGH);   // Set the LED on
    delay(3000);              // Wait for three seconds

    Serial.println("LED off");
    digitalWrite(13, LOW);    // Set the LED off
    delay(3000);              // Wait for three seconds
}

int main(void)
{
    // Mandatory init
    init();

    Serial.begin(115200);

    // Pin 13 has an LED connected on most Arduino boards
    pinMode(13, OUTPUT);

    while (true)
        loop();

    return 0;
}
<|endoftext|>


<commit_before>/*
 * IceWM
 *
 * Copyright (C) 1998-2001 Marko Macek
 */

#include "config.h"

#ifndef NO_CONFIGURE_MENUS

#include "obj.h"
#include "objmenu.h"
#include "browse.h"
#include "wmmgr.h"
#include "wmprog.h"
#include "yicon.h"
#include "sysdep.h"
#include "base.h"
#include "udir.h"

BrowseMenu::BrowseMenu(
    IApp *app,
    YSMListener *smActionListener,
    YActionListener *wmActionListener,
    upath path,
    YWindow *parent): ObjectMenu(wmActionListener, parent)
{
    this->app = app;
    this->smActionListener = smActionListener;
    fPath = path;
    fModTime = 0;
}

BrowseMenu::~BrowseMenu() {
}

void BrowseMenu::updatePopup() {
    struct stat sb;

    if (fPath.stat(&sb) != 0)
        removeAll();
    else if (sb.st_mtime > fModTime) {
        fModTime = sb.st_mtime;

        removeAll();

#ifndef LITE
        ref<YIcon> file = YIcon::getIcon("file");
        ref<YIcon> folder = YIcon::getIcon("folder");
#endif

        for (adir dir(fPath.string()); dir.next(); ) {
            ustring entry(dir.entry());
            upath npath(fPath + entry);

            YMenu *sub = 0;
            if (npath.dirExists())
                sub = new BrowseMenu(app, smActionListener, wmActionListener, npath);

            DFile *pfile = new DFile(app, entry, null, npath);
            YMenuItem *item = add(new DObjectMenuItem(pfile));
            if (item) {
                item->setSubmenu(sub);
#ifndef LITE
                if (sub) {
                    if (folder != null)
                        item->setIcon(folder);
                } else {
                    if (file != null)
                        item->setIcon(file);
                }
#endif
            }
        }
    }
}
#endif
<commit_msg>Adding a menu item may fail. If this happens then the items must be freed to prevent a leak.<commit_after>/*
 * IceWM
 *
 * Copyright (C) 1998-2001 Marko Macek
 */

#include "config.h"

#ifndef NO_CONFIGURE_MENUS

#include "obj.h"
#include "objmenu.h"
#include "browse.h"
#include "wmmgr.h"
#include "wmprog.h"
#include "yicon.h"
#include "sysdep.h"
#include "base.h"
#include "udir.h"

BrowseMenu::BrowseMenu(
    IApp *app,
    YSMListener *smActionListener,
    YActionListener *wmActionListener,
    upath path,
    YWindow *parent): ObjectMenu(wmActionListener, parent)
{
    this->app = app;
    this->smActionListener = smActionListener;
    fPath = path;
    fModTime = 0;
}

BrowseMenu::~BrowseMenu() {
}

void BrowseMenu::updatePopup() {
    struct stat sb;

    if (fPath.stat(&sb) != 0)
        removeAll();
    else if (sb.st_mtime > fModTime) {
        fModTime = sb.st_mtime;

        removeAll();

#ifndef LITE
        ref<YIcon> file = YIcon::getIcon("file");
        ref<YIcon> folder = YIcon::getIcon("folder");
#endif

        for (adir dir(fPath.string()); dir.next(); ) {
            ustring entry(dir.entry());
            upath npath(fPath + entry);

            YMenu *sub = 0;
            if (npath.dirExists())
                sub = new BrowseMenu(app, smActionListener, wmActionListener, npath);

            DFile *pfile = new DFile(app, entry, null, npath);
            YMenuItem *item = add(new DObjectMenuItem(pfile));
            if (item) {
                item->setSubmenu(sub);
#ifndef LITE
                if (sub) {
                    if (folder != null)
                        item->setIcon(folder);
                } else {
                    if (file != null)
                        item->setIcon(file);
                }
#endif
            }
            else if (sub) {
                delete sub;
            }
        }
    }
}
#endif
<|endoftext|>


<commit_before>#include "btcwif.h"

#include <cassert>

#include <ecdsa/base58.h>

#include "utils.h"

namespace btc {
namespace wif {

std::string PrivateKeyToWif(const std::vector<uint8_t> &priv_key) {
  // 0. Preparing...
  std::vector<uint8_t> pk2(priv_key.size() + 1);

  // 1. 0x80 to front.
  pk2[0] = 0x80;
  memcpy(pk2.data() + 1, priv_key.data(), priv_key.size());

  // 2. 0x01 to back.
  pk2.push_back(0x01);

  // 3. Perform SHA256 on extended key.
  std::vector<uint8_t> check_sum_half = utils::sha256(pk2.data(), pk2.size());
  std::vector<uint8_t> check_sum =
      utils::sha256(check_sum_half.data(), check_sum_half.size());

  // 4. Add 4 bytes from check sum to pk2.
  std::vector<uint8_t> pk4(pk2.size() + 4);
  memcpy(pk4.data(), pk2.data(), pk2.size());
  memcpy(pk4.data() + pk2.size(), check_sum.data(), 4);

  // 5. Base58
  return base58::EncodeBase58(pk4);
}

std::vector<uint8_t> WifToPrivateKey(const std::string &priv_key_str) {
  // 1. Revert base58 to data.
  std::vector<uint8_t> pk1;
  assert(base58::DecodeBase58(priv_key_str, pk1));

  // 2. Calculate size.
  size_t size;
  size_t add_index = pk1.size() - 4;
  if (pk1[add_index] == 0x01) {
    size = pk1.size() - 6;
  } else {
    size = pk1.size() - 5;
  }

  // 3. Remove first 1 byte, last 4 byte(s) and
  //   last 1 byte if it equals to 0x01.
  std::vector<uint8_t> pk2(size);
  memcpy(pk2.data(), pk1.data() + 1, size);

  return pk2;
}

bool VerifyWifString(const std::string &priv_key_str) {
  std::vector<uint8_t> priv_key_data;
  assert(base58::DecodeBase58(priv_key_str, priv_key_data));

  std::vector<uint8_t> last_4_bytes(4);
  memcpy(last_4_bytes.data(), priv_key_data.data() + (priv_key_data.size() - 4), 4);

  std::vector<uint8_t> priv_key_data_to_hash(priv_key_data.size() - 4);
  memcpy(priv_key_data_to_hash.data(), priv_key_data.data(), priv_key_data.size());

  std::vector<uint8_t> check_sum_half = utils::sha256(priv_key_data_to_hash.data(), priv_key_data_to_hash.size());
  std::vector<uint8_t> check_sum = utils::sha256(check_sum_half.data(), check_sum_half.size());

  return memcmp(check_sum.data(), last_4_bytes.data(), 4) == 0;
}

}  // namespace wif
}  // namespace btc
<commit_msg>When decode operation fail returns fasle immediately.<commit_after>#include "btcwif.h"

#include <cassert>

#include <ecdsa/base58.h>

#include "utils.h"

namespace btc {
namespace wif {

std::string PrivateKeyToWif(const std::vector<uint8_t> &priv_key) {
  // 0. Preparing...
  std::vector<uint8_t> pk2(priv_key.size() + 1);

  // 1. 0x80 to front.
  pk2[0] = 0x80;
  memcpy(pk2.data() + 1, priv_key.data(), priv_key.size());

  // 2. 0x01 to back.
  pk2.push_back(0x01);

  // 3. Perform SHA256 on extended key.
  std::vector<uint8_t> check_sum_half = utils::sha256(pk2.data(), pk2.size());
  std::vector<uint8_t> check_sum =
      utils::sha256(check_sum_half.data(), check_sum_half.size());

  // 4. Add 4 bytes from check sum to pk2.
  std::vector<uint8_t> pk4(pk2.size() + 4);
  memcpy(pk4.data(), pk2.data(), pk2.size());
  memcpy(pk4.data() + pk2.size(), check_sum.data(), 4);

  // 5. Base58
  return base58::EncodeBase58(pk4);
}

std::vector<uint8_t> WifToPrivateKey(const std::string &priv_key_str) {
  // 1. Revert base58 to data.
  std::vector<uint8_t> pk1;
  assert(base58::DecodeBase58(priv_key_str, pk1));

  // 2. Calculate size.
  size_t size;
  size_t add_index = pk1.size() - 4;
  if (pk1[add_index] == 0x01) {
    size = pk1.size() - 6;
  } else {
    size = pk1.size() - 5;
  }

  // 3. Remove first 1 byte, last 4 byte(s) and
  //   last 1 byte if it equals to 0x01.
  std::vector<uint8_t> pk2(size);
  memcpy(pk2.data(), pk1.data() + 1, size);

  return pk2;
}

bool VerifyWifString(const std::string &priv_key_str) {
  std::vector<uint8_t> priv_key_data;
  bool succ = base58::DecodeBase58(priv_key_str, priv_key_data);
  if (!succ) return false;

  std::vector<uint8_t> last_4_bytes(4);
  memcpy(last_4_bytes.data(), priv_key_data.data() + (priv_key_data.size() - 4), 4);

  std::vector<uint8_t> priv_key_data_to_hash(priv_key_data.size() - 4);
  memcpy(priv_key_data_to_hash.data(), priv_key_data.data(), priv_key_data.size());

  std::vector<uint8_t> check_sum_half = utils::sha256(priv_key_data_to_hash.data(), priv_key_data_to_hash.size());
  std::vector<uint8_t> check_sum = utils::sha256(check_sum_half.data(), check_sum_half.size());

  return memcmp(check_sum.data(), last_4_bytes.data(), 4) == 0;
}

}  // namespace wif
}  // namespace btc
<|endoftext|>


<commit_before>#ifndef buffer_hh_INCLUDED
#define buffer_hh_INCLUDED

#include <string>
#include <vector>
#include <list>
#include <memory>

#include "line_and_column.hh"

namespace Kakoune
{

class Buffer;
class Window;

typedef int      BufferPos;
typedef int      BufferSize;
typedef char     BufferChar;
typedef std::basic_string<BufferChar> BufferString;

struct BufferCoord : LineAndColumn<BufferCoord>
{
    BufferCoord(int line = 0, int column = 0)
        : LineAndColumn(line, column) {}

    template<typename T>
    explicit BufferCoord(const LineAndColumn<T>& other)
        : LineAndColumn(other.line, other.column) {}
};

class BufferIterator
{
public:
    typedef BufferChar value_type;
    typedef BufferSize difference_type;
    typedef const value_type* pointer;
    typedef const value_type& reference;
    typedef std::bidirectional_iterator_tag iterator_category;

    BufferIterator() : m_buffer(NULL), m_position(0) {}
    BufferIterator(const Buffer& buffer, BufferPos position);
    BufferIterator& operator=(const BufferIterator& iterator);

    bool operator== (const BufferIterator& iterator) const;
    bool operator!= (const BufferIterator& iterator) const;
    bool operator<  (const BufferIterator& iterator) const;
    bool operator<= (const BufferIterator& iterator) const;
    bool operator>  (const BufferIterator& iterator) const;
    bool operator>= (const BufferIterator& iterator) const;

    BufferChar operator* () const;
    BufferSize operator- (const BufferIterator& iterator) const;

    BufferIterator operator+ (BufferSize size) const;
    BufferIterator operator- (BufferSize size) const;

    BufferIterator& operator+= (BufferSize size);
    BufferIterator& operator-= (BufferSize size);

    BufferIterator& operator++ ();
    BufferIterator& operator-- ();

    bool is_begin() const;
    bool is_end() const;
    bool is_valid() const;

    const Buffer& buffer() const;

private:
    const Buffer* m_buffer;
    BufferPos     m_position;
    friend class Buffer;
};

struct BufferModification
{
    enum Type { Insert, Erase };

    Type           type;
    BufferIterator position;
    BufferString   content;

    BufferModification(Type type, BufferIterator position,
                       BufferString content)
        : type(type), position(position), content(content) {}

    BufferModification inverse() const;
};

class BufferModificationListener
{
public:
    virtual void on_modification(const BufferModification& modification) = 0;
};

class Buffer
{
public:
    enum class Type
    {
        File,
        Scratch
    };

    Buffer(const std::string& name, Type type,
           const BufferString& initial_content = "");
    Buffer(const Buffer&) = delete;
    Buffer(Buffer&&) = delete;
    Buffer& operator= (const Buffer&) = delete;
    ~Buffer();

    void           begin_undo_group();
    void           end_undo_group();

    bool           undo();
    bool           redo();

    void           erase(const BufferIterator& begin,
                         const BufferIterator& end);

    void           insert(const BufferIterator& position,
                          const BufferString& string);

    BufferString   string(const BufferIterator& begin,
                          const BufferIterator& end) const;

    BufferIterator begin() const;
    BufferIterator end() const;
    BufferSize     length() const;
    BufferSize     line_count() const;

    BufferIterator iterator_at(const BufferCoord& line_and_column) const;
    BufferCoord    line_and_column_at(const BufferIterator& iterator) const;

    BufferCoord     clamp(const BufferCoord& line_and_column) const;

    const std::string& name() const { return m_name; }

    const BufferString& content() const { return m_content; }

    Window* get_or_create_window();
    void delete_window(Window* window);

    bool is_modified() const;
    Type type() const { return m_type; }
    void notify_saved();

    void register_modification_listener(BufferModificationListener* listener) const;
    void unregister_modification_listener(BufferModificationListener* listener) const;

private:
    BufferChar at(BufferPos position) const;

    void       do_erase(const BufferIterator& begin,
                        const BufferIterator& end);

    void       do_insert(const BufferIterator& position,
                         const BufferString& string);

    friend class BufferIterator;

    std::vector<BufferPos> m_lines;

    void compute_lines();
    BufferPos line_at(const BufferIterator& iterator) const;
    BufferSize line_length(BufferPos line) const;

    BufferString m_content;

    std::string  m_name;
    const Type   m_type;

    typedef std::vector<BufferModification> UndoGroup;

    std::vector<UndoGroup>           m_history;
    std::vector<UndoGroup>::iterator m_history_cursor;
    UndoGroup                        m_current_undo_group;

    void apply_modification(const BufferModification& modification);
    void revert_modification(const BufferModification& modification);

    void append_modification(BufferModification&& modification);

    std::list<std::unique_ptr<Window>> m_windows;

    size_t m_last_save_undo_index;

    mutable std::vector<BufferModificationListener*> m_modification_listeners;
};

}

#include "buffer_iterator.inl.hh"

#endif // buffer_hh_INCLUDED
<commit_msg>Buffer: tweak default content<commit_after>#ifndef buffer_hh_INCLUDED
#define buffer_hh_INCLUDED

#include <string>
#include <vector>
#include <list>
#include <memory>

#include "line_and_column.hh"

namespace Kakoune
{

class Buffer;
class Window;

typedef int      BufferPos;
typedef int      BufferSize;
typedef char     BufferChar;
typedef std::basic_string<BufferChar> BufferString;

struct BufferCoord : LineAndColumn<BufferCoord>
{
    BufferCoord(int line = 0, int column = 0)
        : LineAndColumn(line, column) {}

    template<typename T>
    explicit BufferCoord(const LineAndColumn<T>& other)
        : LineAndColumn(other.line, other.column) {}
};

class BufferIterator
{
public:
    typedef BufferChar value_type;
    typedef BufferSize difference_type;
    typedef const value_type* pointer;
    typedef const value_type& reference;
    typedef std::bidirectional_iterator_tag iterator_category;

    BufferIterator() : m_buffer(NULL), m_position(0) {}
    BufferIterator(const Buffer& buffer, BufferPos position);
    BufferIterator& operator=(const BufferIterator& iterator);

    bool operator== (const BufferIterator& iterator) const;
    bool operator!= (const BufferIterator& iterator) const;
    bool operator<  (const BufferIterator& iterator) const;
    bool operator<= (const BufferIterator& iterator) const;
    bool operator>  (const BufferIterator& iterator) const;
    bool operator>= (const BufferIterator& iterator) const;

    BufferChar operator* () const;
    BufferSize operator- (const BufferIterator& iterator) const;

    BufferIterator operator+ (BufferSize size) const;
    BufferIterator operator- (BufferSize size) const;

    BufferIterator& operator+= (BufferSize size);
    BufferIterator& operator-= (BufferSize size);

    BufferIterator& operator++ ();
    BufferIterator& operator-- ();

    bool is_begin() const;
    bool is_end() const;
    bool is_valid() const;

    const Buffer& buffer() const;

private:
    const Buffer* m_buffer;
    BufferPos     m_position;
    friend class Buffer;
};

struct BufferModification
{
    enum Type { Insert, Erase };

    Type           type;
    BufferIterator position;
    BufferString   content;

    BufferModification(Type type, BufferIterator position,
                       BufferString content)
        : type(type), position(position), content(content) {}

    BufferModification inverse() const;
};

class BufferModificationListener
{
public:
    virtual void on_modification(const BufferModification& modification) = 0;
};

class Buffer
{
public:
    enum class Type
    {
        File,
        Scratch
    };

    Buffer(const std::string& name, Type type,
           const BufferString& initial_content = "\n");
    Buffer(const Buffer&) = delete;
    Buffer(Buffer&&) = delete;
    Buffer& operator= (const Buffer&) = delete;
    ~Buffer();

    void           begin_undo_group();
    void           end_undo_group();

    bool           undo();
    bool           redo();

    void           erase(const BufferIterator& begin,
                         const BufferIterator& end);

    void           insert(const BufferIterator& position,
                          const BufferString& string);

    BufferString   string(const BufferIterator& begin,
                          const BufferIterator& end) const;

    BufferIterator begin() const;
    BufferIterator end() const;
    BufferSize     length() const;
    BufferSize     line_count() const;

    BufferIterator iterator_at(const BufferCoord& line_and_column) const;
    BufferCoord    line_and_column_at(const BufferIterator& iterator) const;

    BufferCoord     clamp(const BufferCoord& line_and_column) const;

    const std::string& name() const { return m_name; }

    const BufferString& content() const { return m_content; }

    Window* get_or_create_window();
    void delete_window(Window* window);

    bool is_modified() const;
    Type type() const { return m_type; }
    void notify_saved();

    void register_modification_listener(BufferModificationListener* listener) const;
    void unregister_modification_listener(BufferModificationListener* listener) const;

private:
    BufferChar at(BufferPos position) const;

    void       do_erase(const BufferIterator& begin,
                        const BufferIterator& end);

    void       do_insert(const BufferIterator& position,
                         const BufferString& string);

    friend class BufferIterator;

    std::vector<BufferPos> m_lines;

    void compute_lines();
    BufferPos line_at(const BufferIterator& iterator) const;
    BufferSize line_length(BufferPos line) const;

    BufferString m_content;

    std::string  m_name;
    const Type   m_type;

    typedef std::vector<BufferModification> UndoGroup;

    std::vector<UndoGroup>           m_history;
    std::vector<UndoGroup>::iterator m_history_cursor;
    UndoGroup                        m_current_undo_group;

    void apply_modification(const BufferModification& modification);
    void revert_modification(const BufferModification& modification);

    void append_modification(BufferModification&& modification);

    std::list<std::unique_ptr<Window>> m_windows;

    size_t m_last_save_undo_index;

    mutable std::vector<BufferModificationListener*> m_modification_listeners;
};

}

#include "buffer_iterator.inl.hh"

#endif // buffer_hh_INCLUDED
<|endoftext|>


<commit_before>#include <stdlib.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
#include <resolv.h>

#include <iostream>
#include <memory>

#include "cache.h"
#include "skull_protos.h"

using namespace skull::service::dns;

#define MAX_DNS_REPLY_ADDRS 10
#define IPV4_MAX_LENGTH     16
#define MAX_RECORD_EXPIRED_TIME 2  // unit: second

// ====================== Internal Functions ===================================
class UpdateJobdata {
private:
    std::string domain_;
    adns::Cache::DnsRecords records_;

public:
    UpdateJobdata(const std::string& domain) {
        this->domain_ = domain;
        this->records_.start_ = time(NULL);
    }

    void append(ares_addrttl addr) {
        this->records_.records_.push_back(addr);
    }

    const std::string& domain() const {
        return this->domain_;
    }

    adns::Cache::DnsRecords& records() {
        return this->records_;
    }

    const adns::Cache::DnsRecords& records() const {
        return this->records_;
    }
};

static
void _dnsrecord_updating(skullcpp::Service& service,
                         const std::shared_ptr<UpdateJobdata>& jobData) {
    auto dnsCache = (adns::Cache*)service.get();

    if (!jobData.get()) return;
    if (jobData->domain().empty()) return;
    if (jobData->records().records_.empty()) return;

    const std::string& domain = jobData->domain();
    adns::Cache::DnsRecords& records = jobData->records();

    dnsCache->updateCache(service, domain, records);
    std::cout << "_dnsrecord_updating done, domain: " << domain << std::endl;
}

// dns callback functions
static
size_t _dns_reply_unpack(const void* data, size_t len)
{
    std::cout << "ep dns _unpack len: " << len << std::endl;
    return len;
}

static
void _ep_cb(const skullcpp::Service& service, skullcpp::EPClientRet& ret,
            std::shared_ptr<std::string>& domain)
{
    // 1. Prepare and validate ep status
    std::cout << "dns _ep_cb: response len: " << ret.responseSize()
              << ", status: " << ret.status()
              << ", latency: " << ret.latency()
              << std::endl;

    auto& apiData   = ret.apiData();
    auto& queryReq  = (const query_req&)apiData.request();
    auto& queryResp = (query_resp&)apiData.response();

    if (ret.status() != skullcpp::EPClient::Status::OK) {
        SKULLCPP_LOG_ERROR("svc.dns.query-3",
                        "dns query failed due to network issue",
                        "Check network or dns server status");

        queryResp.set_code(1);
        queryResp.set_error("Dns query failed");
        return;
    }

    // 2. Parse dns answers
    int naddrs = MAX_DNS_REPLY_ADDRS;
    struct ares_addrttl addrs[MAX_DNS_REPLY_ADDRS];
    memset(addrs, 0, sizeof(struct ares_addrttl) * MAX_DNS_REPLY_ADDRS);
    auto response = (const unsigned char *)ret.response();

    int r = ares_parse_a_reply(response, (int)ret.responseSize(),
                               NULL, addrs, &naddrs);

    if (r != ARES_SUCCESS) {
        std::cout << "dns parse reply failed: " << ares_strerror(r) << std::endl;

        SKULLCPP_LOG_ERROR("svc.dns.query-4", "dns parse reply failed: "
            << ares_strerror(r)
            << " domain: " << queryReq.domain(),
            "Check whether queried domain is correct");

        queryResp.set_code(1);
        queryResp.set_error("Dns query failed, check whether domain is correct");

        return;
    }

    std::cout << "got " << naddrs << "dns replies" << std::endl;
    if (!naddrs) {
        queryResp.set_code(1);
        queryResp.set_error("Dns query failed, no ip returned");
        return;
    }

    // 3. Fill the api response
    queryResp.set_code(0);
    bool filled = false;
    auto jobData = std::make_shared<UpdateJobdata>(queryReq.domain());

    for (int i = 0; i < naddrs; i++) {
        char ip [IPV4_MAX_LENGTH];
        inet_ntop(AF_INET, &addrs[i].ipaddr, ip, IPV4_MAX_LENGTH);
        printf(" - ip: %s; ttl: %d\n", ip, addrs[i].ttl);
        jobData->append(addrs[i]);

        if (!filled) {
            // Fill ip
            queryResp.set_ip(ip);
            filled = true;
        }
    }

    // 4. Update it via a service job
    service.createJob(0, 0, skull_BindSvc(_dnsrecord_updating, jobData));
}

static
void _ep_cb_updateonly(const skullcpp::Service& service,
                       skullcpp::EPClientRet& ret,
                       std::shared_ptr<std::string>& domain)
{
    // 1. Prepare and validate ep status
    std::cout << "dns _ep_cb_updateonly: response len: " << ret.responseSize()
              << ", status: " << ret.status()
              << ", latency: " << ret.latency()
              << std::endl;

    if (ret.status() != skullcpp::EPClient::Status::OK) {
        SKULLCPP_LOG_ERROR("svc.dns.query-3",
                        "dns query failed due to network issue",
                        "Check network or dns server status");
        return;
    }

    // 2. Parse dns answers
    int naddrs = MAX_DNS_REPLY_ADDRS;
    struct ares_addrttl addrs[MAX_DNS_REPLY_ADDRS];
    memset(addrs, 0, sizeof(struct ares_addrttl) * MAX_DNS_REPLY_ADDRS);
    auto response = (const unsigned char *)ret.response();

    int r = ares_parse_a_reply(response, (int)ret.responseSize(),
                               NULL, addrs, &naddrs);

    if (r != ARES_SUCCESS) {
        std::cout << "dns parse reply failed: " << ares_strerror(r) << std::endl;

        SKULLCPP_LOG_ERROR("svc.dns.query-4", "dns parse reply failed: "
            << ares_strerror(r)
            << " domain: " << domain,
            "Check whether queried domain is correct");
        return;
    }

    std::cout << "got " << naddrs << "dns replies" << std::endl;
    if (!naddrs) {
        return;
    }

    // 3. Fill the api response
    auto jobData = std::make_shared<UpdateJobdata>(*domain);

    for (int i = 0; i < naddrs; i++) {
        char ip [IPV4_MAX_LENGTH];
        inet_ntop(AF_INET, &addrs[i].ipaddr, ip, IPV4_MAX_LENGTH);
        printf(" - ip: %s; ttl: %d\n", ip, addrs[i].ttl);
        jobData->append(addrs[i]);
    }

    // 4. Update it via a service job
    service.createJob(0, 0, skull_BindSvc(_dnsrecord_updating, jobData));
}

static
void _refresh_domain_records(skullcpp::Service& service,
                             const std::shared_ptr<std::string>& domain) {
    auto dnsCache = (adns::Cache*)service.get();

    bool ret = dnsCache->queryFromDNS(service, *domain, true);
    if (!ret) {
        std::cout << "_refresh_domain_records: query domain failed" << std::endl;
    } else {
        std::cout << "_refresh_domain_records: query domain success" << std::endl;
    }
}

namespace adns {

Cache::Cache() {
    // 1. Init ares library
    int ret = ares_library_init(ARES_LIB_INIT_ALL);
    if (ret) {
        printf("Init ares library failed: %s\n", ares_strerror(ret));
        exit(1);
    }

    // 2. Init Resolver
    res_init();

    // 3. Init name servers
    initNameServers();
}

Cache::~Cache() {
    ares_library_cleanup();
}

const std::string Cache::queryFromCache(const skullcpp::Service& service,
                                        const std::string& domain) const {
    auto it = this->records_.find(domain);
    if (it == this->records_.end()) {
        return "";
    }

    // Reture the 1st unexpired record
    const DnsRecords& records = it->second;
    size_t nrec = records.records_.size();
    if (!nrec) {
        return "";
    }

    time_t now = time(NULL);

    for (const auto& record : records.records_) {
        struct in_addr addr = record.ipaddr;
        int ttl = record.ttl;

        if (now - records.start_ >= ttl) {
            continue;
        }

        char ip [IPV4_MAX_LENGTH];
        inet_ntop(AF_INET, &addr, ip, IPV4_MAX_LENGTH);
        return std::string(ip);
    }

    // If not found, create a job to query dns, then return the 1st one
    auto queryDomain = std::make_shared<std::string>(domain);
    service.createJob(0, 0, skull_BindSvc(_refresh_domain_records, queryDomain));

    char ip [IPV4_MAX_LENGTH];
    inet_ntop(AF_INET, &records.records_[0], ip, IPV4_MAX_LENGTH);
    return std::string(ip);
}

bool Cache::queryFromDNS(const skullcpp::Service& service,
                      const std::string& domain, bool updateOnly) const {
    // Create a simple internet query for ipv4 address and recursion is desired
    unsigned char* query = NULL;
    int query_len = 0;

    // To backward compatible, here we use `ares_mkquery`, if your
    //  platform support higher version of ares, then recommend to use
    //  `ares_create_query`
    int ret = ares_mkquery(domain.c_str(),
                                ns_c_in,     // Internet class
                                ns_t_a,      // ipv4 address
                                0,           // identifier
                                1,           // recursion is desired
                                &query,
                                &query_len);

    if (ret != ARES_SUCCESS) {
        SKULLCPP_LOG_ERROR("svc.dns.query-2", "create dns query failed: "
            << ares_strerror(ret), "Check whether queried domain is correct");
        std::cout << "create dns query failed: " << ares_strerror(ret) << std::endl;
        ares_free_string(query);
        return false;
    }

    // Create EPClient to send the query string to DNS server
    skullcpp::EPClient epClient;
    epClient.setType(skullcpp::EPClient::UDP);
    epClient.setIP(getNameServerIP());
    epClient.setPort(53);
    epClient.setTimeout(1000);
    epClient.setUnpack(_dns_reply_unpack);

    auto queryDomain = std::make_shared<std::string>(domain);
    auto epCb = updateOnly
                    ? skull_BindEp(_ep_cb_updateonly, queryDomain)
                    : skull_BindEp(_ep_cb, queryDomain);

    skullcpp::EPClient::Status st = epClient.send(service, query,
                                        (size_t)query_len,
                                        epCb);
    ares_free_string(query);
    if (st != skullcpp::EPClient::Status::OK) {
        return false;
    } else {
        return true;
    }
}

void Cache::updateCache(skullcpp::Service& service, const std::string& domain,
                        DnsRecords& newRecords) {
    auto it = this->records_.find(domain);
    if (it == this->records_.end()) {
        this->records_.insert(std::make_pair(domain, newRecords));
        return;
    }

    DnsRecords& oldRecords = it->second;
    if (newRecords.start_ > oldRecords.start_) {
        this->records_.erase(it);
        this->records_.insert(std::make_pair(domain, newRecords));
    }
}

void Cache::initNameServers() {
    if (_res.nscount == 0) {
        std::cout << "Not found any name server, exit" << std::endl;
        exit(1);
    }

    for (int i = 0; i < _res.nscount; i++) {
        char ip [IPV4_MAX_LENGTH];
        inet_ntop(AF_INET, &_res.nsaddr_list[i].sin_addr, ip, IPV4_MAX_LENGTH);

        std::cout << "init name server: " << ip << std::endl;
        this->nservers_.push_back(ip);
    }
}

const std::string& Cache::getNameServerIP() const {
    return this->nservers_[0];
}

} // End of namespace

<commit_msg>Adopt latest skull api<commit_after>#include <stdlib.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
#include <resolv.h>

#include <iostream>
#include <memory>

#include "cache.h"
#include "skull_protos.h"

using namespace skull::service::dns;

#define MAX_DNS_REPLY_ADDRS 10
#define IPV4_MAX_LENGTH     16
#define MAX_RECORD_EXPIRED_TIME 2  // unit: second

// ====================== Internal Functions ===================================
class UpdateJobdata {
private:
    std::string domain_;
    adns::Cache::DnsRecords records_;

public:
    UpdateJobdata(const std::string& domain) {
        this->domain_ = domain;
        this->records_.start_ = time(NULL);
    }

    void append(ares_addrttl addr) {
        this->records_.records_.push_back(addr);
    }

    const std::string& domain() const {
        return this->domain_;
    }

    adns::Cache::DnsRecords& records() {
        return this->records_;
    }

    const adns::Cache::DnsRecords& records() const {
        return this->records_;
    }
};

static
void _dnsrecord_updating(skullcpp::Service& service,
                         const std::shared_ptr<UpdateJobdata>& jobData) {
    auto dnsCache = (adns::Cache*)service.get();

    if (!jobData.get()) return;
    if (jobData->domain().empty()) return;
    if (jobData->records().records_.empty()) return;

    const std::string& domain = jobData->domain();
    adns::Cache::DnsRecords& records = jobData->records();

    dnsCache->updateCache(service, domain, records);
    std::cout << "_dnsrecord_updating done, domain: " << domain << std::endl;
}

// dns callback functions
static
size_t _dns_reply_unpack(const void* data, size_t len)
{
    std::cout << "ep dns _unpack len: " << len << std::endl;
    return len;
}

static
void _ep_cb(const skullcpp::Service& service, skullcpp::EPClientRet& ret,
            std::shared_ptr<std::string>& domain)
{
    // 1. Prepare and validate ep status
    std::cout << "dns _ep_cb: response len: " << ret.responseSize()
              << ", status: " << ret.status()
              << ", latency: " << ret.latency()
              << std::endl;

    auto& apiData   = ret.apiData();
    auto& queryReq  = (const query_req&)apiData.request();
    auto& queryResp = (query_resp&)apiData.response();

    if (ret.status() != skullcpp::EPClient::Status::OK) {
        SKULLCPP_LOG_ERROR("svc.dns.query-3",
                        "dns query failed due to network issue",
                        "Check network or dns server status");

        queryResp.set_code(1);
        queryResp.set_error("Dns query failed");
        return;
    }

    // 2. Parse dns answers
    int naddrs = MAX_DNS_REPLY_ADDRS;
    struct ares_addrttl addrs[MAX_DNS_REPLY_ADDRS];
    memset(addrs, 0, sizeof(struct ares_addrttl) * MAX_DNS_REPLY_ADDRS);
    auto response = (const unsigned char *)ret.response();

    int r = ares_parse_a_reply(response, (int)ret.responseSize(),
                               NULL, addrs, &naddrs);

    if (r != ARES_SUCCESS) {
        std::cout << "dns parse reply failed: " << ares_strerror(r) << std::endl;

        SKULLCPP_LOG_ERROR("svc.dns.query-4", "dns parse reply failed: "
            << ares_strerror(r)
            << " domain: " << queryReq.domain(),
            "Check whether queried domain is correct");

        queryResp.set_code(1);
        queryResp.set_error("Dns query failed, check whether domain is correct");

        return;
    }

    std::cout << "got " << naddrs << "dns replies" << std::endl;
    if (!naddrs) {
        queryResp.set_code(1);
        queryResp.set_error("Dns query failed, no ip returned");
        return;
    }

    // 3. Fill the api response
    queryResp.set_code(0);
    bool filled = false;
    auto jobData = std::make_shared<UpdateJobdata>(queryReq.domain());

    for (int i = 0; i < naddrs; i++) {
        char ip [IPV4_MAX_LENGTH];
        inet_ntop(AF_INET, &addrs[i].ipaddr, ip, IPV4_MAX_LENGTH);
        printf(" - ip: %s; ttl: %d\n", ip, addrs[i].ttl);
        jobData->append(addrs[i]);

        if (!filled) {
            // Fill ip
            queryResp.set_ip(ip);
            filled = true;
        }
    }

    // 4. Update it via a service job
    service.createJob(0, 0, skull_BindSvc(_dnsrecord_updating, jobData));
}

static
void _ep_cb_updateonly(const skullcpp::Service& service,
                       skullcpp::EPClientRet& ret,
                       std::shared_ptr<std::string>& domain)
{
    // 1. Prepare and validate ep status
    std::cout << "dns _ep_cb_updateonly: response len: " << ret.responseSize()
              << ", status: " << ret.status()
              << ", latency: " << ret.latency()
              << std::endl;

    if (ret.status() != skullcpp::EPClient::Status::OK) {
        SKULLCPP_LOG_ERROR("svc.dns.query-3",
                        "dns query failed due to network issue",
                        "Check network or dns server status");
        return;
    }

    // 2. Parse dns answers
    int naddrs = MAX_DNS_REPLY_ADDRS;
    struct ares_addrttl addrs[MAX_DNS_REPLY_ADDRS];
    memset(addrs, 0, sizeof(struct ares_addrttl) * MAX_DNS_REPLY_ADDRS);
    auto response = (const unsigned char *)ret.response();

    int r = ares_parse_a_reply(response, (int)ret.responseSize(),
                               NULL, addrs, &naddrs);

    if (r != ARES_SUCCESS) {
        std::cout << "dns parse reply failed: " << ares_strerror(r) << std::endl;

        SKULLCPP_LOG_ERROR("svc.dns.query-4", "dns parse reply failed: "
            << ares_strerror(r)
            << " domain: " << domain,
            "Check whether queried domain is correct");
        return;
    }

    std::cout << "got " << naddrs << "dns replies" << std::endl;
    if (!naddrs) {
        return;
    }

    // 3. Fill the api response
    auto jobData = std::make_shared<UpdateJobdata>(*domain);

    for (int i = 0; i < naddrs; i++) {
        char ip [IPV4_MAX_LENGTH];
        inet_ntop(AF_INET, &addrs[i].ipaddr, ip, IPV4_MAX_LENGTH);
        printf(" - ip: %s; ttl: %d\n", ip, addrs[i].ttl);
        jobData->append(addrs[i]);
    }

    // 4. Update it via a service job
    service.createJob(0, 0, skull_BindSvc(_dnsrecord_updating, jobData));
}

static
void _refresh_domain_records(skullcpp::Service& service,
                             const std::shared_ptr<std::string>& domain) {
    auto dnsCache = (adns::Cache*)service.get();

    bool ret = dnsCache->queryFromDNS(service, *domain, true);
    if (!ret) {
        std::cout << "_refresh_domain_records: query domain failed" << std::endl;
    } else {
        std::cout << "_refresh_domain_records: query domain success" << std::endl;
    }
}

namespace adns {

Cache::Cache() {
    // 1. Init ares library
    int ret = ares_library_init(ARES_LIB_INIT_ALL);
    if (ret) {
        printf("Init ares library failed: %s\n", ares_strerror(ret));
        exit(1);
    }

    // 2. Init Resolver
    res_init();

    // 3. Init name servers
    initNameServers();
}

Cache::~Cache() {
    ares_library_cleanup();
}

const std::string Cache::queryFromCache(const skullcpp::Service& service,
                                        const std::string& domain) const {
    auto it = this->records_.find(domain);
    if (it == this->records_.end()) {
        return "";
    }

    // Reture the 1st unexpired record
    const DnsRecords& records = it->second;
    size_t nrec = records.records_.size();
    if (!nrec) {
        return "";
    }

    time_t now = time(NULL);

    for (const auto& record : records.records_) {
        struct in_addr addr = record.ipaddr;
        int ttl = record.ttl;

        if (now - records.start_ >= ttl) {
            continue;
        }

        char ip [IPV4_MAX_LENGTH];
        inet_ntop(AF_INET, &addr, ip, IPV4_MAX_LENGTH);
        return std::string(ip);
    }

    // If not found, create a job to query dns, then return the 1st one
    auto queryDomain = std::make_shared<std::string>(domain);
    service.createJob(0, 0, skull_BindSvc(_refresh_domain_records, queryDomain));

    char ip [IPV4_MAX_LENGTH];
    inet_ntop(AF_INET, &records.records_[0], ip, IPV4_MAX_LENGTH);
    return std::string(ip);
}

bool Cache::queryFromDNS(const skullcpp::Service& service,
                      const std::string& domain, bool updateOnly) const {
    // Create a simple internet query for ipv4 address and recursion is desired
    unsigned char* query = NULL;
    int query_len = 0;

    // To backward compatible, here we use `ares_mkquery`, if your
    //  platform support higher version of ares, then recommend to use
    //  `ares_create_query`
    int ret = ares_mkquery(domain.c_str(),
                                ns_c_in,     // Internet class
                                ns_t_a,      // ipv4 address
                                0,           // identifier
                                1,           // recursion is desired
                                &query,
                                &query_len);

    if (ret != ARES_SUCCESS) {
        SKULLCPP_LOG_ERROR("svc.dns.query-2", "create dns query failed: "
            << ares_strerror(ret), "Check whether queried domain is correct");
        std::cout << "create dns query failed: " << ares_strerror(ret) << std::endl;
        ares_free_string(query);
        return false;
    }

    // Create EPClient to send the query string to DNS server
    skullcpp::EPClient epClient;
    epClient.setType(skullcpp::EPClient::UDP);
    epClient.setIP(getNameServerIP());
    epClient.setPort(53);
    epClient.setTimeout(1000);
    epClient.setUnpack(_dns_reply_unpack);

    auto queryDomain = std::make_shared<std::string>(domain);
    auto epCb = updateOnly
                    ? skull_BindEpCb(_ep_cb_updateonly, queryDomain)
                    : skull_BindEpCb(_ep_cb, queryDomain);

    skullcpp::EPClient::Status st = epClient.send(service, query,
                                        (size_t)query_len,
                                        epCb);
    ares_free_string(query);
    if (st != skullcpp::EPClient::Status::OK) {
        return false;
    } else {
        return true;
    }
}

void Cache::updateCache(skullcpp::Service& service, const std::string& domain,
                        DnsRecords& newRecords) {
    auto it = this->records_.find(domain);
    if (it == this->records_.end()) {
        this->records_.insert(std::make_pair(domain, newRecords));
        return;
    }

    DnsRecords& oldRecords = it->second;
    if (newRecords.start_ > oldRecords.start_) {
        this->records_.erase(it);
        this->records_.insert(std::make_pair(domain, newRecords));
    }
}

void Cache::initNameServers() {
    if (_res.nscount == 0) {
        std::cout << "Not found any name server, exit" << std::endl;
        exit(1);
    }

    for (int i = 0; i < _res.nscount; i++) {
        char ip [IPV4_MAX_LENGTH];
        inet_ntop(AF_INET, &_res.nsaddr_list[i].sin_addr, ip, IPV4_MAX_LENGTH);

        std::cout << "init name server: " << ip << std::endl;
        this->nservers_.push_back(ip);
    }
}

const std::string& Cache::getNameServerIP() const {
    return this->nservers_[0];
}

} // End of namespace

<|endoftext|>


<commit_before>#include <boost/test/unit_test.hpp>
#include <boost/algorithm/string/predicate.hpp>

#include <eosio/testing/tester.hpp>
#include <eosio/chain/abi_serializer.hpp>
#include <eosio/chain/wasm_eosio_constraints.hpp>
#include <eosio/chain/resource_limits.hpp>
#include <eosio/chain/exceptions.hpp>
#include <eosio/chain/wast_to_wasm.hpp>
#include <eosio/chain_plugin/chain_plugin.hpp>
#include <eosio/chain/backing_store/kv_context.hpp>

#include <contracts.hpp>

#include <fc/io/fstream.hpp>

#include <Runtime/Runtime.h>

#include <fc/variant_object.hpp>
#include <fc/io/json.hpp>

#include <array>
#include <utility>

#ifdef NON_VALIDATING_TEST
#define TESTER tester
#else
#define TESTER validating_tester
#endif

using namespace eosio;
using namespace eosio::chain;
using namespace eosio::testing;
using namespace fc;

BOOST_AUTO_TEST_SUITE(get_kv_table_addr_tests)

BOOST_FIXTURE_TEST_CASE( get_kv_table_addr_test, TESTER ) try {
   eosio::chain_apis::read_only::get_table_rows_result result;
   auto chk_result = [&](int row, int data) {
      if( data == 1 )
      {
         BOOST_REQUIRE_EQUAL("jane", result.rows[row]["account_name"].as_string());
         BOOST_REQUIRE_EQUAL("jane", result.rows[row]["first_name"]["field_0"].as_string());
         BOOST_REQUIRE_EQUAL("Jane", result.rows[row]["first_name"]["field_1"].as_string());
         BOOST_REQUIRE_EQUAL("jane", result.rows[row]["last_name"]["field_0"].as_string());
         BOOST_REQUIRE_EQUAL("Doe", result.rows[row]["last_name"]["field_1"].as_string());
         BOOST_REQUIRE_EQUAL("1234 MyStreet", result.rows[row]["street_city_state_cntry"]["field_1"].as_string());
         BOOST_REQUIRE_EQUAL("jane", result.rows[row]["personal_id"]["field_0"].as_string());
         BOOST_REQUIRE_EQUAL("jdoe", result.rows[row]["personal_id"]["field_1"].as_string());
      }
      else if (data == 2)
      {
         BOOST_REQUIRE_EQUAL("john", result.rows[row]["account_name"].as_string());
         BOOST_REQUIRE_EQUAL("john", result.rows[row]["first_name"]["field_0"].as_string());
         BOOST_REQUIRE_EQUAL("John", result.rows[row]["first_name"]["field_1"].as_string());
         BOOST_REQUIRE_EQUAL("john", result.rows[row]["last_name"]["field_0"].as_string());
         BOOST_REQUIRE_EQUAL("Smith", result.rows[row]["last_name"]["field_1"].as_string());
         BOOST_REQUIRE_EQUAL("123 MyStreet", result.rows[row]["street_city_state_cntry"]["field_1"].as_string());
         BOOST_REQUIRE_EQUAL("john", result.rows[row]["personal_id"]["field_0"].as_string());
         BOOST_REQUIRE_EQUAL("jsmith", result.rows[row]["personal_id"]["field_1"].as_string());
      }
      else if (data == 3)
      {
         BOOST_REQUIRE_EQUAL("lois", result.rows[row]["account_name"].as_string());
         BOOST_REQUIRE_EQUAL("lois", result.rows[row]["first_name"]["field_0"].as_string());
         BOOST_REQUIRE_EQUAL("Lois", result.rows[row]["first_name"]["field_1"].as_string());
         BOOST_REQUIRE_EQUAL("lois", result.rows[row]["last_name"]["field_0"].as_string());
         BOOST_REQUIRE_EQUAL("Lane", result.rows[row]["last_name"]["field_1"].as_string());
         BOOST_REQUIRE_EQUAL("5432 MyStreet", result.rows[row]["street_city_state_cntry"]["field_1"].as_string());
         BOOST_REQUIRE_EQUAL("lois", result.rows[row]["personal_id"]["field_0"].as_string());
         BOOST_REQUIRE_EQUAL("llane", result.rows[row]["personal_id"]["field_1"].as_string());
      }
      else
      {
         BOOST_REQUIRE_EQUAL("steve", result.rows[row]["account_name"].as_string());
         BOOST_REQUIRE_EQUAL("steve", result.rows[row]["first_name"]["field_0"].as_string());
         BOOST_REQUIRE_EQUAL("Steve", result.rows[row]["first_name"]["field_1"].as_string());
         BOOST_REQUIRE_EQUAL("steve", result.rows[row]["last_name"]["field_0"].as_string());
         BOOST_REQUIRE_EQUAL("Jones", result.rows[row]["last_name"]["field_1"].as_string());
         BOOST_REQUIRE_EQUAL("321 MyStreet", result.rows[row]["street_city_state_cntry"]["field_1"].as_string());
         BOOST_REQUIRE_EQUAL("steve", result.rows[row]["personal_id"]["field_0"].as_string());
         BOOST_REQUIRE_EQUAL("sjones", result.rows[row]["personal_id"]["field_1"].as_string());
      }
   };

   produce_blocks(2);

   create_accounts({ "kvaddrbook"_n });

   produce_block();

   set_code(config::system_account_name, contracts::kv_bios_wasm());
   set_abi(config::system_account_name, contracts::kv_bios_abi().data());
   push_action("eosio"_n, "ramkvlimits"_n, "eosio"_n, mutable_variant_object()("k", 1024)("v", 1024)("i", 1024));
   produce_blocks(1);

   set_code( "kvaddrbook"_n, contracts::kv_addr_book_wasm() );
   set_abi( "kvaddrbook"_n, contracts::kv_addr_book_abi().data() );
   produce_blocks(1);

   auto arg = mutable_variant_object();
   push_action("kvaddrbook"_n, "test"_n, "kvaddrbook"_n, arg );

   eosio::chain_apis::read_only plugin(*(this->control), {}, fc::microseconds::maximum());
   eosio::chain_apis::read_only::get_kv_table_rows_params p;
   p.code = "kvaddrbook"_n;
   p.table = "kvaddrbook"_n;
   p.index_name = "accname"_n;
   p.index_value = "john";
   p.encode_type = "name";
   p.lower_bound = "";
   p.upper_bound = "";
   p.json = true;
   p.reverse = false;
   result = plugin.read_only::get_kv_table_rows(p);
   BOOST_REQUIRE_EQUAL(1u, result.rows.size());
   chk_result(0, 2);

   p.index_name = "accname"_n;
   p.index_value = "";
   p.encode_type = "name";
   p.lower_bound = "aaa";
   p.upper_bound = "";
   p.reverse = false;
   result = plugin.read_only::get_kv_table_rows(p);
   BOOST_REQUIRE_EQUAL(4u, result.rows.size());
   chk_result(0, 1);
   chk_result(1, 2);
   chk_result(2, 3);
   chk_result(3, 4);

   p.index_name = "accname"_n;
   p.index_value = "";
   p.encode_type = "name";
   p.lower_bound = "john";
   p.upper_bound = "";
   p.reverse = false;
   result = plugin.read_only::get_kv_table_rows(p);
   BOOST_REQUIRE_EQUAL(3u, result.rows.size());
   chk_result(0, 2);
   chk_result(1, 3);
   chk_result(2, 4);

   p.index_name = "accname"_n;
   p.index_value = "";
   p.encode_type = "name";
   p.lower_bound = "john";
   p.upper_bound = "lois";
   p.reverse = false;
   result = plugin.read_only::get_kv_table_rows(p);
   BOOST_REQUIRE_EQUAL(2u, result.rows.size());
   chk_result(0, 2);

   p.index_name = "accname"_n;
   p.index_value = "";
   p.encode_type = "name";
   p.lower_bound = "";
   p.upper_bound = "steve";
   p.reverse = true;
   result = plugin.read_only::get_kv_table_rows(p);
   BOOST_REQUIRE_EQUAL(4u, result.rows.size());
   chk_result(0, 4);
   chk_result(1, 3);
   chk_result(2, 2);
   chk_result(3, 1);

   p.index_name = "accname"_n;
   p.index_value = "";
   p.encode_type = "name";
   p.lower_bound = "john";
   p.upper_bound = "steve";
   p.reverse = true;
   result = plugin.read_only::get_kv_table_rows(p);
   BOOST_REQUIRE_EQUAL(3u, result.rows.size());
   chk_result(0, 4);
   chk_result(1, 3);

   p.index_name = "accname"_n;
   p.index_value = "";
   p.encode_type = "name";
   p.lower_bound = "";
   p.upper_bound = "aaaa";
   p.reverse = true;
   result = plugin.read_only::get_kv_table_rows(p);
   BOOST_REQUIRE_EQUAL(0u, result.rows.size());

   p.index_name = "accname"_n;
   p.index_value = "";
   p.encode_type = "name";
   p.lower_bound = "steve";
   p.upper_bound = "john";
   p.reverse = true;
   result = plugin.read_only::get_kv_table_rows(p);
   BOOST_REQUIRE_EQUAL(0u, result.rows.size());

   p.index_name = "accname"_n;
   p.index_value = "";
   p.encode_type = "name";
   p.lower_bound = "";
   p.upper_bound = "john";
   p.reverse = true;
   result = plugin.read_only::get_kv_table_rows(p);
   BOOST_REQUIRE_EQUAL(2u, result.rows.size());
   chk_result(0, 2);
   chk_result(1, 1);
}
FC_LOG_AND_RETHROW()

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>fix kv table addr test<commit_after>#include <boost/test/unit_test.hpp>
#include <boost/algorithm/string/predicate.hpp>

#include <eosio/testing/tester.hpp>
#include <eosio/chain/abi_serializer.hpp>
#include <eosio/chain/wasm_eosio_constraints.hpp>
#include <eosio/chain/resource_limits.hpp>
#include <eosio/chain/exceptions.hpp>
#include <eosio/chain/wast_to_wasm.hpp>
#include <eosio/chain_plugin/chain_plugin.hpp>
#include <eosio/chain/backing_store/kv_context.hpp>

#include <contracts.hpp>

#include <fc/io/fstream.hpp>

#include <Runtime/Runtime.h>

#include <fc/variant_object.hpp>
#include <fc/io/json.hpp>

#include <array>
#include <utility>

#ifdef NON_VALIDATING_TEST
#define TESTER tester
#else
#define TESTER validating_tester
#endif

BOOST_AUTO_TEST_SUITE(get_kv_table_addr_tests)

using namespace eosio::chain;
using namespace eosio::testing;
using namespace fc;

BOOST_FIXTURE_TEST_CASE( get_kv_table_addr_test, TESTER ) try {
   eosio::chain_apis::read_only::get_table_rows_result result;
   auto chk_result = [&](int row, int data) {
      if( data == 1 )
      {
         BOOST_REQUIRE_EQUAL("jane", result.rows[row]["account_name"].as_string());
         BOOST_REQUIRE_EQUAL("jane", result.rows[row]["first_name"]["field_0"].as_string());
         BOOST_REQUIRE_EQUAL("Jane", result.rows[row]["first_name"]["field_1"].as_string());
         BOOST_REQUIRE_EQUAL("jane", result.rows[row]["last_name"]["field_0"].as_string());
         BOOST_REQUIRE_EQUAL("Doe", result.rows[row]["last_name"]["field_1"].as_string());
         BOOST_REQUIRE_EQUAL("1234 MyStreet", result.rows[row]["street_city_state_cntry"]["field_1"].as_string());
         BOOST_REQUIRE_EQUAL("jane", result.rows[row]["personal_id"]["field_0"].as_string());
         BOOST_REQUIRE_EQUAL("jdoe", result.rows[row]["personal_id"]["field_1"].as_string());
      }
      else if (data == 2)
      {
         BOOST_REQUIRE_EQUAL("john", result.rows[row]["account_name"].as_string());
         BOOST_REQUIRE_EQUAL("john", result.rows[row]["first_name"]["field_0"].as_string());
         BOOST_REQUIRE_EQUAL("John", result.rows[row]["first_name"]["field_1"].as_string());
         BOOST_REQUIRE_EQUAL("john", result.rows[row]["last_name"]["field_0"].as_string());
         BOOST_REQUIRE_EQUAL("Smith", result.rows[row]["last_name"]["field_1"].as_string());
         BOOST_REQUIRE_EQUAL("123 MyStreet", result.rows[row]["street_city_state_cntry"]["field_1"].as_string());
         BOOST_REQUIRE_EQUAL("john", result.rows[row]["personal_id"]["field_0"].as_string());
         BOOST_REQUIRE_EQUAL("jsmith", result.rows[row]["personal_id"]["field_1"].as_string());
      }
      else if (data == 3)
      {
         BOOST_REQUIRE_EQUAL("lois", result.rows[row]["account_name"].as_string());
         BOOST_REQUIRE_EQUAL("lois", result.rows[row]["first_name"]["field_0"].as_string());
         BOOST_REQUIRE_EQUAL("Lois", result.rows[row]["first_name"]["field_1"].as_string());
         BOOST_REQUIRE_EQUAL("lois", result.rows[row]["last_name"]["field_0"].as_string());
         BOOST_REQUIRE_EQUAL("Lane", result.rows[row]["last_name"]["field_1"].as_string());
         BOOST_REQUIRE_EQUAL("5432 MyStreet", result.rows[row]["street_city_state_cntry"]["field_1"].as_string());
         BOOST_REQUIRE_EQUAL("lois", result.rows[row]["personal_id"]["field_0"].as_string());
         BOOST_REQUIRE_EQUAL("llane", result.rows[row]["personal_id"]["field_1"].as_string());
      }
      else
      {
         BOOST_REQUIRE_EQUAL("steve", result.rows[row]["account_name"].as_string());
         BOOST_REQUIRE_EQUAL("steve", result.rows[row]["first_name"]["field_0"].as_string());
         BOOST_REQUIRE_EQUAL("Steve", result.rows[row]["first_name"]["field_1"].as_string());
         BOOST_REQUIRE_EQUAL("steve", result.rows[row]["last_name"]["field_0"].as_string());
         BOOST_REQUIRE_EQUAL("Jones", result.rows[row]["last_name"]["field_1"].as_string());
         BOOST_REQUIRE_EQUAL("321 MyStreet", result.rows[row]["street_city_state_cntry"]["field_1"].as_string());
         BOOST_REQUIRE_EQUAL("steve", result.rows[row]["personal_id"]["field_0"].as_string());
         BOOST_REQUIRE_EQUAL("sjones", result.rows[row]["personal_id"]["field_1"].as_string());
      }
   };

   produce_blocks(2);

   create_accounts({ "kvaddrbook"_n });

   produce_block();

   set_code(config::system_account_name, contracts::kv_bios_wasm());
   set_abi(config::system_account_name, contracts::kv_bios_abi().data());
   push_action("eosio"_n, "ramkvlimits"_n, "eosio"_n, mutable_variant_object()("k", 1024)("v", 1024)("i", 1024));
   produce_blocks(1);

   set_code( "kvaddrbook"_n, contracts::kv_addr_book_wasm() );
   set_abi( "kvaddrbook"_n, contracts::kv_addr_book_abi().data() );
   produce_blocks(1);

   auto arg = mutable_variant_object();
   push_action("kvaddrbook"_n, "test"_n, "kvaddrbook"_n, arg );

   eosio::chain_apis::read_only plugin(*(this->control), {}, fc::microseconds::maximum());
   eosio::chain_apis::read_only::get_kv_table_rows_params p;
   p.code = "kvaddrbook"_n;
   p.table = "kvaddrbook"_n;
   p.index_name = "accname"_n;
   p.index_value = "john";
   p.encode_type = "name";
   p.lower_bound = {};
   p.upper_bound = {};
   p.json = true;
   p.reverse = false;
   result = plugin.read_only::get_kv_table_rows(p);
   BOOST_REQUIRE_EQUAL(1u, result.rows.size());
   chk_result(0, 2);

   p.index_name = "accname"_n;
   p.index_value = {};
   p.encode_type = "name";
   p.lower_bound = "aaa";
   p.upper_bound = {};
   p.reverse = false;
   result = plugin.read_only::get_kv_table_rows(p);
   BOOST_REQUIRE_EQUAL(4u, result.rows.size());
   chk_result(0, 1);
   chk_result(1, 2);
   chk_result(2, 3);
   chk_result(3, 4);

   p.index_name = "accname"_n;
   p.index_value = {};
   p.encode_type = "name";
   p.lower_bound = "john";
   p.upper_bound = {};
   p.reverse = false;
   result = plugin.read_only::get_kv_table_rows(p);
   BOOST_REQUIRE_EQUAL(3u, result.rows.size());
   chk_result(0, 2);
   chk_result(1, 3);
   chk_result(2, 4);

   p.index_name = "accname"_n;
   p.index_value = {};
   p.encode_type = "name";
   p.lower_bound = "john";
   p.upper_bound = "lois";
   p.reverse = false;
   result = plugin.read_only::get_kv_table_rows(p);
   BOOST_REQUIRE_EQUAL(2u, result.rows.size());
   chk_result(0, 2);

   p.index_name = "accname"_n;
   p.index_value = {};
   p.encode_type = "name";
   p.lower_bound = {};
   p.upper_bound = "steve";
   p.reverse = true;
   result = plugin.read_only::get_kv_table_rows(p);
   BOOST_REQUIRE_EQUAL(4u, result.rows.size());
   chk_result(0, 4);
   chk_result(1, 3);
   chk_result(2, 2);
   chk_result(3, 1);

   p.index_name = "accname"_n;
   p.index_value = {};
   p.encode_type = "name";
   p.lower_bound = "john";
   p.upper_bound = "steve";
   p.reverse = true;
   result = plugin.read_only::get_kv_table_rows(p);
   BOOST_REQUIRE_EQUAL(3u, result.rows.size());
   chk_result(0, 4);
   chk_result(1, 3);

   p.index_name = "accname"_n;
   p.index_value = {};
   p.encode_type = "name";
   p.lower_bound = {};
   p.upper_bound = "aaaa";
   p.reverse = true;
   result = plugin.read_only::get_kv_table_rows(p);
   BOOST_REQUIRE_EQUAL(0u, result.rows.size());

   p.index_name = "accname"_n;
   p.index_value = {};
   p.encode_type = "name";
   p.lower_bound = "steve";
   p.upper_bound = "john";
   p.reverse = true;
   BOOST_CHECK_THROW(plugin.read_only::get_kv_table_rows(p), contract_table_query_exception);

   p.index_name = "accname"_n;
   p.index_value = {};
   p.encode_type = "name";
   p.lower_bound = {};
   p.upper_bound = "john";
   p.reverse = true;
   result = plugin.read_only::get_kv_table_rows(p);
   BOOST_REQUIRE_EQUAL(2u, result.rows.size());
   chk_result(0, 2);
   chk_result(1, 1);
}
FC_LOG_AND_RETHROW()

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>int Config()
{
  static struct InitDialogItem InitItems[]={
  /* 0*/  DI_DOUBLEBOX,3,1,57,19,0,0,0,0,(char *)MTitle,

  /* 1*/  DI_SINGLEBOX,5,2,55,8,0,0,DIF_LEFTTEXT,0,(char *)MRules,
  /* 2*/  DI_CHECKBOX,7,3,0,0,0,0,0,0,(char*)MIgnoreQuotation,
  /* 3*/  DI_CHECKBOX,7,4,0,0,0,0,0,0,(char*)MIgnoreAfter,
  /* 4*/  DI_CHECKBOX,7,5,0,0,0,0,0,0,(char*)MPriority,
  /* 5*/  DI_CHECKBOX,7,6,0,0,0,0,0,0,(char*)MJumpToPair,
  /* 6*/  DI_CHECKBOX,7,7,0,0,0,0,0,0,(char*)MBeep,

  /* 7*/  DI_SINGLEBOX,5,9,55,16,0,0,DIF_LEFTTEXT,0,(char *)MDescriptions,
  /* 8*/  DI_TEXT,7,10,0,0,0,0,0,0,(char*)MTypeQuotes,
  /* 9*/  DI_FIXEDIT,7,11,26,0,0,0,0,0,"",
  /*10*/  DI_TEXT,7,12,0,0,0,0,0,0,(char*)MDescript1,
  /*11*/  DI_FIXEDIT,7,13,26,0,0,0,0,0,"",
  /*12*/  DI_TEXT,7,14,0,0,0,0,0,0,(char*)MDescript2,
  /*13*/  DI_FIXEDIT,7,15,46,0,0,0,0,0,"",

  /*14*/  DI_TEXT,-1,17,0,0,0,0,DIF_SEPARATOR,0,"",
  /*15*/  DI_BUTTON,0,18,0,0,0,0,DIF_CENTERGROUP,1,(char *)MSave,
  /*16*/  DI_BUTTON,0,18,0,0,0,0,DIF_CENTERGROUP,0,(char *)MCancel
  };

  struct FarDialogItem DialogItems[sizeof(InitItems)/sizeof(InitItems[0])];
  InitDialogItems(InitItems,DialogItems,sizeof(InitItems)/sizeof(InitItems[0]));

  DialogItems[2].Param.Selected=Opt.IgnoreQuotes;
  DialogItems[3].Param.Selected=Opt.IgnoreAfter;
  DialogItems[4].Param.Selected=Opt.BracketPrior;
  DialogItems[5].Param.Selected=Opt.JumpToPair;
  DialogItems[6].Param.Selected=Opt.Beep;
  lstrcpy(DialogItems[9].Data.Data,Opt.QuotesType);
  lstrcpy(DialogItems[11].Data.Data,Opt.Brackets1);
  lstrcpy(DialogItems[13].Data.Data,Opt.Brackets2);

  if (Info.Dialog(Info.ModuleNumber,-1,-1,61,21,"Config",
                  DialogItems,sizeof(DialogItems)/sizeof(DialogItems[0])) != 15)
    return(FALSE);

  Opt.IgnoreQuotes=DialogItems[2].Param.Selected;
  Opt.IgnoreAfter=DialogItems[3].Param.Selected;
  Opt.BracketPrior=DialogItems[4].Param.Selected;
  Opt.JumpToPair=DialogItems[5].Param.Selected;
  Opt.Beep=DialogItems[6].Param.Selected;
  lstrcpy(Opt.QuotesType,DialogItems[9].Data.Data);
  lstrcpy(Opt.Brackets1,DialogItems[11].Data.Data);
  lstrcpy(Opt.Brackets2,DialogItems[13].Data.Data);

  HKEY hKey;
  DWORD Disposition;
  if((RegCreateKeyEx(HKEY_CURRENT_USER,PluginRootKey,0,NULL,0,
                  KEY_WRITE,NULL,&hKey,&Disposition)) == ERROR_SUCCESS)
  {
    RegSetValueEx(hKey,"Options",0,REG_BINARY,(LPBYTE)&Opt,sizeof(Opt));
    RegCloseKey(hKey);
  }
  return TRUE;
}
<commit_msg>gcc bug fixes<commit_after>int Config()
{
  static struct InitDialogItem InitItems[]={
  /* 0*/  {DI_DOUBLEBOX,3,1,57,19,0,0,0,0,(char *)MTitle},

  /* 1*/  {DI_SINGLEBOX,5,2,55,8,0,0,DIF_LEFTTEXT,0,(char *)MRules},
  /* 2*/  {DI_CHECKBOX,7,3,0,0,0,0,0,0,(char*)MIgnoreQuotation},
  /* 3*/  {DI_CHECKBOX,7,4,0,0,0,0,0,0,(char*)MIgnoreAfter},
  /* 4*/  {DI_CHECKBOX,7,5,0,0,0,0,0,0,(char*)MPriority},
  /* 5*/  {DI_CHECKBOX,7,6,0,0,0,0,0,0,(char*)MJumpToPair},
  /* 6*/  {DI_CHECKBOX,7,7,0,0,0,0,0,0,(char*)MBeep},

  /* 7*/  {DI_SINGLEBOX,5,9,55,16,0,0,DIF_LEFTTEXT,0,(char *)MDescriptions},
  /* 8*/  {DI_TEXT,7,10,0,0,0,0,0,0,(char*)MTypeQuotes},
  /* 9*/  {DI_FIXEDIT,7,11,26,0,0,0,0,0,""},
  /*10*/  {DI_TEXT,7,12,0,0,0,0,0,0,(char*)MDescript1},
  /*11*/  {DI_FIXEDIT,7,13,26,0,0,0,0,0,""},
  /*12*/  {DI_TEXT,7,14,0,0,0,0,0,0,(char*)MDescript2},
  /*13*/  {DI_FIXEDIT,7,15,46,0,0,0,0,0,""},

  /*14*/  {DI_TEXT,-1,17,0,0,0,0,DIF_SEPARATOR,0,""},
  /*15*/  {DI_BUTTON,0,18,0,0,0,0,DIF_CENTERGROUP,1,(char *)MSave},
  /*16*/  {DI_BUTTON,0,18,0,0,0,0,DIF_CENTERGROUP,0,(char *)MCancel}
  };

  struct FarDialogItem DialogItems[sizeof(InitItems)/sizeof(InitItems[0])];
  InitDialogItems(InitItems,DialogItems,sizeof(InitItems)/sizeof(InitItems[0]));

  DialogItems[2].Param.Selected=Opt.IgnoreQuotes;
  DialogItems[3].Param.Selected=Opt.IgnoreAfter;
  DialogItems[4].Param.Selected=Opt.BracketPrior;
  DialogItems[5].Param.Selected=Opt.JumpToPair;
  DialogItems[6].Param.Selected=Opt.Beep;
  lstrcpy(DialogItems[9].Data.Data,Opt.QuotesType);
  lstrcpy(DialogItems[11].Data.Data,Opt.Brackets1);
  lstrcpy(DialogItems[13].Data.Data,Opt.Brackets2);

  if (Info.Dialog(Info.ModuleNumber,-1,-1,61,21,"Config",
                  DialogItems,sizeof(DialogItems)/sizeof(DialogItems[0])) != 15)
    return(FALSE);

  Opt.IgnoreQuotes=DialogItems[2].Param.Selected;
  Opt.IgnoreAfter=DialogItems[3].Param.Selected;
  Opt.BracketPrior=DialogItems[4].Param.Selected;
  Opt.JumpToPair=DialogItems[5].Param.Selected;
  Opt.Beep=DialogItems[6].Param.Selected;
  lstrcpy(Opt.QuotesType,DialogItems[9].Data.Data);
  lstrcpy(Opt.Brackets1,DialogItems[11].Data.Data);
  lstrcpy(Opt.Brackets2,DialogItems[13].Data.Data);

  HKEY hKey;
  DWORD Disposition;
  if((RegCreateKeyEx(HKEY_CURRENT_USER,PluginRootKey,0,NULL,0,
                  KEY_WRITE,NULL,&hKey,&Disposition)) == ERROR_SUCCESS)
  {
    RegSetValueEx(hKey,"Options",0,REG_BINARY,(LPBYTE)&Opt,sizeof(Opt));
    RegCloseKey(hKey);
  }
  return TRUE;
}
<|endoftext|>