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

/**
 * @file qp_spline_path_generator.cc
 **/
#include <algorithm>
#include <utility>
#include <vector>

#include "modules/planning/optimizer/qp_spline_path/qp_spline_path_generator.h"

#include "modules/common/proto/pnc_point.pb.h"

#include "modules/common/log.h"
#include "modules/common/macro.h"
#include "modules/common/util/string_util.h"
#include "modules/common/util/util.h"
#include "modules/planning/common/planning_gflags.h"
#include "modules/planning/math/double.h"
#include "modules/planning/math/sl_analytic_transformation.h"

namespace apollo {
namespace planning {

using ConstPathObstacleList = std::vector<const PathObstacle*>;

QpSplinePathGenerator::QpSplinePathGenerator(
    const ReferenceLine& reference_line,
    const QpSplinePathConfig& qp_spline_path_config)
    : reference_line_(reference_line),
      qp_spline_path_config_(qp_spline_path_config) {}

bool QpSplinePathGenerator::Generate(
    const ConstPathObstacleList& path_obstacles, const SpeedData& speed_data,
    const common::TrajectoryPoint& init_point, PathData* const path_data) {
  if (!CalculateInitFrenetPoint(init_point, &init_frenet_point_)) {
    AERROR << "Fail to map init point: " << init_point.ShortDebugString();
    return false;
  }
  double start_s = init_frenet_point_.s();
  double end_s = std::min(reference_line_.length(),
                          init_frenet_point_.s() + FLAGS_look_forward_distance);

  QpFrenetFrame qp_frenet_frame(reference_line_, path_obstacles, speed_data,
                                init_frenet_point_, start_s, end_s,
                                qp_spline_path_config_.time_resolution());
  if (!qp_frenet_frame.Init(qp_spline_path_config_.num_output())) {
    AERROR << "Fail to initialize qp frenet frame";
    return false;
  }

  if (!InitCoordRange(qp_frenet_frame, &start_s, &end_s)) {
    AERROR << "Measure natural coord system with s range failed!";
    return false;
  }

  AINFO << "pss path start with " << start_s << ", end with " << end_s;
  if (!InitSpline(init_frenet_point_, start_s, end_s - 0.1)) {
    AERROR << "Init smoothing spline failed with (" << start_s << ",  end_s "
           << end_s;
    return false;
  }

  if (!AddConstraint(qp_frenet_frame)) {
    AERROR << "Fail to setup pss path constraint.";
    return false;
  }
  if (!AddKernel()) {
    AERROR << "Fail to setup pss path kernel.";
    return false;
  }
  if (!Solve()) {
    AERROR << "Fail to solve the qp problem.";
    return false;
  }

  AINFO << common::util::StrCat("Spline dl:", init_frenet_point_.dl(), ", ddl:",
                                init_frenet_point_.ddl());

  // extract data
  const Spline1d& spline = spline_generator_->spline();
  std::vector<common::PathPoint> path_points;

  double start_l = spline(init_frenet_point_.s());
  ReferencePoint ref_point =
      reference_line_.get_reference_point(init_frenet_point_.s());
  common::math::Vec2d xy_point = SLAnalyticTransformation::CalculateXYPoint(
      ref_point.heading(), common::math::Vec2d(ref_point.x(), ref_point.y()),
      start_l);

  double x_diff = xy_point.x() - init_point.path_point().x();
  double y_diff = xy_point.y() - init_point.path_point().y();

  double s = init_frenet_point_.s();
  double s_resolution =
      (end_s - init_frenet_point_.s()) / qp_spline_path_config_.num_output();
  while (Double::Compare(s, end_s) < 0) {
    double l = spline(s);
    double dl = spline.Derivative(s);
    double ddl = spline.SecondOrderDerivative(s);
    ReferencePoint ref_point = reference_line_.get_reference_point(s);
    common::math::Vec2d xy_point = SLAnalyticTransformation::CalculateXYPoint(
        ref_point.heading(), common::math::Vec2d(ref_point.x(), ref_point.y()),
        l);
    xy_point.set_x(xy_point.x() - x_diff);
    xy_point.set_y(xy_point.y() - y_diff);
    double theta = SLAnalyticTransformation::CalculateTheta(
        ref_point.heading(), ref_point.kappa(), l, dl);
    double kappa = SLAnalyticTransformation::CalculateKappa(
        ref_point.kappa(), ref_point.dkappa(), l, dl, ddl);
    common::PathPoint path_point = common::util::MakePathPoint(
        xy_point.x(), xy_point.y(), 0.0, theta, kappa, 0.0, 0.0);
    if (path_points.size() != 0) {
      double distance =
          common::util::Distance2D(path_points.back(), path_point);
      path_point.set_s(path_points.back().s() + distance);
    }
    if (Double::Compare(path_point.s(), end_s) >= 0) {
      break;
    }
    path_points.push_back(path_point);
    s += s_resolution;
  }
  path_data->SetReferenceLine(&reference_line_);
  path_data->SetDiscretizedPath(DiscretizedPath(path_points));
  return true;
}

bool QpSplinePathGenerator::CalculateInitFrenetPoint(
    const common::TrajectoryPoint& traj_point,
    common::FrenetFramePoint* const frenet_frame_point) {
  common::SLPoint sl_point;
  if (!reference_line_.get_point_in_frenet_frame(
          {traj_point.path_point().x(), traj_point.path_point().y()},
          &sl_point)) {
    return false;
  }
  frenet_frame_point->set_s(sl_point.s());
  frenet_frame_point->set_l(sl_point.l());
  const double theta = traj_point.path_point().theta();
  const double kappa = traj_point.path_point().kappa();
  const double l = frenet_frame_point->l();

  ReferencePoint ref_point =
      reference_line_.get_reference_point(frenet_frame_point->s());

  const double theta_ref = ref_point.heading();
  const double kappa_ref = ref_point.kappa();
  const double dkappa_ref = ref_point.dkappa();

  const double dl = SLAnalyticTransformation::CalculateLateralDerivative(
      theta_ref, theta, l, kappa_ref);
  const double ddl =
      SLAnalyticTransformation::CalculateSecondOrderLateralDerivative(
          theta_ref, theta, kappa_ref, kappa, dkappa_ref, l);
  frenet_frame_point->set_dl(dl);
  frenet_frame_point->set_ddl(ddl);
  return true;
}

bool QpSplinePathGenerator::InitCoordRange(const QpFrenetFrame& qp_frenet_frame,
                                           double* const start_s,
                                           double* const end_s) {
  // TODO(all): step 1 get current sl coordinate - with init coordinate point
  double start_point = std::max(init_frenet_point_.s() - 5.0, 0.0);

  const ReferenceLine& reference_line_ = qp_frenet_frame.GetReferenceLine();

  double end_point = std::min(reference_line_.length(),
                              *start_s + FLAGS_look_forward_distance);

  end_point =
      std::min(qp_frenet_frame.feasible_longitudinal_upper_bound(), end_point);
  *start_s = start_point;
  *end_s = end_point;
  return true;
}

bool QpSplinePathGenerator::InitSpline(
    const common::FrenetFramePoint& init_frenet_point, const double start_s,
    const double end_s) {
  // set knots
  if (qp_spline_path_config_.number_of_knots() <= 1) {
    AERROR << "Two few number of knots: "
           << qp_spline_path_config_.number_of_knots();
    return false;
  }
  double distance = std::fmin(reference_line_.map_path().length(), end_s) -
                    init_frenet_point.s();
  distance = std::fmin(distance, FLAGS_look_forward_distance);
  const double delta_s = distance / qp_spline_path_config_.number_of_knots();
  double curr_knot_s = init_frenet_point.s();

  for (uint32_t i = 0; i <= qp_spline_path_config_.number_of_knots(); ++i) {
    knots_.push_back(curr_knot_s);
    curr_knot_s += delta_s;
  }

  // spawn a new spline generator
  spline_generator_.reset(
      new Spline1dGenerator(knots_, qp_spline_path_config_.spline_order()));

  // set evaluated_s_
  std::uint32_t num_evaluated_s =
      qp_spline_path_config_.number_of_fx_constraint_knots();
  if (num_evaluated_s <= 2) {
    AERROR << "Too few evaluated positions. Suggest: > 2, current number: "
           << num_evaluated_s;
    return false;
  }
  const double ds = (spline_generator_->spline().x_knots().back() -
                     spline_generator_->spline().x_knots().front()) /
                    num_evaluated_s;
  double curr_evaluated_s = spline_generator_->spline().x_knots().front();

  for (uint32_t i = 0; i < num_evaluated_s; ++i) {
    evaluated_s_.push_back(curr_evaluated_s);
    curr_evaluated_s += ds;
  }

  return true;
}

bool QpSplinePathGenerator::AddConstraint(
    const QpFrenetFrame& qp_frenet_frame) {
  Spline1dConstraint* spline_constraint =
      spline_generator_->mutable_spline_constraint();

  // add init status constraint
  spline_constraint->AddPointConstraint(init_frenet_point_.s(),
                                             init_frenet_point_.l());
  spline_constraint->AddPointDerivativeConstraint(init_frenet_point_.s(),
                                                     init_frenet_point_.dl());
  spline_constraint->AddPointSecondDerivativeConstraint(
      init_frenet_point_.s(), init_frenet_point_.ddl());
  ADEBUG << "init frenet point: " << init_frenet_point_.ShortDebugString();

  // add end point constraint
  spline_constraint->AddPointConstraint(knots_.back(), 0.0);
  spline_constraint->AddPointDerivativeConstraint(knots_.back(), 0.0);
  spline_constraint->AddPointSecondDerivativeConstraint(knots_.back(), 0.0);

  // add map bound constraint
  std::vector<double> boundary_low;
  std::vector<double> boundary_high;
  for (const double s : evaluated_s_) {
    std::pair<double, double> boundary = std::make_pair(0.0, 0.0);
    qp_frenet_frame.GetMapBound(s, &boundary);
    boundary_low.push_back(boundary.first);
    boundary_high.push_back(boundary.second);
  }
  if (!spline_constraint->AddBoundary(evaluated_s_, boundary_low,
                                          boundary_high)) {
    AERROR << "Add boundary constraint failed";
    return false;
  }

  // add spline joint third derivative constraint
  if (!spline_constraint->AddThirdDerivativeSmoothConstraint()) {
    AERROR << "Add spline joint third derivative constraint failed!";
    return false;
  }

  return true;
}

bool QpSplinePathGenerator::AddKernel() {
  Spline1dKernel* spline_kernel = spline_generator_->mutable_spline_kernel();

  if (qp_spline_path_config_.regularization_weight() > 0) {
    spline_kernel->AddRegularization(
        qp_spline_path_config_.regularization_weight());
  }

  if (qp_spline_path_config_.derivative_weight() > 0) {
    spline_kernel->add_derivative_kernel_matrix(
        qp_spline_path_config_.derivative_weight());
  }

  if (qp_spline_path_config_.second_derivative_weight() > 0) {
    spline_kernel->add_second_order_derivative_matrix(
        qp_spline_path_config_.second_derivative_weight());
  }

  if (qp_spline_path_config_.third_derivative_weight() > 0) {
    spline_kernel->add_third_order_derivative_matrix(
        qp_spline_path_config_.third_derivative_weight());
  }

  // reference line kernel
  if (qp_spline_path_config_.number_of_knots() > 1) {
    std::vector<double> l_vec(knots_.size(), 0.0);
    spline_kernel->add_reference_line_kernel_matrix(
        knots_, l_vec, qp_spline_path_config_.reference_line_weight());
  }
  return true;
}

bool QpSplinePathGenerator::Solve() {
  if (!spline_generator_->Solve()) {
    AERROR << "Could not solve the qp problem in spline path generator.";
    return false;
  }
  return true;
}

}  // namespace planning
}  // namespace apollo
<commit_msg>planning: add qp path boundary debug log.<commit_after>/******************************************************************************
 * Copyright 2017 The Apollo Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *****************************************************************************/

/**
 * @file qp_spline_path_generator.cc
 **/
#include <algorithm>
#include <utility>
#include <vector>

#include "modules/planning/optimizer/qp_spline_path/qp_spline_path_generator.h"

#include "modules/common/proto/pnc_point.pb.h"

#include "modules/common/log.h"
#include "modules/common/macro.h"
#include "modules/common/util/string_util.h"
#include "modules/common/util/util.h"
#include "modules/planning/common/planning_gflags.h"
#include "modules/planning/math/double.h"
#include "modules/planning/math/sl_analytic_transformation.h"

namespace apollo {
namespace planning {

using ConstPathObstacleList = std::vector<const PathObstacle*>;

QpSplinePathGenerator::QpSplinePathGenerator(
    const ReferenceLine& reference_line,
    const QpSplinePathConfig& qp_spline_path_config)
    : reference_line_(reference_line),
      qp_spline_path_config_(qp_spline_path_config) {}

bool QpSplinePathGenerator::Generate(
    const ConstPathObstacleList& path_obstacles, const SpeedData& speed_data,
    const common::TrajectoryPoint& init_point, PathData* const path_data) {
  if (!CalculateInitFrenetPoint(init_point, &init_frenet_point_)) {
    AERROR << "Fail to map init point: " << init_point.ShortDebugString();
    return false;
  }
  double start_s = init_frenet_point_.s();
  double end_s = std::min(reference_line_.length(),
                          init_frenet_point_.s() + FLAGS_look_forward_distance);

  QpFrenetFrame qp_frenet_frame(reference_line_, path_obstacles, speed_data,
                                init_frenet_point_, start_s, end_s,
                                qp_spline_path_config_.time_resolution());
  if (!qp_frenet_frame.Init(qp_spline_path_config_.num_output())) {
    AERROR << "Fail to initialize qp frenet frame";
    return false;
  }

  if (!InitCoordRange(qp_frenet_frame, &start_s, &end_s)) {
    AERROR << "Measure natural coord system with s range failed!";
    return false;
  }

  AINFO << "pss path start with " << start_s << ", end with " << end_s;
  if (!InitSpline(init_frenet_point_, start_s, end_s - 0.1)) {
    AERROR << "Init smoothing spline failed with (" << start_s << ",  end_s "
           << end_s;
    return false;
  }

  if (!AddConstraint(qp_frenet_frame)) {
    AERROR << "Fail to setup pss path constraint.";
    return false;
  }
  if (!AddKernel()) {
    AERROR << "Fail to setup pss path kernel.";
    return false;
  }
  if (!Solve()) {
    AERROR << "Fail to solve the qp problem.";
    return false;
  }

  AINFO << common::util::StrCat("Spline dl:", init_frenet_point_.dl(), ", ddl:",
                                init_frenet_point_.ddl());

  // extract data
  const Spline1d& spline = spline_generator_->spline();
  std::vector<common::PathPoint> path_points;

  double start_l = spline(init_frenet_point_.s());
  ReferencePoint ref_point =
      reference_line_.get_reference_point(init_frenet_point_.s());
  common::math::Vec2d xy_point = SLAnalyticTransformation::CalculateXYPoint(
      ref_point.heading(), common::math::Vec2d(ref_point.x(), ref_point.y()),
      start_l);

  double x_diff = xy_point.x() - init_point.path_point().x();
  double y_diff = xy_point.y() - init_point.path_point().y();

  double s = init_frenet_point_.s();
  double s_resolution =
      (end_s - init_frenet_point_.s()) / qp_spline_path_config_.num_output();
  while (Double::Compare(s, end_s) < 0) {
    double l = spline(s);
    double dl = spline.Derivative(s);
    double ddl = spline.SecondOrderDerivative(s);
    ReferencePoint ref_point = reference_line_.get_reference_point(s);
    common::math::Vec2d xy_point = SLAnalyticTransformation::CalculateXYPoint(
        ref_point.heading(), common::math::Vec2d(ref_point.x(), ref_point.y()),
        l);
    xy_point.set_x(xy_point.x() - x_diff);
    xy_point.set_y(xy_point.y() - y_diff);
    double theta = SLAnalyticTransformation::CalculateTheta(
        ref_point.heading(), ref_point.kappa(), l, dl);
    double kappa = SLAnalyticTransformation::CalculateKappa(
        ref_point.kappa(), ref_point.dkappa(), l, dl, ddl);
    common::PathPoint path_point = common::util::MakePathPoint(
        xy_point.x(), xy_point.y(), 0.0, theta, kappa, 0.0, 0.0);
    if (path_points.size() != 0) {
      double distance =
          common::util::Distance2D(path_points.back(), path_point);
      path_point.set_s(path_points.back().s() + distance);
    }
    if (Double::Compare(path_point.s(), end_s) >= 0) {
      break;
    }
    path_points.push_back(path_point);
    s += s_resolution;
  }
  path_data->SetReferenceLine(&reference_line_);
  path_data->SetDiscretizedPath(DiscretizedPath(path_points));
  return true;
}

bool QpSplinePathGenerator::CalculateInitFrenetPoint(
    const common::TrajectoryPoint& traj_point,
    common::FrenetFramePoint* const frenet_frame_point) {
  common::SLPoint sl_point;
  if (!reference_line_.get_point_in_frenet_frame(
          {traj_point.path_point().x(), traj_point.path_point().y()},
          &sl_point)) {
    return false;
  }
  frenet_frame_point->set_s(sl_point.s());
  frenet_frame_point->set_l(sl_point.l());
  const double theta = traj_point.path_point().theta();
  const double kappa = traj_point.path_point().kappa();
  const double l = frenet_frame_point->l();

  ReferencePoint ref_point =
      reference_line_.get_reference_point(frenet_frame_point->s());

  const double theta_ref = ref_point.heading();
  const double kappa_ref = ref_point.kappa();
  const double dkappa_ref = ref_point.dkappa();

  const double dl = SLAnalyticTransformation::CalculateLateralDerivative(
      theta_ref, theta, l, kappa_ref);
  const double ddl =
      SLAnalyticTransformation::CalculateSecondOrderLateralDerivative(
          theta_ref, theta, kappa_ref, kappa, dkappa_ref, l);
  frenet_frame_point->set_dl(dl);
  frenet_frame_point->set_ddl(ddl);
  return true;
}

bool QpSplinePathGenerator::InitCoordRange(const QpFrenetFrame& qp_frenet_frame,
                                           double* const start_s,
                                           double* const end_s) {
  // TODO(all): step 1 get current sl coordinate - with init coordinate point
  double start_point = std::max(init_frenet_point_.s() - 5.0, 0.0);

  const ReferenceLine& reference_line_ = qp_frenet_frame.GetReferenceLine();

  double end_point = std::min(reference_line_.length(),
                              *start_s + FLAGS_look_forward_distance);

  end_point =
      std::min(qp_frenet_frame.feasible_longitudinal_upper_bound(), end_point);
  *start_s = start_point;
  *end_s = end_point;
  return true;
}

bool QpSplinePathGenerator::InitSpline(
    const common::FrenetFramePoint& init_frenet_point, const double start_s,
    const double end_s) {
  // set knots
  if (qp_spline_path_config_.number_of_knots() <= 1) {
    AERROR << "Two few number of knots: "
           << qp_spline_path_config_.number_of_knots();
    return false;
  }
  double distance = std::fmin(reference_line_.map_path().length(), end_s) -
                    init_frenet_point.s();
  distance = std::fmin(distance, FLAGS_look_forward_distance);
  const double delta_s = distance / qp_spline_path_config_.number_of_knots();
  double curr_knot_s = init_frenet_point.s();

  for (uint32_t i = 0; i <= qp_spline_path_config_.number_of_knots(); ++i) {
    knots_.push_back(curr_knot_s);
    curr_knot_s += delta_s;
  }

  // spawn a new spline generator
  spline_generator_.reset(
      new Spline1dGenerator(knots_, qp_spline_path_config_.spline_order()));

  // set evaluated_s_
  std::uint32_t num_evaluated_s =
      qp_spline_path_config_.number_of_fx_constraint_knots();
  if (num_evaluated_s <= 2) {
    AERROR << "Too few evaluated positions. Suggest: > 2, current number: "
           << num_evaluated_s;
    return false;
  }
  const double ds = (spline_generator_->spline().x_knots().back() -
                     spline_generator_->spline().x_knots().front()) /
                    num_evaluated_s;
  double curr_evaluated_s = spline_generator_->spline().x_knots().front();

  for (uint32_t i = 0; i < num_evaluated_s; ++i) {
    evaluated_s_.push_back(curr_evaluated_s);
    curr_evaluated_s += ds;
  }

  return true;
}

bool QpSplinePathGenerator::AddConstraint(
    const QpFrenetFrame& qp_frenet_frame) {
  Spline1dConstraint* spline_constraint =
      spline_generator_->mutable_spline_constraint();

  // add init status constraint
  spline_constraint->AddPointConstraint(init_frenet_point_.s(),
                                             init_frenet_point_.l());
  spline_constraint->AddPointDerivativeConstraint(init_frenet_point_.s(),
                                                     init_frenet_point_.dl());
  spline_constraint->AddPointSecondDerivativeConstraint(
      init_frenet_point_.s(), init_frenet_point_.ddl());
  ADEBUG << "init frenet point: " << init_frenet_point_.ShortDebugString();

  // add end point constraint
  spline_constraint->AddPointConstraint(knots_.back(), 0.0);
  spline_constraint->AddPointDerivativeConstraint(knots_.back(), 0.0);
  spline_constraint->AddPointSecondDerivativeConstraint(knots_.back(), 0.0);

  // add map bound constraint
  std::vector<double> boundary_low;
  std::vector<double> boundary_high;
  for (const double s : evaluated_s_) {
    std::pair<double, double> boundary = std::make_pair(0.0, 0.0);
    qp_frenet_frame.GetMapBound(s, &boundary);
    boundary_low.push_back(boundary.first);
    boundary_high.push_back(boundary.second);
    ADEBUG << "s:" << s << " boundary_low:" << boundary.first
        << " boundary_high:" << boundary.second;

  }
  if (!spline_constraint->AddBoundary(evaluated_s_, boundary_low,
                                          boundary_high)) {
    AERROR << "Add boundary constraint failed";
    return false;
  }

  // add spline joint third derivative constraint
  if (!spline_constraint->AddThirdDerivativeSmoothConstraint()) {
    AERROR << "Add spline joint third derivative constraint failed!";
    return false;
  }

  return true;
}

bool QpSplinePathGenerator::AddKernel() {
  Spline1dKernel* spline_kernel = spline_generator_->mutable_spline_kernel();

  if (qp_spline_path_config_.regularization_weight() > 0) {
    spline_kernel->AddRegularization(
        qp_spline_path_config_.regularization_weight());
  }

  if (qp_spline_path_config_.derivative_weight() > 0) {
    spline_kernel->add_derivative_kernel_matrix(
        qp_spline_path_config_.derivative_weight());
  }

  if (qp_spline_path_config_.second_derivative_weight() > 0) {
    spline_kernel->add_second_order_derivative_matrix(
        qp_spline_path_config_.second_derivative_weight());
  }

  if (qp_spline_path_config_.third_derivative_weight() > 0) {
    spline_kernel->add_third_order_derivative_matrix(
        qp_spline_path_config_.third_derivative_weight());
  }

  // reference line kernel
  if (qp_spline_path_config_.number_of_knots() > 1) {
    std::vector<double> l_vec(knots_.size(), 0.0);
    spline_kernel->add_reference_line_kernel_matrix(
        knots_, l_vec, qp_spline_path_config_.reference_line_weight());
  }
  return true;
}

bool QpSplinePathGenerator::Solve() {
  if (!spline_generator_->Solve()) {
    AERROR << "Could not solve the qp problem in spline path generator.";
    return false;
  }
  return true;
}

}  // namespace planning
}  // namespace apollo
<|endoftext|>


<commit_before>/*------------------------------------------------------------------------
* (The MIT License)
*
* Copyright (c) 2008-2011 Rhomobile, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* http://rhomobile.com
*------------------------------------------------------------------------*/

#include "ClientRegister.h"
#include "SyncThread.h"
#include "ILoginListener.h"
#include "common/RhoConf.h"
#include "common/RhodesApp.h"
#include "System.h"

rho::String rho_sysimpl_get_phone_id();

namespace rho{
namespace sync{

using namespace rho::common;
using namespace rho::db;

static const int THREAD_WAIT_TIMEOUT = 10;
static const char * const PUSH_PIN_NAME = "push_pin";

IMPLEMENT_LOGCLASS(CClientRegister,"ClientRegister");

CClientRegister* CClientRegister::m_pInstance = 0;
bool CClientRegister::s_sslVerifyPeer = true;
VectorPtr<ILoginListener*> CClientRegister::s_loginListeners;

/*static*/ CClientRegister* CClientRegister::Get()
{
    if (!m_pInstance)
    {
        m_pInstance = new CClientRegister();
    }
    return m_pInstance;
}

/*static*/ CClientRegister* CClientRegister::Create()
{
    String session = CSyncThread::getSyncEngine().loadSession();
    if (session.length() > 0)
    {
        Get()->setRhoconnectCredentials("", "", session);
    }
    Get()->startUp();
    return m_pInstance;
}

/*static*/ CClientRegister* CClientRegister::Create(const String& devicePin)
{
    Get()->setDevicehPin(devicePin);
    return m_pInstance;
}

/*static*/ void CClientRegister::Stop()
{
    if(m_pInstance)
    {
        m_pInstance->doStop();
    }
}

/*static*/ void CClientRegister::Destroy()
{
    if ( m_pInstance )
        delete m_pInstance;

    m_pInstance = 0;
}

/*static*/ void CClientRegister::SetSslVerifyPeer(boolean b)
{
    s_sslVerifyPeer = b;
    if (m_pInstance)
        m_pInstance->m_NetRequest.setSslVerifyPeer(b);
}

bool CClientRegister::GetSslVerifyPeer()
{
    return s_sslVerifyPeer;
}

/*static*/void CClientRegister::AddLoginListener(ILoginListener* listener)
{
    s_loginListeners.addElement(listener);
}

CClientRegister::CClientRegister() : m_nPollInterval(POLL_INTERVAL_SECONDS)
{
    m_NetRequest.setSslVerifyPeer(s_sslVerifyPeer);

}

CClientRegister::~CClientRegister()
{
    doStop();
    m_pInstance = null;
}
void CClientRegister::setRhoconnectCredentials(const String& user, const String& pass, const String& session)
{
    LOG(INFO) + "New Sync credentials - user: " + user + ", sess: " + session;

    for(VectorPtr<ILoginListener*>::iterator I = s_loginListeners.begin(); I != s_loginListeners.end(); ++I)
    {
        (*I)->onLogin(user, pass, session);
    }
    startUp();
}

void CClientRegister::dropRhoconnectCredentials(const String& session)
{
    for(VectorPtr<ILoginListener*>::iterator I = s_loginListeners.begin(); I != s_loginListeners.end(); ++I)
    {
        (*I)->onLogout(session);
    }
}

void CClientRegister::setDevicehPin(const String& pin)
{
    m_strDevicePin = pin;
    RHOCONF().setString(PUSH_PIN_NAME, pin, true);

    if (pin.length() > 0)
    {
        startUp();
    } else
    {
        doStop();
    }
}

void CClientRegister::startUp()
{
    if ( RHOCONF().getString("syncserver").length() > 0 )
    {
        LOG(INFO) + "Starting ClientRegister...";

        start(epLow);
        stopWait();
    }
}

void CClientRegister::run()
{
    unsigned i = 0;
    LOG(INFO)+"ClientRegister is started";
	while(!isStopping())
	{
        i++;
        LOG(INFO)+"Try to register: " + i;
        if ( CSyncThread::getInstance() != null )
		{
			if ( doRegister(CSyncThread::getSyncEngine()) )
			{
			    LOG(INFO)+"Registered: " + i;
				break;
			}
		} else
		    LOG(INFO)+"SyncThread is not ready";

		LOG(INFO)+"Waiting for "+ m_nPollInterval+ " sec to try again to register client";
		wait(m_nPollInterval*1000);
	}
    LOG(INFO)+"ClientRegister thread shutdown";
}

String CClientRegister::getRegisterBody(const String& strClientID)
{
	IRhoPushClient* pushClient = RHODESAPP().getDefaultPushClient();
	int port = RHOCONF().getInt("push_port");

	String body = CSyncThread::getSyncEngine().getProtocol().getClientRegisterBody( strClientID, m_strDevicePin,
		port > 0 ? port : DEFAULT_PUSH_PORT, rho_rhodesapp_getplatform(), rho::System::getPhoneId(),
        /*device_push_type*/ (0 != pushClient) ? pushClient->getType() : "" /*it means native push type*/);

	LOG(INFO)+"getRegisterBody() BODY is: " + body;
	return body;

	/*
    if(m_isAns)
		body = CSyncThread::getSyncEngine().getProtocol().getClientAnsRegisterBody( strClientID, m_strDevicePin,
			port > 0 ? port : DEFAULT_PUSH_PORT, rho_rhodesapp_getplatform(), rho_sysimpl_get_phone_id() );
	else
		body = CSyncThread::getSyncEngine().getProtocol().getClientRegisterBody( strClientID, m_strDevicePin,
			port > 0 ? port : DEFAULT_PUSH_PORT, rho_rhodesapp_getplatform(), rho_sysimpl_get_phone_id() );
	*/

}

boolean CClientRegister::doRegister(CSyncEngine& oSync)
{
    String session = oSync.loadSession();
    if ( session.length() == 0 )
    {
        m_nPollInterval = POLL_INTERVAL_INFINITE;
        LOG(INFO)+"Session is empty, do register later";
        return false;
    }
    if ( m_strDevicePin.length() == 0 )
    {
        m_strDevicePin = RHOCONF().getString(PUSH_PIN_NAME);
    }
    if ( m_strDevicePin.length() == 0 )
    {
        m_nPollInterval = POLL_INTERVAL_INFINITE;
        LOG(INFO)+"Device PUSH pin is empty, do register later";
        return false;
    }
    m_nPollInterval = POLL_INTERVAL_SECONDS;

	String client_id = oSync.loadClientID();
	if ( client_id.length() == 0 )
	{
        LOG(WARNING)+"Sync client_id is empty, do register later";
		return false;
	}

    IDBResult res = CDBAdapter::getUserDB().executeSQL("SELECT token,token_sent from client_info");
    if ( !res.isEnd() ) {
		String token = res.getStringByIdx(0);
		int token_sent = res.getIntByIdx(1) && !RHOCONF().getBool("register_push_at_startup");
		if ( m_strDevicePin.compare(token) == 0 && token_sent > 0 )
		{
			//token in db same as new one and it was already send to the server
			//so we do nothing
			return true;
		}
    }
	String strBody = getRegisterBody(client_id);
    NetResponse resp = getNet().pushData( oSync.getProtocol().getClientRegisterUrl(client_id), strBody, &oSync );
	if( resp.isOK() )
    {
//				try {
			CDBAdapter::getUserDB().executeSQL("UPDATE client_info SET token_sent=?, token=?", 1, m_strDevicePin );
//				} catch(Exception ex) {
//					LOG.ERROR("Error saving token_sent to the DB...");
//				}
		LOG(INFO)+"Registered client sucessfully...";
		return true;
	}

	LOG(WARNING)+"Network error: "+ resp.getRespCode();
	return false;
}

void CClientRegister::doStop()
{
    LOG(INFO) + "Stopping ClientRegister...";

    m_NetRequest.cancel();
    stop(WAIT_BEFOREKILL_SECONDS);
}

}
}
<commit_msg>Remove storing device pin in rhoconfig<commit_after>/*------------------------------------------------------------------------
* (The MIT License)
*
* Copyright (c) 2008-2011 Rhomobile, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* http://rhomobile.com
*------------------------------------------------------------------------*/

#include "ClientRegister.h"
#include "SyncThread.h"
#include "ILoginListener.h"
#include "common/RhoConf.h"
#include "common/RhodesApp.h"
#include "System.h"

rho::String rho_sysimpl_get_phone_id();

namespace rho{
namespace sync{

using namespace rho::common;
using namespace rho::db;

static const int THREAD_WAIT_TIMEOUT = 10;

IMPLEMENT_LOGCLASS(CClientRegister,"ClientRegister");

CClientRegister* CClientRegister::m_pInstance = 0;
bool CClientRegister::s_sslVerifyPeer = true;
VectorPtr<ILoginListener*> CClientRegister::s_loginListeners;

/*static*/ CClientRegister* CClientRegister::Get()
{
    if (!m_pInstance)
    {
        m_pInstance = new CClientRegister();
    }
    return m_pInstance;
}

/*static*/ CClientRegister* CClientRegister::Create()
{
    LOG(TRACE) + "Loading rhoconnect session...";
    String session = CSyncThread::getSyncEngine().loadSession();
    if (session.length() > 0)
    {
        LOG(TRACE) + "Loaded";
        Get()->setRhoconnectCredentials("", "", session);
    }
    LOG(TRACE) + "Starting ClientRegister";
    Get()->startUp();
    return m_pInstance;
}

/*static*/ CClientRegister* CClientRegister::Create(const String& devicePin)
{
    Get()->setDevicehPin(devicePin);
    return m_pInstance;
}

/*static*/ void CClientRegister::Stop()
{
    if(m_pInstance)
    {
        m_pInstance->doStop();
    }
}

/*static*/ void CClientRegister::Destroy()
{
    if ( m_pInstance )
        delete m_pInstance;

    m_pInstance = 0;
}

/*static*/ void CClientRegister::SetSslVerifyPeer(boolean b)
{
    s_sslVerifyPeer = b;
    if (m_pInstance)
        m_pInstance->m_NetRequest.setSslVerifyPeer(b);
}

bool CClientRegister::GetSslVerifyPeer()
{
    return s_sslVerifyPeer;
}

/*static*/void CClientRegister::AddLoginListener(ILoginListener* listener)
{
    s_loginListeners.addElement(listener);
}

CClientRegister::CClientRegister() : m_nPollInterval(POLL_INTERVAL_SECONDS)
{
    m_NetRequest.setSslVerifyPeer(s_sslVerifyPeer);

}

CClientRegister::~CClientRegister()
{
    doStop();
    m_pInstance = null;
}
void CClientRegister::setRhoconnectCredentials(const String& user, const String& pass, const String& session)
{
    LOG(INFO) + "New Sync credentials - user: " + user + ", sess: " + session;

    for(VectorPtr<ILoginListener*>::iterator I = s_loginListeners.begin(); I != s_loginListeners.end(); ++I)
    {
        (*I)->onLogin(user, pass, session);
    }
    startUp();
}

void CClientRegister::dropRhoconnectCredentials(const String& session)
{
    for(VectorPtr<ILoginListener*>::iterator I = s_loginListeners.begin(); I != s_loginListeners.end(); ++I)
    {
        (*I)->onLogout(session);
    }
}

void CClientRegister::setDevicehPin(const String& pin)
{
    m_strDevicePin = pin;

    if (pin.length() > 0)
    {
        startUp();
    } else
    {
        doStop();
    }
}

void CClientRegister::startUp()
{
    if ( RHOCONF().getString("syncserver").length() > 0 )
    {
        LOG(INFO) + "Starting ClientRegister...";

        start(epLow);
        stopWait();
    }
}

void CClientRegister::run()
{
    unsigned i = 0;
    LOG(INFO)+"ClientRegister is started";
	while(!isStopping())
	{
        i++;
        LOG(INFO)+"Try to register: " + i;
        if ( CSyncThread::getInstance() != null )
		{
			if ( doRegister(CSyncThread::getSyncEngine()) )
			{
			    LOG(INFO)+"Registered: " + i;
				break;
			}
		} else
		    LOG(INFO)+"SyncThread is not ready";

		LOG(INFO)+"Waiting for "+ m_nPollInterval+ " sec to try again to register client";
		wait(m_nPollInterval*1000);
	}
    LOG(INFO)+"ClientRegister thread shutdown";
}

String CClientRegister::getRegisterBody(const String& strClientID)
{
	IRhoPushClient* pushClient = RHODESAPP().getDefaultPushClient();
	int port = RHOCONF().getInt("push_port");

	String body = CSyncThread::getSyncEngine().getProtocol().getClientRegisterBody( strClientID, m_strDevicePin,
		port > 0 ? port : DEFAULT_PUSH_PORT, rho_rhodesapp_getplatform(), rho::System::getPhoneId(),
        /*device_push_type*/ (0 != pushClient) ? pushClient->getType() : "" /*it means native push type*/);

	LOG(INFO)+"getRegisterBody() BODY is: " + body;
	return body;

	/*
    if(m_isAns)
		body = CSyncThread::getSyncEngine().getProtocol().getClientAnsRegisterBody( strClientID, m_strDevicePin,
			port > 0 ? port : DEFAULT_PUSH_PORT, rho_rhodesapp_getplatform(), rho_sysimpl_get_phone_id() );
	else
		body = CSyncThread::getSyncEngine().getProtocol().getClientRegisterBody( strClientID, m_strDevicePin,
			port > 0 ? port : DEFAULT_PUSH_PORT, rho_rhodesapp_getplatform(), rho_sysimpl_get_phone_id() );
	*/

}

boolean CClientRegister::doRegister(CSyncEngine& oSync)
{
    String session = oSync.loadSession();
    if ( session.length() == 0 )
    {
        m_nPollInterval = POLL_INTERVAL_INFINITE;
        LOG(INFO)+"Session is empty, do register later";
        return false;
    }
    if ( m_strDevicePin.length() == 0 )
    {
        m_nPollInterval = POLL_INTERVAL_INFINITE;
        LOG(INFO)+"Device PUSH pin is empty, do register later";
        return false;
    }
    m_nPollInterval = POLL_INTERVAL_SECONDS;

	String client_id = oSync.loadClientID();
	if ( client_id.length() == 0 )
	{
        LOG(WARNING)+"Sync client_id is empty, do register later";
		return false;
	}

    IDBResult res = CDBAdapter::getUserDB().executeSQL("SELECT token,token_sent from client_info");
    if ( !res.isEnd() ) {
		String token = res.getStringByIdx(0);
		int token_sent = res.getIntByIdx(1) && !RHOCONF().getBool("register_push_at_startup");
		if ( m_strDevicePin.compare(token) == 0 && token_sent > 0 )
		{
			//token in db same as new one and it was already send to the server
			//so we do nothing
			return true;
		}
    }
	String strBody = getRegisterBody(client_id);
    NetResponse resp = getNet().pushData( oSync.getProtocol().getClientRegisterUrl(client_id), strBody, &oSync );
	if( resp.isOK() )
    {
//				try {
			CDBAdapter::getUserDB().executeSQL("UPDATE client_info SET token_sent=?, token=?", 1, m_strDevicePin );
//				} catch(Exception ex) {
//					LOG.ERROR("Error saving token_sent to the DB...");
//				}
		LOG(INFO)+"Registered client sucessfully...";
		return true;
	}

	LOG(WARNING)+"Network error: "+ resp.getRespCode();
	return false;
}

void CClientRegister::doStop()
{
    LOG(INFO) + "Stopping ClientRegister...";

    m_NetRequest.cancel();
    stop(WAIT_BEFOREKILL_SECONDS);
}

}
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2010, 2012-2013, 2015,2017-2019 ARM Limited
 * All rights reserved
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * Copyright (c) 2002-2006 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "arch/arm/fs_workload.hh"

#include "arch/arm/faults.hh"
#include "base/loader/object_file.hh"
#include "base/loader/symtab.hh"
#include "cpu/thread_context.hh"
#include "dev/arm/gic_v2.hh"
#include "kern/system_events.hh"
#include "params/ArmFsWorkload.hh"

namespace ArmISA
{

void
SkipFunc::returnFromFuncIn(ThreadContext *tc)
{
    PCState newPC = tc->pcState();
    if (inAArch64(tc)) {
        newPC.set(tc->readIntReg(INTREG_X30));
    } else {
        newPC.set(tc->readIntReg(ReturnAddressReg) & ~ULL(1));
    }

    CheckerCPU *checker = tc->getCheckerCpuPtr();
    if (checker) {
        tc->pcStateNoRecord(newPC);
    } else {
        tc->pcState(newPC);
    }
}

FsWorkload::FsWorkload(Params *p)
  : OsKernel(*p),
    kernelEntry((entry & loadAddrMask) + loadAddrOffset)
{
    bootLoaders.reserve(p->boot_loader.size());
    for (const auto &bl : p->boot_loader) {
        std::unique_ptr<ObjectFile> bl_obj;
        bl_obj.reset(createObjectFile(bl));

        fatal_if(!bl_obj, "Could not read bootloader: %s", bl);
        bootLoaders.emplace_back(std::move(bl_obj));
    }

    if (obj) {
        bootldr = getBootLoader(obj);
    } else if (!bootLoaders.empty()) {
        // No kernel specified, default to the first boot loader
        bootldr = bootLoaders[0].get();
    }

    fatal_if(!bootLoaders.empty() && !bootldr,
             "Can't find a matching boot loader / kernel combination!");

    if (bootldr) {
        bootldr->loadGlobalSymbols(debugSymbolTable);

        _highestELIs64 = (bootldr->getArch() == ObjectFile::Arm64);
    } else {
        _highestELIs64 = (obj->getArch() == ObjectFile::Arm64);
    }
}

void
FsWorkload::initState()
{
    OsKernel::initState();

    // Reset CP15?? What does that mean -- ali

    // FPEXC.EN = 0

    for (auto *tc: system->threadContexts) {
        Reset().invoke(tc);
        tc->activate();
    }

    auto *arm_sys = dynamic_cast<ArmSystem *>(system);

    if (bootldr) {
        bool is_gic_v2 =
            arm_sys->getGIC()->supportsVersion(BaseGic::GicVersion::GIC_V2);
        bootldr->buildImage().write(system->physProxy);

        inform("Using bootloader at address %#x", bootldr->entryPoint());

        // Put the address of the boot loader into r7 so we know
        // where to branch to after the reset fault
        // All other values needed by the boot loader to know what to do
        fatal_if(!arm_sys->params()->flags_addr,
                 "flags_addr must be set with bootloader");

        fatal_if(!arm_sys->params()->gic_cpu_addr && is_gic_v2,
                 "gic_cpu_addr must be set with bootloader");

        for (auto tc: arm_sys->threadContexts) {
            if (!arm_sys->highestELIs64())
                tc->setIntReg(3, kernelEntry);
            if (is_gic_v2)
                tc->setIntReg(4, arm_sys->params()->gic_cpu_addr);
            tc->setIntReg(5, arm_sys->params()->flags_addr);
        }
        inform("Using kernel entry physical address at %#x\n", kernelEntry);
    } else {
        // Set the initial PC to be at start of the kernel code
        if (!arm_sys->highestELIs64())
            arm_sys->threadContexts[0]->pcState(entry);
    }
}

ObjectFile *
FsWorkload::getBootLoader(ObjectFile *const obj)
{
    for (auto &bl : bootLoaders) {
        if (bl->getArch() == obj->getArch())
            return bl.get();
    }

    return nullptr;
}

Addr
FsWorkload::resetAddr() const
{
    if (bootldr) {
        return bootldr->entryPoint();
    } else {
        return kernelEntry;
    }
}

} // namespace ArmISA

ArmISA::FsWorkload *
ArmFsWorkloadParams::create()
{
    return new ArmISA::FsWorkload(this);
}
<commit_msg>arch-arm: Handle empty object_file scenario in ArmFsWorkload<commit_after>/*
 * Copyright (c) 2010, 2012-2013, 2015,2017-2019 ARM Limited
 * All rights reserved
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * Copyright (c) 2002-2006 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "arch/arm/fs_workload.hh"

#include "arch/arm/faults.hh"
#include "base/loader/object_file.hh"
#include "base/loader/symtab.hh"
#include "cpu/thread_context.hh"
#include "dev/arm/gic_v2.hh"
#include "kern/system_events.hh"
#include "params/ArmFsWorkload.hh"

namespace ArmISA
{

void
SkipFunc::returnFromFuncIn(ThreadContext *tc)
{
    PCState newPC = tc->pcState();
    if (inAArch64(tc)) {
        newPC.set(tc->readIntReg(INTREG_X30));
    } else {
        newPC.set(tc->readIntReg(ReturnAddressReg) & ~ULL(1));
    }

    CheckerCPU *checker = tc->getCheckerCpuPtr();
    if (checker) {
        tc->pcStateNoRecord(newPC);
    } else {
        tc->pcState(newPC);
    }
}

FsWorkload::FsWorkload(Params *p)
  : OsKernel(*p),
    kernelEntry((entry & loadAddrMask) + loadAddrOffset)
{
    bootLoaders.reserve(p->boot_loader.size());
    for (const auto &bl : p->boot_loader) {
        std::unique_ptr<ObjectFile> bl_obj;
        bl_obj.reset(createObjectFile(bl));

        fatal_if(!bl_obj, "Could not read bootloader: %s", bl);
        bootLoaders.emplace_back(std::move(bl_obj));
    }

    if (obj) {
        bootldr = getBootLoader(obj);
    } else if (!bootLoaders.empty()) {
        // No kernel specified, default to the first boot loader
        bootldr = bootLoaders[0].get();
    }

    fatal_if(!bootLoaders.empty() && !bootldr,
             "Can't find a matching boot loader / kernel combination!");

    if (bootldr) {
        bootldr->loadGlobalSymbols(debugSymbolTable);

        _highestELIs64 = (bootldr->getArch() == ObjectFile::Arm64);
    } else if (obj) {
        _highestELIs64 = (obj->getArch() == ObjectFile::Arm64);
    }
}

void
FsWorkload::initState()
{
    OsKernel::initState();

    // Reset CP15?? What does that mean -- ali

    // FPEXC.EN = 0

    for (auto *tc: system->threadContexts) {
        Reset().invoke(tc);
        tc->activate();
    }

    auto *arm_sys = dynamic_cast<ArmSystem *>(system);

    if (bootldr) {
        bool is_gic_v2 =
            arm_sys->getGIC()->supportsVersion(BaseGic::GicVersion::GIC_V2);
        bootldr->buildImage().write(system->physProxy);

        inform("Using bootloader at address %#x", bootldr->entryPoint());

        // Put the address of the boot loader into r7 so we know
        // where to branch to after the reset fault
        // All other values needed by the boot loader to know what to do
        fatal_if(!arm_sys->params()->flags_addr,
                 "flags_addr must be set with bootloader");

        fatal_if(!arm_sys->params()->gic_cpu_addr && is_gic_v2,
                 "gic_cpu_addr must be set with bootloader");

        for (auto tc: arm_sys->threadContexts) {
            if (!arm_sys->highestELIs64())
                tc->setIntReg(3, kernelEntry);
            if (is_gic_v2)
                tc->setIntReg(4, arm_sys->params()->gic_cpu_addr);
            tc->setIntReg(5, arm_sys->params()->flags_addr);
        }
        inform("Using kernel entry physical address at %#x\n", kernelEntry);
    } else {
        // Set the initial PC to be at start of the kernel code
        if (!arm_sys->highestELIs64())
            arm_sys->threadContexts[0]->pcState(entry);
    }
}

ObjectFile *
FsWorkload::getBootLoader(ObjectFile *const obj)
{
    for (auto &bl : bootLoaders) {
        if (bl->getArch() == obj->getArch())
            return bl.get();
    }

    return nullptr;
}

Addr
FsWorkload::resetAddr() const
{
    if (bootldr) {
        return bootldr->entryPoint();
    } else {
        return kernelEntry;
    }
}

} // namespace ArmISA

ArmISA::FsWorkload *
ArmFsWorkloadParams::create()
{
    return new ArmISA::FsWorkload(this);
}
<|endoftext|>


<commit_before>#include <iostream>
#include <list>
#include <string>
#include <algebra/block_matrix.h>
#include <algebra/matrix.h>
#include <algebra/vector.h>

using std::cout;
using std::endl;
using namespace MathTL;

int main()
{
  cout << "Testing the class BlockMatrix ..." << endl;

  BlockMatrix<double> defaultM;
  cout << "- a default block matrix:" << endl << defaultM;

  BlockMatrix<double> N(1);
  cout << "- a BlockMatrix(1):" << endl << N;

  BlockMatrix<double> M(1,2);
  cout << "- a BlockMatrix(1,2) M:" << endl << M;

  Matrix<double>* Mblock = new Matrix<double>(2, 3, "1 2 3 4 5 6");
  M.set_block(0, 0, Mblock);
  M.resize_block_row(0, Mblock->row_dimension());
  M.resize_block_column(0, Mblock->column_dimension());
  Mblock = new Matrix<double>(2, 2, "7 8 9 10");
  M.set_block(0, 1, Mblock);
  M.resize_block_column(1, Mblock->column_dimension());
  cout << "- the same block matrix M after 2 * set_block(0,*,*):" << endl << M;

  BlockMatrix<double>* Mcopy = new BlockMatrix<double>(M);
  BlockMatrix<double>* Mcopy2 = new BlockMatrix<double>(*Mcopy);
  delete Mcopy;
  cout << "- testing copy constructor:" << endl << (*Mcopy2);
  delete Mcopy2;

  Vector<double> x(5, "1 2 3 4 5"), y(2);
  M.apply(x, y);
  cout << "- a vector x=" << x << ", Mx=" << y << endl;

  MatrixBlock<double>* MT = M.clone_transposed();
  cout << "- M^T:" << endl;
  MT->print(cout);
  delete MT;

  x.resize(2);
  x[0] = 1;
  x[1] = 2;
  y.resize(5);
  M.apply_transposed(x, y);
  cout << "- a vector x=" << x << ", (M^T)x=" << y << endl;

  BlockMatrix<double> B(2,3), C(3,3);
  Matrix<double>* B00 = new Matrix<double>(1, 1, "1");
  B.set_block(0, 0, B00);
  Matrix<double>* B01 = new Matrix<double>(1, 1, "2");
  B.set_block(0, 1, B01);
//   Matrix<double>* B02 = new Matrix<double>(1, 1, "3");
//   B.set_block(0, 2, B02);
  Matrix<double>* B10 = new Matrix<double>(1, 1, "4");
  B.set_block(1, 0, B10);
  Matrix<double>* B11 = new Matrix<double>(1, 1, "5");
  B.set_block(1, 1, B11);
  Matrix<double>* B12 = new Matrix<double>(1, 1, "6");
  B.set_block(1, 2, B12);
  cout << " - a BlockMatrix B:" << endl << B;
//   Matrix<double>* C00 = new Matrix<double>(1, 1, "1");
//   C.set_block(0, 0, C00);
  Matrix<double>* C01 = new Matrix<double>(1, 1, "2");
  C.set_block(0, 1, C01);
  Matrix<double>* C02 = new Matrix<double>(1, 1, "3");
  C.set_block(0, 2, C02);
  Matrix<double>* C10 = new Matrix<double>(1, 1, "4");
  C.set_block(1, 0, C10);
  Matrix<double>* C11 = new Matrix<double>(1, 1, "5");
  C.set_block(1, 1, C11);
  Matrix<double>* C12 = new Matrix<double>(1, 1, "6");
  C.set_block(1, 2, C12);
  Matrix<double>* C20 = new Matrix<double>(1, 1, "7");
  C.set_block(2, 0, C20);
  Matrix<double>* C21 = new Matrix<double>(1, 1, "8");
  C.set_block(2, 1, C21);
  Matrix<double>* C22 = new Matrix<double>(1, 1, "9");
  C.set_block(2, 2, C22);
  cout << " - a BlockMatrix C:" << endl << C;
  cout << "- B*C=" << endl << B*C;

  return 0;
}
<commit_msg>test also the alternative transpose() routine<commit_after>#include <iostream>
#include <list>
#include <string>
#include <algebra/block_matrix.h>
#include <algebra/matrix.h>
#include <algebra/vector.h>

using std::cout;
using std::endl;
using namespace MathTL;

int main()
{
  cout << "Testing the class BlockMatrix ..." << endl;

  BlockMatrix<double> defaultM;
  cout << "- a default block matrix:" << endl << defaultM;

  BlockMatrix<double> N(1);
  cout << "- a BlockMatrix(1):" << endl << N;

  BlockMatrix<double> M(1,2);
  cout << "- a BlockMatrix(1,2) M:" << endl << M;

  Matrix<double>* Mblock = new Matrix<double>(2, 3, "1 2 3 4 5 6");
  M.set_block(0, 0, Mblock);
  M.resize_block_row(0, Mblock->row_dimension());
  M.resize_block_column(0, Mblock->column_dimension());
  Mblock = new Matrix<double>(2, 2, "7 8 9 10");
  M.set_block(0, 1, Mblock);
  M.resize_block_column(1, Mblock->column_dimension());
  cout << "- the same block matrix M after 2 * set_block(0,*,*):" << endl << M;

  BlockMatrix<double>* Mcopy = new BlockMatrix<double>(M);
  BlockMatrix<double>* Mcopy2 = new BlockMatrix<double>(*Mcopy);
  delete Mcopy;
  cout << "- testing copy constructor:" << endl << (*Mcopy2);
  delete Mcopy2;

  Vector<double> x(5, "1 2 3 4 5"), y(2);
  M.apply(x, y);
  cout << "- a vector x=" << x << ", Mx=" << y << endl;

  cout << "- M^T:" << endl << transpose(M);

  x.resize(2);
  x[0] = 1;
  x[1] = 2;
  y.resize(5);
  M.apply_transposed(x, y);
  cout << "- a vector x=" << x << ", (M^T)x=" << y << endl;

  BlockMatrix<double> B(2,3), C(3,3);
  Matrix<double>* B00 = new Matrix<double>(1, 1, "1");
  B.set_block(0, 0, B00);
  Matrix<double>* B01 = new Matrix<double>(1, 1, "2");
  B.set_block(0, 1, B01);
//   Matrix<double>* B02 = new Matrix<double>(1, 1, "3");
//   B.set_block(0, 2, B02);
  Matrix<double>* B10 = new Matrix<double>(1, 1, "4");
  B.set_block(1, 0, B10);
  Matrix<double>* B11 = new Matrix<double>(1, 1, "5");
  B.set_block(1, 1, B11);
  Matrix<double>* B12 = new Matrix<double>(1, 1, "6");
  B.set_block(1, 2, B12);
  cout << " - a BlockMatrix B:" << endl << B;
//   Matrix<double>* C00 = new Matrix<double>(1, 1, "1");
//   C.set_block(0, 0, C00);
  Matrix<double>* C01 = new Matrix<double>(1, 1, "2");
  C.set_block(0, 1, C01);
  Matrix<double>* C02 = new Matrix<double>(1, 1, "3");
  C.set_block(0, 2, C02);
  Matrix<double>* C10 = new Matrix<double>(1, 1, "4");
  C.set_block(1, 0, C10);
  Matrix<double>* C11 = new Matrix<double>(1, 1, "5");
  C.set_block(1, 1, C11);
  Matrix<double>* C12 = new Matrix<double>(1, 1, "6");
  C.set_block(1, 2, C12);
  Matrix<double>* C20 = new Matrix<double>(1, 1, "7");
  C.set_block(2, 0, C20);
  Matrix<double>* C21 = new Matrix<double>(1, 1, "8");
  C.set_block(2, 1, C21);
  Matrix<double>* C22 = new Matrix<double>(1, 1, "9");
  C.set_block(2, 2, C22);
  cout << " - a BlockMatrix C:" << endl << C;
  cout << "- B*C=" << endl << B*C;

  return 0;
}
<|endoftext|>


<commit_before>// Copyright 2008, Google Inc. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//  1. Redistributions of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//  2. Redistributions in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//  3. Neither the name of Google Inc. nor the names of its contributors may be
//     used to endorse or promote products derived from this software without
//     specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// Walk a KML NetworkLink hierarchy.
// Fetches and parses the NetworkLinks in a given file recursively.
// Prints a count of the number of KML files fetched and the total number
// of each kind of Feature in the hierachy.

#include <iostream>
#include <map>
#include <string>
#include "boost/scoped_ptr.hpp"
#include "kml/dom.h"
#include "kml/dom/xsd.h"  // TODO: expose Xsd::ElementName() properly
#include "kml/engine.h"
#include "curlfetch.h"

using kmldom::ElementPtr;
using kmldom::FeaturePtr;
using kmldom::NetworkLinkPtr;
using kmldom::OverlayPtr;
using kmlengine::KmlFile;
using kmlengine::KmzCache;
using std::cout;
using std::endl;

static void CountFeature(int type_id);
static void PrintFeatureCounts();
static void PrintFileCount();
static void WalkFile(const std::string& url, KmzCache* kmz_cache);

static int file_count;

static void PrintFileCount() {
  cout << "files " << file_count << endl;
}

typedef std::map<int,int> feature_counter_t;
feature_counter_t feature_counter;

static void CountFeature(int type_id) {
  feature_counter_t::const_iterator entry = feature_counter.find(type_id);
  if (entry == feature_counter.end()) {
    feature_counter[type_id] = 1;
  } else {
    ++feature_counter[type_id];
  }
}

static void PrintFeatureCounts() {
  for (feature_counter_t::const_iterator iter = feature_counter.begin();
       iter != feature_counter.end(); ++iter) {
    std::string element_name;
    cout << kmldom::Xsd::GetSchema()->ElementName(iter->first) << " "
      << iter->second << endl;
  }
}

class FeatureCounter : public kmlengine::FeatureVisitor {
 public:
  FeatureCounter(const KmlFile& kml_file, KmzCache* kmz_cache)
      : kml_file_(kml_file), kmz_cache_(kmz_cache) {}

  virtual void VisitFeature(const kmldom::FeaturePtr& feature) {
    CountFeature(feature->Type());
    if (OverlayPtr overlay = AsOverlay(feature)) {
      std::string href;
      if (kmlengine::GetIconParentHref(overlay, &href)) {
        std::string url;
        if (kmlengine::ResolveUri(kml_file_.get_url(), href, &url)) {
          std::string data;
          if (!kmz_cache_->FetchUrl(url.c_str(), &data)) {
            cout << "fetch failed " << url << endl;
            return;
          }
          cout << href << " bytes " << data.size() << endl;
        }
      }
    }
  }

 private:
  const KmlFile& kml_file_;
  KmzCache* kmz_cache_;
};

static void HandleFile(const KmlFile& kml_file, KmzCache* kmz_cache) {
  FeatureCounter feature_counter(kml_file, kmz_cache);
  kmlengine::VisitFeatureHierarchy(kmlengine::GetRootFeature(kml_file.root()),
                                   feature_counter);
}

static void WalkNetworkLinks(const KmlFile& kml_file, KmzCache* kmz_cache) {
  const kmlengine::ElementVector& link_vector =
      kml_file.get_link_parent_vector();
  for (size_t i = 0; i < link_vector.size(); ++i) {
    if (NetworkLinkPtr networklink = AsNetworkLink(link_vector[i])) {
      std::string href;
      if (kmlengine::GetLinkParentHref(networklink, &href)) {
         std::string url;
         if (kmlengine::ResolveUri(kml_file.get_url(), href, &url)) {
           WalkFile(url, kmz_cache);
         }
      }
    }
  }
}

static void WalkFile(const std::string& url, KmzCache* kmz_cache) {
  cout << url << endl;

  std::string kml;
  if (!kmz_cache->FetchUrl(url.c_str(), &kml)) {
    cout << "fetch failed " << url << endl;
    return;
  }

  // Parse it.
  std::string errors;
  boost::scoped_ptr<KmlFile> kml_file(KmlFile::CreateFromParse(kml, &errors));
  if (!kml_file.get()) {
    cout << "parse failed " << url << endl;
    cout << errors;
    return;
  }
  kml_file->set_url(url);
  ++file_count;

  HandleFile(*kml_file.get(), kmz_cache);

  WalkNetworkLinks(*kml_file.get(), kmz_cache);
}

int main(int argc, char** argv) {
  if (argc != 2) {
    cout << "usage: " << argv[0] << " url" << endl;
    return 1;
  }
  const char* url = argv[1];
  KmzCache kmz_cache(CurlToString, 30);
  WalkFile(url, &kmz_cache);
  PrintFileCount();
  PrintFeatureCounts();
}
<commit_msg>Use KmlFilePtr<commit_after>// Copyright 2008, Google Inc. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//  1. Redistributions of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//  2. Redistributions in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//  3. Neither the name of Google Inc. nor the names of its contributors may be
//     used to endorse or promote products derived from this software without
//     specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// Walk a KML NetworkLink hierarchy.
// Fetches and parses the NetworkLinks in a given file recursively.
// Prints a count of the number of KML files fetched and the total number
// of each kind of Feature in the hierachy.

#include <iostream>
#include <map>
#include <string>
#include "kml/dom.h"
#include "kml/dom/xsd.h"  // TODO: expose Xsd::ElementName() properly
#include "kml/engine.h"
#include "curlfetch.h"

using kmldom::ElementPtr;
using kmldom::FeaturePtr;
using kmldom::NetworkLinkPtr;
using kmldom::OverlayPtr;
using kmlengine::KmlFile;
using kmlengine::KmlFilePtr;
using kmlengine::KmzCache;
using std::cout;
using std::endl;

static void CountFeature(int type_id);
static void PrintFeatureCounts();
static void PrintFileCount();
static void WalkFile(const std::string& url, KmzCache* kmz_cache);

static int file_count;

static void PrintFileCount() {
  cout << "files " << file_count << endl;
}

typedef std::map<int,int> feature_counter_t;
feature_counter_t feature_counter;

static void CountFeature(int type_id) {
  feature_counter_t::const_iterator entry = feature_counter.find(type_id);
  if (entry == feature_counter.end()) {
    feature_counter[type_id] = 1;
  } else {
    ++feature_counter[type_id];
  }
}

static void PrintFeatureCounts() {
  for (feature_counter_t::const_iterator iter = feature_counter.begin();
       iter != feature_counter.end(); ++iter) {
    std::string element_name;
    cout << kmldom::Xsd::GetSchema()->ElementName(iter->first) << " "
      << iter->second << endl;
  }
}

class FeatureCounter : public kmlengine::FeatureVisitor {
 public:
  FeatureCounter(const KmlFilePtr& kml_file, KmzCache* kmz_cache)
      : kml_file_(kml_file), kmz_cache_(kmz_cache) {}

  virtual void VisitFeature(const kmldom::FeaturePtr& feature) {
    CountFeature(feature->Type());
    if (OverlayPtr overlay = AsOverlay(feature)) {
      std::string href;
      if (kmlengine::GetIconParentHref(overlay, &href)) {
        std::string url;
        if (kmlengine::ResolveUri(kml_file_->get_url(), href, &url)) {
          std::string data;
          if (!kmz_cache_->FetchUrl(url.c_str(), &data)) {
            cout << "fetch failed " << url << endl;
            return;
          }
          cout << href << " bytes " << data.size() << endl;
        }
      }
    }
  }

 private:
  const KmlFilePtr kml_file_;
  KmzCache* kmz_cache_;
};

static void HandleFile(const KmlFilePtr& kml_file, KmzCache* kmz_cache) {
  FeatureCounter feature_counter(kml_file, kmz_cache);
  kmlengine::VisitFeatureHierarchy(kmlengine::GetRootFeature(kml_file->root()),
                                   feature_counter);
}

static void WalkNetworkLinks(const KmlFilePtr& kml_file, KmzCache* kmz_cache) {
  const kmlengine::ElementVector& link_vector =
      kml_file->get_link_parent_vector();
  for (size_t i = 0; i < link_vector.size(); ++i) {
    if (NetworkLinkPtr networklink = AsNetworkLink(link_vector[i])) {
      std::string href;
      if (kmlengine::GetLinkParentHref(networklink, &href)) {
         std::string url;
         if (kmlengine::ResolveUri(kml_file->get_url(), href, &url)) {
           WalkFile(url, kmz_cache);
         }
      }
    }
  }
}

static void WalkFile(const std::string& url, KmzCache* kmz_cache) {
  cout << url << endl;

  std::string kml;
  if (!kmz_cache->FetchUrl(url.c_str(), &kml)) {
    cout << "fetch failed " << url << endl;
    return;
  }

  // Parse it.
  std::string errors;
  KmlFilePtr kml_file = KmlFile::CreateFromParse(kml, &errors);
  if (!kml_file) {
    cout << "parse failed " << url << endl;
    cout << errors;
    return;
  }
  kml_file->set_url(url);
  ++file_count;

  HandleFile(kml_file, kmz_cache);

  WalkNetworkLinks(kml_file, kmz_cache);
}

int main(int argc, char** argv) {
  if (argc != 2) {
    cout << "usage: " << argv[0] << " url" << endl;
    return 1;
  }
  const char* url = argv[1];
  KmzCache kmz_cache(CurlToString, 30);
  WalkFile(url, &kmz_cache);
  PrintFileCount();
  PrintFeatureCounts();
}
<|endoftext|>


<commit_before>//////////////////////////////////////////////////////////////////////////
//
// SneezyMUD - All rights reserved, SneezyMUD Coding Team
//
//////////////////////////////////////////////////////////////////////////

// commodity.cc

#include "stdsneezy.h"
#include "shop.h"
#include "obj_commodity.h"
#include "shopowned.h"

TCommodity::TCommodity() :
  TObj()
{
}

TCommodity::TCommodity(const TCommodity &a) :
  TObj(a)
{
}

TCommodity & TCommodity::operator=(const TCommodity &a)
{
  if (this == &a) return *this;
  TObj::operator=(a);
  return *this;
}

TCommodity::~TCommodity()
{
}

void TCommodity::assignFourValues(int, int, int, int)
{
}

void TCommodity::getFourValues(int *x1, int *x2, int *x3, int *x4) const
{
  *x1 = 0;
  *x2 = 0;
  *x3 = 0;
  *x4 = 0;
}

sstring TCommodity::statObjInfo() const
{
  sstring a("");
  return a;
}

void TCommodity::lowCheck()
{
  if (!isname("commodity", name)) {
    vlogf(LOG_LOW, fmt("raw material without COMMODITY in name (%s : %d)") %
               getName() % objVnum());
  }
  if (!numUnits()) {
    vlogf(LOG_LOW, fmt("raw material needs weight above 0.0 (%s : %d)") %
               getName() % objVnum());
  }
  if (!pricePerUnit()) {
    vlogf(LOG_LOW, fmt("raw material needs price above 0 (%s : %d)") %
               getName() % objVnum());
  }

  TObj::lowCheck();
}

int TCommodity::sellPrice(int num, int shop_nr, float, const TBeing *ch)
{
  float cost_per;
  int price;

  cost_per = pricePerUnit();
  price = (int) (numUnits() * cost_per * shop_index[shop_nr].getProfitSell(this,ch));

  if (obj_flags.cost <= 1) {
    price = max(0, price);
  } else {
    price = max(1, price);
  }

  return price;
}

int TCommodity::shopPrice(int num, int shop_nr, float, const TBeing *ch) const
{
  float cost_per;
  int price;

  cost_per = pricePerUnit();
  price = (int) (num * cost_per * shop_index[shop_nr].getProfitBuy(this, ch));
  price = max(1, price);

  return price;
}

int TCommodity::buyMe(TBeing *ch, TMonster *keeper, int num, int shop_nr)
{
  char buf[256];
  char buf2[80];
  int price, vnum;
  float cost_per;
  TObj *obj2;

  if (parent != keeper) {
    vlogf(LOG_BUG, "Error: buy_treasure():shop.cc  obj not on keeper");
    return -1;
  }
  if (!shop_index[shop_nr].willBuy(this)) {
    keeper->doTell(ch->getName(), shop_index[shop_nr].do_not_buy);
    return -1;
  }
  if (num > (int) (numUnits())) {
    num = (int) (numUnits());
    keeper->doTell(ch->getName(), fmt("I don't have that much %s.  Here's the %d that I do have.") % fname(name) % num);
  }
  cost_per = pricePerUnit();
  price = shopPrice(num, shop_nr, -1, ch);
  vnum = objVnum();

  if (ch->getMoney() < price) {
    keeper->doTell(ch->name, shop_index[shop_nr].missing_cash2);

    switch (shop_index[shop_nr].temper1) {
      case 0:
        keeper->doAction(ch->name, CMD_SMILE);
        return -1;
      case 1:
        act("$n grins happily.", 0, keeper, 0, 0, TO_ROOM);
        return -1;
      default:
        return -1;
    }
  }
  strcpy(buf2, fname(name).c_str());
  --(*this);
  int num2 = (int) (numUnits()) - num;
  if (num2) {
    setWeight(num2/10.0);
    *keeper += *this;
  } else {
    delete this;
  }

  if (num) {
    obj2 = read_object(vnum, VIRTUAL);
    obj2->setWeight(num/10.0);
    *ch += *obj2;
    keeper->doTell(ch->getName(), fmt("Here ya go.  That's %d units of %s.") %
       num % buf2);
    act("$n buys $p.", TRUE, ch, obj2, keeper, TO_NOTVICT);

    TShopOwned tso(shop_nr, keeper, ch);
    tso.doBuyTransaction(price, getName(), TX_BUYING, obj2);

  } else {
    // this happens with sub zero weight components
    vlogf(LOG_BUG, fmt("Bogus num %d in buyMe component at %d.  wgt=%.2f") %  num % ch->in_room % getWeight());
  }

  sprintf(buf, "%s/%d", SHOPFILE_PATH, shop_nr);
  keeper->saveItems(buf);
  ch->doSave(SILENT_YES);
  return price;
}

void TCommodity::sellMe(TBeing *ch, TMonster *keeper, int shop_nr, int)
{
  TThing *t;
  TCommodity *obj2 = NULL;
  int num, price;
  char buf[256], buf2[80];

  strcpy(buf2, fname(name).c_str());
  price = sellPrice(1, shop_nr, -1, ch);

  if (isObjStat(ITEM_NODROP)) {
    ch->sendTo("You can't let go of it, it must be CURSED!\n\r");
    return;
  }
  if (isObjStat(ITEM_PROTOTYPE)) {
    ch->sendTo("That's a prototype, no selling that!\n\r");
    return;
  }
  if (will_not_buy(ch, keeper, this, shop_nr))
    return;

  if (!shop_index[shop_nr].willBuy(this)) {
    keeper->doTell(ch->getName(), shop_index[shop_nr].do_not_buy);
    return;
  }
  if (keeper->getMoney() < price) {
    keeper->doTell(ch->getName(), shop_index[shop_nr].missing_cash1);
    return;
  }
  for (t = keeper->getStuff(); t; t = t->nextThing) {
    obj2 = dynamic_cast<TCommodity *>(t);
    if (!obj2)
      continue;

    if (obj2->objVnum() == objVnum())
      break;
  }
  if (!t) {
    TObj *to = read_object(objVnum(), VIRTUAL);
    obj2 = dynamic_cast<TCommodity *>(to);
    obj2->setWeight(0.0);
  } else
    --(*obj2);
  num = obj2->numUnits() + numUnits();
  num = max(min(num, 10000), 0);

  if (num) {
    obj2->setWeight(num/10.0);
    *keeper += *obj2;
    --(*this);

    TShopOwned tso(shop_nr, keeper, ch);
    tso.doSellTransaction(price, obj2->getName(), TX_SELLING, obj2);

    keeper->doTell(ch->getName(), fmt("Thanks, here's your %d talens.") % price);
    act("$n sells $p.", TRUE, ch, this, 0, TO_ROOM);
    if (ch->isAffected(AFF_GROUP) && ch->desc &&
            IS_SET(ch->desc->autobits, AUTO_SPLIT) &&
            (ch->master || ch->followers)){
      sprintf(buf, "%d", price);
      ch->doSplit(buf, false);
    }
    delete this;
  }
  if (!ch->delaySave)
    ch->doSave(SILENT_YES);
  sprintf(buf, "%s/%d", SHOPFILE_PATH, shop_nr);
  keeper->saveItems(buf);
  return;
}

int TCommodity::sellCommod(TBeing *ch, TMonster *keeper, int shop_nr, TThing *bag)
{
  int rc;

  if (equippedBy)
    *ch += *ch->unequip(eq_pos);

  if (bag && bag != ch) {
    rc = get(ch, this, bag, GETOBJOBJ, true);
    if (IS_SET_DELETE(rc, DELETE_ITEM)) {
      return DELETE_THIS;
    }
    if (IS_SET_DELETE(rc, DELETE_VICT)) {
      return DELETE_ITEM;
    }
    if (IS_SET_DELETE(rc, DELETE_THIS)) {
      return DELETE_VICT;
    }
    if (!dynamic_cast<TBeing *>(parent)) {
      // could fail on volume or sumthing
      return FALSE;
    }
  }

  sellMe(ch, keeper, shop_nr, 1);
  return FALSE;
}

void TCommodity::valueMe(TBeing *ch, TMonster *keeper, int shop_nr, int)
{
  int price;
  char buf2[80];

  strcpy(buf2, fname(name).c_str());
  price = sellPrice(1, shop_nr, -1, ch);

  if (!shop_index[shop_nr].willBuy(this)) {
    keeper->doTell(ch->getName(), shop_index[shop_nr].do_not_buy);
    return;
  }

  keeper->doTell(ch->getName(), fmt("Hmm, I'd give you %d talens for that.") % price);
  return;
}

const sstring TCommodity::shopList(const TBeing *ch, const sstring &arg, int min_amt, int max_amt, int, int, int k, unsigned long int) const
{
  char buf[256];
  float cost = pricePerUnit();

  sprintf(buf, "[%2d] COMMODITY: %-20.20s  : %5d units    %.2f talens (per unit)\n\r",
            k + 1, material_nums[getMaterial()].mat_name,
            (int) (numUnits()),  cost);
  if (arg.empty() && min_amt == 999999)     /* everything */
  /* specific item */
    return buf;
  else if (isname(arg, name) && min_amt == 999999)
    return buf;
  /* specific item and specific cost */
  else if (isname(arg, name) && cost >= min_amt && cost <= max_amt)
    return buf;
  else if (arg.empty() && cost >= min_amt && cost <= max_amt)   /* specific cost */
    return buf;
  else
    return "";
}

int TCommodity::numUnits() const
{
  return (int) (10.0 * getWeight());
}

float TCommodity::pricePerUnit() const
{
  /*
  if(!material_nums[getMaterial()].price)
    vlogf(LOG_BUG, fmt("commodity '%s' has no price for material %i") %
	  getName() % getMaterial());
  */

  return material_nums[getMaterial()].price;
}

int TCommodity::getSizeIndex() const
{
  int weight=numUnits();

  if(weight<=2){
    return 0;
  } else if(weight<=4){
    return 1;
  } else if(weight<=6){
    return 2;
  } else if(weight<=8){
    return 3;
  } else if(weight<=10){
    return 4;
  } else if(weight<=15){
    return 5;
  } else {
    return 6;
  }
}

void TCommodity::updateDesc()
{
  int sizeindex=getSizeIndex();
  char buf[256];

  const char *metalname [] =
  {
    "bit",
    "nugget",
    "ingot",
    "sovereign",
    "rod",
    "bar",
    "pile"
  };

  const char *mineralname [] =
  {
    "tiny piece",
    "small piece",
    "piece",
    "large piece",
    "huge piece",
    "gigantic piece",
    "massive piece"
  };

  if (isObjStat(ITEM_STRUNG)) {
    delete [] name;
    delete [] shortDescr;
    delete [] descr;

    extraDescription *exd;
    while ((exd = ex_description)) {
      ex_description = exd->next;
      delete exd;
    }
    ex_description = NULL;
    delete [] action_description;
    action_description = NULL;
  } else {
    addObjStat(ITEM_STRUNG);
    ex_description = NULL;
    action_description = NULL;
  }

  if(isMineral()){
    sprintf(buf, (fmt("commodity %s %s") % mineralname[sizeindex] %
	    material_nums[getMaterial()].mat_name).c_str());
    name = mud_str_dup(buf);

    sprintf(buf, (fmt("a %s of rough %s") % mineralname[sizeindex] %
		  material_nums[getMaterial()].mat_name).c_str());
    shortDescr = mud_str_dup(buf);

    sprintf(buf, (fmt("A %s of rough %s has been left here.  What luck!") %
		  mineralname[sizeindex] %
		  material_nums[getMaterial()].mat_name).c_str());
    setDescr(mud_str_dup(buf));
  } else {
    sprintf(buf, (fmt("commodity %s %s") % metalname[sizeindex] %
	    material_nums[getMaterial()].mat_name).c_str());
    name = mud_str_dup(buf);

    sprintf(buf, (fmt("a %s of %s") % metalname[sizeindex] %
		  material_nums[getMaterial()].mat_name).c_str());
    shortDescr = mud_str_dup(buf);

    sprintf(buf, (fmt("A %s of %s has been left here.  What luck!") %
		  metalname[sizeindex] %
		  material_nums[getMaterial()].mat_name).c_str());
    setDescr(mud_str_dup(buf));
  }
  obj_flags.cost = suggestedPrice();

}

int TCommodity::suggestedPrice() const
{
  return (int)(numUnits() * pricePerUnit());
};

void TCommodity::setWeight(const float w)
{
  TObj::setWeight(w);

  //  if(!bootTime)
    updateDesc();
}

void TCommodity::setMaterial(ubyte num)
{
  TObj::setMaterial(num);

  //  if(!bootTime)
    updateDesc();
}
<commit_msg>fixed commodity shop code distinguishing commods based on vnum instead of mat<commit_after>//////////////////////////////////////////////////////////////////////////
//
// SneezyMUD - All rights reserved, SneezyMUD Coding Team
//
//////////////////////////////////////////////////////////////////////////

// commodity.cc

#include "stdsneezy.h"
#include "shop.h"
#include "obj_commodity.h"
#include "shopowned.h"

TCommodity::TCommodity() :
  TObj()
{
}

TCommodity::TCommodity(const TCommodity &a) :
  TObj(a)
{
}

TCommodity & TCommodity::operator=(const TCommodity &a)
{
  if (this == &a) return *this;
  TObj::operator=(a);
  return *this;
}

TCommodity::~TCommodity()
{
}

void TCommodity::assignFourValues(int, int, int, int)
{
}

void TCommodity::getFourValues(int *x1, int *x2, int *x3, int *x4) const
{
  *x1 = 0;
  *x2 = 0;
  *x3 = 0;
  *x4 = 0;
}

sstring TCommodity::statObjInfo() const
{
  sstring a("");
  return a;
}

void TCommodity::lowCheck()
{
  if (!isname("commodity", name)) {
    vlogf(LOG_LOW, fmt("raw material without COMMODITY in name (%s : %d)") %
               getName() % objVnum());
  }
  if (!numUnits()) {
    vlogf(LOG_LOW, fmt("raw material needs weight above 0.0 (%s : %d)") %
               getName() % objVnum());
  }
  if (!pricePerUnit()) {
    vlogf(LOG_LOW, fmt("raw material needs price above 0 (%s : %d)") %
               getName() % objVnum());
  }

  TObj::lowCheck();
}

int TCommodity::sellPrice(int num, int shop_nr, float, const TBeing *ch)
{
  float cost_per;
  int price;

  cost_per = pricePerUnit();
  price = (int) (numUnits() * cost_per * shop_index[shop_nr].getProfitSell(this,ch));

  if (obj_flags.cost <= 1) {
    price = max(0, price);
  } else {
    price = max(1, price);
  }

  return price;
}

int TCommodity::shopPrice(int num, int shop_nr, float, const TBeing *ch) const
{
  float cost_per;
  int price;

  cost_per = pricePerUnit();
  price = (int) (num * cost_per * shop_index[shop_nr].getProfitBuy(this, ch));
  price = max(1, price);

  return price;
}

int TCommodity::buyMe(TBeing *ch, TMonster *keeper, int num, int shop_nr)
{
  char buf[256];
  char buf2[80];
  int price, vnum;
  float cost_per;
  TObj *obj2;

  if (parent != keeper) {
    vlogf(LOG_BUG, "Error: buy_treasure():shop.cc  obj not on keeper");
    return -1;
  }
  if (!shop_index[shop_nr].willBuy(this)) {
    keeper->doTell(ch->getName(), shop_index[shop_nr].do_not_buy);
    return -1;
  }
  if (num > (int) (numUnits())) {
    num = (int) (numUnits());
    keeper->doTell(ch->getName(), fmt("I don't have that much %s.  Here's the %d that I do have.") % fname(name) % num);
  }
  cost_per = pricePerUnit();
  price = shopPrice(num, shop_nr, -1, ch);
  vnum = objVnum();

  if (ch->getMoney() < price) {
    keeper->doTell(ch->name, shop_index[shop_nr].missing_cash2);

    switch (shop_index[shop_nr].temper1) {
      case 0:
        keeper->doAction(ch->name, CMD_SMILE);
        return -1;
      case 1:
        act("$n grins happily.", 0, keeper, 0, 0, TO_ROOM);
        return -1;
      default:
        return -1;
    }
  }
  strcpy(buf2, fname(name).c_str());
  --(*this);
  int num2 = (int) (numUnits()) - num;
  if (num2) {
    setWeight(num2/10.0);
    *keeper += *this;
  } else {
    delete this;
  }

  if (num) {
    obj2 = read_object(vnum, VIRTUAL);
    obj2->setWeight(num/10.0);
    *ch += *obj2;
    keeper->doTell(ch->getName(), fmt("Here ya go.  That's %d units of %s.") %
       num % buf2);
    act("$n buys $p.", TRUE, ch, obj2, keeper, TO_NOTVICT);

    TShopOwned tso(shop_nr, keeper, ch);
    tso.doBuyTransaction(price, getName(), TX_BUYING, obj2);

  } else {
    // this happens with sub zero weight components
    vlogf(LOG_BUG, fmt("Bogus num %d in buyMe component at %d.  wgt=%.2f") %  num % ch->in_room % getWeight());
  }

  sprintf(buf, "%s/%d", SHOPFILE_PATH, shop_nr);
  keeper->saveItems(buf);
  ch->doSave(SILENT_YES);
  return price;
}

void TCommodity::sellMe(TBeing *ch, TMonster *keeper, int shop_nr, int)
{
  TThing *t;
  TCommodity *obj2 = NULL;
  int num, price;
  char buf[256], buf2[80];

  strcpy(buf2, fname(name).c_str());
  price = sellPrice(1, shop_nr, -1, ch);

  if (isObjStat(ITEM_NODROP)) {
    ch->sendTo("You can't let go of it, it must be CURSED!\n\r");
    return;
  }
  if (isObjStat(ITEM_PROTOTYPE)) {
    ch->sendTo("That's a prototype, no selling that!\n\r");
    return;
  }
  if (will_not_buy(ch, keeper, this, shop_nr))
    return;

  if (!shop_index[shop_nr].willBuy(this)) {
    keeper->doTell(ch->getName(), shop_index[shop_nr].do_not_buy);
    return;
  }
  if (keeper->getMoney() < price) {
    keeper->doTell(ch->getName(), shop_index[shop_nr].missing_cash1);
    return;
  }
  for (t = keeper->getStuff(); t; t = t->nextThing) {
    obj2 = dynamic_cast<TCommodity *>(t);
    if (!obj2)
      continue;

    if (obj2->getMaterial() == getMaterial())
      break;
  }
  if (!t) {
    TObj *to = read_object(objVnum(), VIRTUAL);
    obj2 = dynamic_cast<TCommodity *>(to);
    obj2->setWeight(0.0);
  } else
    --(*obj2);
  num = obj2->numUnits() + numUnits();
  num = max(min(num, 10000), 0);

  if (num) {
    obj2->setWeight(num/10.0);
    *keeper += *obj2;
    --(*this);

    TShopOwned tso(shop_nr, keeper, ch);
    tso.doSellTransaction(price, obj2->getName(), TX_SELLING, obj2);

    keeper->doTell(ch->getName(), fmt("Thanks, here's your %d talens.") % price);
    act("$n sells $p.", TRUE, ch, this, 0, TO_ROOM);
    if (ch->isAffected(AFF_GROUP) && ch->desc &&
            IS_SET(ch->desc->autobits, AUTO_SPLIT) &&
            (ch->master || ch->followers)){
      sprintf(buf, "%d", price);
      ch->doSplit(buf, false);
    }
    delete this;
  }
  if (!ch->delaySave)
    ch->doSave(SILENT_YES);
  sprintf(buf, "%s/%d", SHOPFILE_PATH, shop_nr);
  keeper->saveItems(buf);
  return;
}

int TCommodity::sellCommod(TBeing *ch, TMonster *keeper, int shop_nr, TThing *bag)
{
  int rc;

  if (equippedBy)
    *ch += *ch->unequip(eq_pos);

  if (bag && bag != ch) {
    rc = get(ch, this, bag, GETOBJOBJ, true);
    if (IS_SET_DELETE(rc, DELETE_ITEM)) {
      return DELETE_THIS;
    }
    if (IS_SET_DELETE(rc, DELETE_VICT)) {
      return DELETE_ITEM;
    }
    if (IS_SET_DELETE(rc, DELETE_THIS)) {
      return DELETE_VICT;
    }
    if (!dynamic_cast<TBeing *>(parent)) {
      // could fail on volume or sumthing
      return FALSE;
    }
  }

  sellMe(ch, keeper, shop_nr, 1);
  return FALSE;
}

void TCommodity::valueMe(TBeing *ch, TMonster *keeper, int shop_nr, int)
{
  int price;
  char buf2[80];

  strcpy(buf2, fname(name).c_str());
  price = sellPrice(1, shop_nr, -1, ch);

  if (!shop_index[shop_nr].willBuy(this)) {
    keeper->doTell(ch->getName(), shop_index[shop_nr].do_not_buy);
    return;
  }

  keeper->doTell(ch->getName(), fmt("Hmm, I'd give you %d talens for that.") % price);
  return;
}

const sstring TCommodity::shopList(const TBeing *ch, const sstring &arg, int min_amt, int max_amt, int, int, int k, unsigned long int) const
{
  char buf[256];
  float cost = pricePerUnit();

  sprintf(buf, "[%2d] COMMODITY: %-20.20s  : %5d units    %.2f talens (per unit)\n\r",
            k + 1, material_nums[getMaterial()].mat_name,
            (int) (numUnits()),  cost);
  if (arg.empty() && min_amt == 999999)     /* everything */
  /* specific item */
    return buf;
  else if (isname(arg, name) && min_amt == 999999)
    return buf;
  /* specific item and specific cost */
  else if (isname(arg, name) && cost >= min_amt && cost <= max_amt)
    return buf;
  else if (arg.empty() && cost >= min_amt && cost <= max_amt)   /* specific cost */
    return buf;
  else
    return "";
}

int TCommodity::numUnits() const
{
  return (int) (10.0 * getWeight());
}

float TCommodity::pricePerUnit() const
{
  /*
  if(!material_nums[getMaterial()].price)
    vlogf(LOG_BUG, fmt("commodity '%s' has no price for material %i") %
	  getName() % getMaterial());
  */

  return material_nums[getMaterial()].price;
}

int TCommodity::getSizeIndex() const
{
  int weight=numUnits();

  if(weight<=2){
    return 0;
  } else if(weight<=4){
    return 1;
  } else if(weight<=6){
    return 2;
  } else if(weight<=8){
    return 3;
  } else if(weight<=10){
    return 4;
  } else if(weight<=15){
    return 5;
  } else {
    return 6;
  }
}

void TCommodity::updateDesc()
{
  int sizeindex=getSizeIndex();
  char buf[256];

  const char *metalname [] =
  {
    "bit",
    "nugget",
    "ingot",
    "sovereign",
    "rod",
    "bar",
    "pile"
  };

  const char *mineralname [] =
  {
    "tiny piece",
    "small piece",
    "piece",
    "large piece",
    "huge piece",
    "gigantic piece",
    "massive piece"
  };

  if (isObjStat(ITEM_STRUNG)) {
    delete [] name;
    delete [] shortDescr;
    delete [] descr;

    extraDescription *exd;
    while ((exd = ex_description)) {
      ex_description = exd->next;
      delete exd;
    }
    ex_description = NULL;
    delete [] action_description;
    action_description = NULL;
  } else {
    addObjStat(ITEM_STRUNG);
    ex_description = NULL;
    action_description = NULL;
  }

  if(isMineral()){
    sprintf(buf, (fmt("commodity %s %s") % mineralname[sizeindex] %
	    material_nums[getMaterial()].mat_name).c_str());
    name = mud_str_dup(buf);

    sprintf(buf, (fmt("a %s of rough %s") % mineralname[sizeindex] %
		  material_nums[getMaterial()].mat_name).c_str());
    shortDescr = mud_str_dup(buf);

    sprintf(buf, (fmt("A %s of rough %s has been left here.  What luck!") %
		  mineralname[sizeindex] %
		  material_nums[getMaterial()].mat_name).c_str());
    setDescr(mud_str_dup(buf));
  } else {
    sprintf(buf, (fmt("commodity %s %s") % metalname[sizeindex] %
	    material_nums[getMaterial()].mat_name).c_str());
    name = mud_str_dup(buf);

    sprintf(buf, (fmt("a %s of %s") % metalname[sizeindex] %
		  material_nums[getMaterial()].mat_name).c_str());
    shortDescr = mud_str_dup(buf);

    sprintf(buf, (fmt("A %s of %s has been left here.  What luck!") %
		  metalname[sizeindex] %
		  material_nums[getMaterial()].mat_name).c_str());
    setDescr(mud_str_dup(buf));
  }
  obj_flags.cost = suggestedPrice();

}

int TCommodity::suggestedPrice() const
{
  return (int)(numUnits() * pricePerUnit());
};

void TCommodity::setWeight(const float w)
{
  TObj::setWeight(w);

  //  if(!bootTime)
    updateDesc();
}

void TCommodity::setMaterial(ubyte num)
{
  TObj::setMaterial(num);

  //  if(!bootTime)
    updateDesc();
}
<|endoftext|>