<commit_before>// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <cstdlib>
#include <string>
#include <vector>

#include <gflags/gflags.h>
#include <gflags/gflags_declare.h>
#include "base/logging.h"
#include "compat/string.h"
#include "file_utils.h"
#include "perf_protobuf_io.h"
#include "perf_recorder.h"
#include "quipper_lib.h"
#include "string_utils.h"

namespace {

DEFINE_int64(duration, 0, "Duration to run perf in seconds");
DEFINE_string(perf_path, "", "Path to perf");
DEFINE_string(output_file, "/dev/stdout",
              "Path to store the output perf_data.pb.data");
DEFINE_bool(run_inject, false,
            "If true, run perf inject on the recorded perf data");
DEFINE_string(inject_args, "",
            "a list of hyphen-separated flags passed to perf inject, "
            "must be used with --run_inject");

bool ParsePerfArguments(int argc, const char* argv[], int* duration,
                        std::vector<string>* perf_args,
                        std::vector<string>* inject_args, string* output_file) {
  if (argc < 2) {
    return false;
  }

  *duration = FLAGS_duration;
  if (*duration <= 0) return false;

  string perf_path = FLAGS_perf_path;
  if (perf_path.empty()) return false;

  perf_args->emplace_back(perf_path);

  for (int i = 1; i < argc; i++) {
    perf_args->emplace_back(argv[i]);
  }

  *output_file = FLAGS_output_file;
  if (output_file->empty()) return false;

  bool run_inject = FLAGS_run_inject;
  string inject_args_string = FLAGS_inject_args;
  if (!run_inject && !inject_args_string.empty()) return false;

  quipper::SplitString(inject_args_string, ';', inject_args);
  // Similar to perf_args, insert the perf_path in front of inject_args.
  inject_args->emplace(inject_args->begin(), perf_path);
  return true;
}

bool RecordPerf(int perf_duration, const std::vector<string>& perf_args,
                const std::vector<string>& inject_args,
                const string& output_file) {
  quipper::PerfRecorder perf_recorder;
  string output_string;
  if (!perf_recorder.RunCommandAndGetSerializedOutput(
          perf_args, perf_duration, inject_args, &output_string)) {
    LOG(ERROR) << "Couldn't record perf";
    return false;
  }
  if (!quipper::BufferToFile(output_file, output_string)) {
    LOG(ERROR) << "Couldn't write perf_data.pb.data at " << output_file;
    return false;
  }
  return true;
}

}  // namespace

// Usage is:
// To run perf using quipper and generate a perf_data.pb.data:
//   <exe> --duration <duration in seconds>
//         --perf_path <path to perf>
//         --output_file <path to store the output perf_data.pb.data>
//         [--run_inject]
//         [--inject_arg <perf inject argument>]
//         --
//         <perf arguments>
//  or the old way, this is temporarily supported, without any flags:
//   <exe> <duration in seconds> <perf command line>

int main(int argc, char* argv[]) {
  std::vector<string> perf_args, inject_args;
  int perf_duration = 0;

  if (ParseOldPerfArguments(argc, const_cast<const char**>(argv),
                            &perf_duration, &perf_args)) {
    return RecordPerf(perf_duration, perf_args, inject_args, "/dev/stdout")
               ? EXIT_SUCCESS
               : EXIT_FAILURE;
  }

  gflags::ParseCommandLineFlags(&argc, &argv, true);

  string output_file;
  perf_args.clear();

  if (ParsePerfArguments(argc, const_cast<const char**>(argv), &perf_duration,
                         &perf_args, &inject_args, &output_file)) {
    return RecordPerf(perf_duration, perf_args, inject_args, output_file)
               ? EXIT_SUCCESS
               : EXIT_FAILURE;
  }

  LOG(ERROR) << "Invalid command line.";
  LOG(ERROR) << "Usage: " << argv[0] << " --duration <duration in seconds>"
             << " --perf_path <path to perf>"
             << " --output_file <path to store the output perf_data.pb.data>"
             << " [--run_inject]"
             << " [--inject_args <hyphen-separated perf inject arguments>]"
             << " -- <perf arguments>"
             << "\nor\n"
             << argv[0] << " <duration in seconds>"
             << " <path to perf>"
             << " <perf arguments>";
  return EXIT_FAILURE;
}
<commit_msg>Only append the inject command when run_inject=true (#113)<commit_after>// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <cstdlib>
#include <string>
#include <vector>

#include <gflags/gflags.h>
#include <gflags/gflags_declare.h>
#include "base/logging.h"
#include "compat/string.h"
#include "file_utils.h"
#include "perf_protobuf_io.h"
#include "perf_recorder.h"
#include "quipper_lib.h"
#include "string_utils.h"

namespace {

DEFINE_int64(duration, 0, "Duration to run perf in seconds");
DEFINE_string(perf_path, "", "Path to perf");
DEFINE_string(output_file, "/dev/stdout",
              "Path to store the output perf_data.pb.data");
DEFINE_bool(run_inject, false,
            "If true, run perf inject on the recorded perf data");
DEFINE_string(inject_args, "",
            "a list of hyphen-separated flags passed to perf inject, "
            "must be used with --run_inject");

bool ParsePerfArguments(int argc, const char* argv[], int* duration,
                        std::vector<string>* perf_args,
                        std::vector<string>* inject_args, string* output_file) {
  if (argc < 2) {
    return false;
  }

  *duration = FLAGS_duration;
  if (*duration <= 0) return false;

  string perf_path = FLAGS_perf_path;
  if (perf_path.empty()) return false;

  perf_args->emplace_back(perf_path);

  for (int i = 1; i < argc; i++) {
    perf_args->emplace_back(argv[i]);
  }

  *output_file = FLAGS_output_file;
  if (output_file->empty()) return false;

  bool run_inject = FLAGS_run_inject;
  string inject_args_string = FLAGS_inject_args;
  if (!run_inject && !inject_args_string.empty()) return false;

  if (run_inject) {
    quipper::SplitString(inject_args_string, ';', inject_args);
    // Similar to perf_args, insert the perf_path in front of inject_args.
    inject_args->emplace(inject_args->begin(), perf_path);
  }
  return true;
}

bool RecordPerf(int perf_duration, const std::vector<string>& perf_args,
                const std::vector<string>& inject_args,
                const string& output_file) {
  quipper::PerfRecorder perf_recorder;
  string output_string;
  if (!perf_recorder.RunCommandAndGetSerializedOutput(
          perf_args, perf_duration, inject_args, &output_string)) {
    LOG(ERROR) << "Couldn't record perf";
    return false;
  }
  if (!quipper::BufferToFile(output_file, output_string)) {
    LOG(ERROR) << "Couldn't write perf_data.pb.data at " << output_file;
    return false;
  }
  return true;
}

}  // namespace

// Usage is:
// To run perf using quipper and generate a perf_data.pb.data:
//   <exe> --duration <duration in seconds>
//         --perf_path <path to perf>
//         --output_file <path to store the output perf_data.pb.data>
//         [--run_inject]
//         [--inject_arg <perf inject argument>]
//         --
//         <perf arguments>
//  or the old way, this is temporarily supported, without any flags:
//   <exe> <duration in seconds> <perf command line>

int main(int argc, char* argv[]) {
  std::vector<string> perf_args, inject_args;
  int perf_duration = 0;

  if (ParseOldPerfArguments(argc, const_cast<const char**>(argv),
                            &perf_duration, &perf_args)) {
    return RecordPerf(perf_duration, perf_args, inject_args, "/dev/stdout")
               ? EXIT_SUCCESS
               : EXIT_FAILURE;
  }

  gflags::ParseCommandLineFlags(&argc, &argv, true);

  string output_file;
  perf_args.clear();

  if (ParsePerfArguments(argc, const_cast<const char**>(argv), &perf_duration,
                         &perf_args, &inject_args, &output_file)) {
    return RecordPerf(perf_duration, perf_args, inject_args, output_file)
               ? EXIT_SUCCESS
               : EXIT_FAILURE;
  }

  LOG(ERROR) << "Invalid command line.";
  LOG(ERROR) << "Usage: " << argv[0] << " --duration <duration in seconds>"
             << " --perf_path <path to perf>"
             << " --output_file <path to store the output perf_data.pb.data>"
             << " [--run_inject]"
             << " [--inject_args <hyphen-separated perf inject arguments>]"
             << " -- <perf arguments>"
             << "\nor\n"
             << argv[0] << " <duration in seconds>"
             << " <path to perf>"
             << " <perf arguments>";
  return EXIT_FAILURE;
}
<|endoftext|>


<commit_before><commit_msg>`yli::load::load_DDS_texture`: initialize `filecode_char` with zeroes.<commit_after><|endoftext|>


<commit_before>#include <gdal_priv.h>
#include <iostream>
#include <iomanip>
#include <opencv2/opencv.hpp>
#include <opencv2/stitching/detail/blenders.hpp>
#include "utils.h"

class Bounds {
public:
  Bounds() {}

  int FromDataset(GDALDataset *ds) {
    double geotransform[6];
    CPLErr err = ds->GetGeoTransform(geotransform);
    check(err == CE_None, NULL);

    ul.first  = geotransform[0];
    ul.second = geotransform[3];
    lr.first  = ul.first + ds->GetRasterXSize() * geotransform[1];
    lr.second = ul.second + ds->GetRasterYSize() * geotransform[5];

    return false;
  error:
    return true;
  }

  void extend(Bounds obounds) {
    ul.first  = std::min(obounds.ul.first, ul.first);
    ul.second = std::max(obounds.ul.second, ul.second);
    lr.first  = std::max(obounds.lr.first, lr.first);
    lr.second = std::min(obounds.lr.second, lr.second);
  }

  std::pair<double, double> ul;
  std::pair<double, double> lr;
};

int
main(int argc, char **argv) {
  if(argc < 3) { std::cout << "usage: stitch <stitch-datasets*> out.tif" << std::endl; return -1; };

  // declarations
  std::vector<GDALDataset *> datasets;
  Bounds bounds;
  bool err;
  int j = 1;
  double geotransform[6];
  int xsize, ysize;
  cv::Ptr<cv::detail::Blender> blender = cv::detail::Blender::createDefault(cv::detail::Blender::FEATHER, false);
  std::vector<cv::Size> sizes;
  std::vector<cv::Point> corners;
  cv::Mat result, result_mask;
  GDALDataset *outds = NULL;

  // init gdal
  GDALAllRegister();

  // open datasets
  for(int i = 1; i < argc - 1; i++) {
    GDALDataset *dataset = (GDALDataset *) GDALOpen(argv[i], GA_ReadOnly);
    check(dataset != NULL, "Could not open %s\n", argv[i]);
    datasets.push_back(dataset);
  }

  err = bounds.FromDataset(datasets.at(0));
  check(err == false, "%s doesn't have geo information", argv[1]);

  // fill out bookkeeping structures
  j = 1;
  for(GDALDataset *ds : datasets) {
    Bounds obounds;
    obounds.FromDataset(ds);
    check(err == false, "%s doesn't have geo information", argv[j]);
    bounds.extend(obounds);
    j++;
  }

  // no need to check err, we did that when we built the bounds up
  datasets[0]->GetGeoTransform(geotransform);
  xsize = (bounds.lr.first - bounds.ul.first) / geotransform[1] + 0.5;
  ysize = (bounds.lr.second - bounds.ul.second) / geotransform[5] + 0.5;
  printf("Creating dataset %s with size %d x %d \n", argv[argc - 1], xsize, ysize);
  printf("and bounds UL: %f %f LR: %f %f\n", bounds.ul.first, bounds.ul.second, bounds.lr.first, bounds.lr.second);

  geotransform[0] = bounds.ul.first;
  geotransform[2] = 0;
  geotransform[3] = bounds.ul.second;
  geotransform[4] = 0;

  // build sizes and point vectors
  j = 1;
  for(GDALDataset *ds : datasets) {
    Bounds obounds;
    obounds.FromDataset(ds);
    std::cout << ds->GetRasterXSize() << ", " << ds->GetRasterYSize() << std::endl;
    cv::Point pt(
      round((obounds.ul.first - geotransform[0]) / geotransform[1]),
      round((obounds.ul.second - geotransform[3]) / geotransform[5])
    );
    corners.push_back(pt);
    std::cout << "placing " << argv[j] << " at " << pt.x << ", " << pt.y << std::endl;

    cv::Size s(
      ((obounds.lr.first - geotransform[0]) / geotransform[1] + 0.5) - pt.x,
      ((obounds.lr.second - geotransform[3]) / geotransform[5] + 0.5) - pt.y
    );
    sizes.push_back(s);
    std::cout << "sizing " << argv[j] << " at " << s.width << ", " << s.height << std::endl;

    j++;
  }

  blender->prepare(corners, sizes);

  for(int i = 1; i < argc - 1; i++) {
    cv::Mat im = cv::imread(argv[i]);
    resize(im, im, sizes.at(i - 1), cv::INTER_LANCZOS4);
    std::vector<cv::Mat> channels;
    cv::split(im, channels);
    im.convertTo(im, CV_16SC3);
    std::cout << "merging " << argv[i] << std::endl;
    blender->feed(im, 0xFFFFFF & channels.at(0), corners.at(i - 1));
  }

  blender->blend(result, result_mask);
  std::cout << "writing " << argv[argc - 1] << std::endl;
  cv::imwrite(argv[argc - 1], result);
  std::cout << "done" << std::endl;

  outds = (GDALDataset *) GDALOpen(argv[argc - 1], GA_Update);
  check(outds != NULL, "Could not open %s\n", argv[argc - 1]);

  outds->SetGeoTransform(geotransform);
  outds->SetProjection(datasets.at(0)->GetProjectionRef());

  GDALClose(outds);
  for(GDALDataset *ds : datasets)
    GDALClose(ds);
  return 0;
error:
  if(outds) GDALClose(outds);
  for(GDALDataset *ds : datasets)
    GDALClose(ds);
  return -1;
}<commit_msg>smartly setting sharpness<commit_after>#include <gdal_priv.h>
#include <iostream>
#include <iomanip>
#include <opencv2/opencv.hpp>
#include <opencv2/stitching/detail/blenders.hpp>
#include <opencv2/stitching/detail/util.hpp>
#include "utils.h"

class Bounds {
public:
  Bounds() {}

  int FromDataset(GDALDataset *ds) {
    double geotransform[6];
    CPLErr err = ds->GetGeoTransform(geotransform);
    check(err == CE_None, NULL);

    ul.first  = geotransform[0];
    ul.second = geotransform[3];
    lr.first  = ul.first + ds->GetRasterXSize() * geotransform[1];
    lr.second = ul.second + ds->GetRasterYSize() * geotransform[5];

    return false;
  error:
    return true;
  }

  void extend(Bounds obounds) {
    ul.first  = std::min(obounds.ul.first, ul.first);
    ul.second = std::max(obounds.ul.second, ul.second);
    lr.first  = std::max(obounds.lr.first, lr.first);
    lr.second = std::min(obounds.lr.second, lr.second);
  }

  std::pair<double, double> ul;
  std::pair<double, double> lr;
};

int
main(int argc, char **argv) {
  if(argc < 3) { std::cout << "usage: stitch <stitch-datasets*> out.tif" << std::endl; return -1; };

  // declarations
  std::vector<GDALDataset *> datasets;
  Bounds bounds;
  bool err;
  int j = 1;
  double geotransform[6];
  int xsize, ysize;
  cv::Ptr<cv::detail::Blender> blender = cv::detail::Blender::createDefault(cv::detail::Blender::FEATHER, false);
  std::vector<cv::Size> sizes;
  std::vector<cv::Point> corners;
  cv::Mat result, result_mask;
  GDALDataset *outds = NULL;
  cv::Size dst_sz;
  float blend_width;

  // init gdal
  GDALAllRegister();

  // open datasets
  for(int i = 1; i < argc - 1; i++) {
    GDALDataset *dataset = (GDALDataset *) GDALOpen(argv[i], GA_ReadOnly);
    check(dataset != NULL, "Could not open %s\n", argv[i]);
    datasets.push_back(dataset);
  }

  err = bounds.FromDataset(datasets.at(0));
  check(err == false, "%s doesn't have geo information", argv[1]);

  // fill out bookkeeping structures
  j = 1;
  for(GDALDataset *ds : datasets) {
    Bounds obounds;
    obounds.FromDataset(ds);
    check(err == false, "%s doesn't have geo information", argv[j]);
    bounds.extend(obounds);
    j++;
  }

  // no need to check err, we did that when we built the bounds up
  datasets[0]->GetGeoTransform(geotransform);
  xsize = (bounds.lr.first - bounds.ul.first) / geotransform[1] + 0.5;
  ysize = (bounds.lr.second - bounds.ul.second) / geotransform[5] + 0.5;
  printf("Creating dataset %s with size %d x %d \n", argv[argc - 1], xsize, ysize);
  printf("and bounds UL: %f %f LR: %f %f\n", bounds.ul.first, bounds.ul.second, bounds.lr.first, bounds.lr.second);

  geotransform[0] = bounds.ul.first;
  geotransform[2] = 0;
  geotransform[3] = bounds.ul.second;
  geotransform[4] = 0;

  // build sizes and point vectors
  j = 1;
  for(GDALDataset *ds : datasets) {
    Bounds obounds;
    obounds.FromDataset(ds);
    std::cout << ds->GetRasterXSize() << ", " << ds->GetRasterYSize() << std::endl;
    cv::Point pt(
      round((obounds.ul.first - geotransform[0]) / geotransform[1]),
      round((obounds.ul.second - geotransform[3]) / geotransform[5])
    );
    corners.push_back(pt);
    std::cout << "placing " << argv[j] << " at " << pt.x << ", " << pt.y << std::endl;

    cv::Size s(
      ((obounds.lr.first - geotransform[0]) / geotransform[1] + 0.5) - pt.x,
      ((obounds.lr.second - geotransform[3]) / geotransform[5] + 0.5) - pt.y
    );
    sizes.push_back(s);
    std::cout << "sizing " << argv[j] << " at " << s.width << ", " << s.height << std::endl;

    j++;
  }

  // from https://github.com/Itseez/opencv/blob/0726c4d4ea80e73c96ccee7bd3ef5f71f46ac82b/samples/cpp/stitching_detailed.cpp#L799
  dst_sz = cv::detail::resultRoi(corners, sizes).size();
  blend_width = sqrt(static_cast<float>(dst_sz.area())) * 5 / 100.f;
  std::cout << "Blending sharpness set to " << 1.f / blend_width << std::endl;
  dynamic_cast<cv::detail::FeatherBlender *>(blender.get())->setSharpness(1.f / blend_width);

  blender->prepare(corners, sizes);

  for(int i = 1; i < argc - 1; i++) {
    cv::Mat im = cv::imread(argv[i]);
    resize(im, im, sizes.at(i - 1), cv::INTER_LANCZOS4);
    std::vector<cv::Mat> channels;
    cv::split(im, channels);
    im.convertTo(im, CV_16SC3);
    std::cout << "merging " << argv[i] << std::endl;
    blender->feed(im, 0xFFFFFF & channels.at(0), corners.at(i - 1));
  }

  blender->blend(result, result_mask);
  std::cout << "writing " << argv[argc - 1] << std::endl;
  cv::imwrite(argv[argc - 1], result);
  std::cout << "done" << std::endl;

  outds = (GDALDataset *) GDALOpen(argv[argc - 1], GA_Update);
  check(outds != NULL, "Could not open %s\n", argv[argc - 1]);

  outds->SetGeoTransform(geotransform);
  outds->SetProjection(datasets.at(0)->GetProjectionRef());

  GDALClose(outds);
  for(GDALDataset *ds : datasets)
    GDALClose(ds);
  return 0;
error:
  if(outds) GDALClose(outds);
  for(GDALDataset *ds : datasets)
    GDALClose(ds);
  return -1;
}<|endoftext|>


<commit_before>// Copyright (c) 2015, Karsten Heinze <karsten.heinze@sidenotes.de>
// 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.
//
// 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 HOLDER 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.

#ifndef SESAME_VERSION_HPP
#define SESAME_VERSION_HPP

#include <cstdint>

namespace sesame {

const uint32_t VERSION_MAJOR = 0;
const uint32_t VERSION_MINOR = 4;
const uint32_t VERSION_BUGFIX = 4;

namespace
{
   static const String getVersionString()
   {
      StringStream s;
      s << "Sesame ";
      s << VERSION_MAJOR << "." << VERSION_MINOR << "." << VERSION_BUGFIX;
      s << " - Copyright (c), 2015 Karsten Heinze";

      return s.str();
   }
}

static const String VERSION_STRING( getVersionString() );

}

#endif
<commit_msg>Version bump.<commit_after>// Copyright (c) 2015, Karsten Heinze <karsten.heinze@sidenotes.de>
// 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.
//
// 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 HOLDER 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.

#ifndef SESAME_VERSION_HPP
#define SESAME_VERSION_HPP

#include <cstdint>

namespace sesame {

const uint32_t VERSION_MAJOR = 0;
const uint32_t VERSION_MINOR = 5;
const uint32_t VERSION_BUGFIX = 0;

namespace
{
   static const String getVersionString()
   {
      StringStream s;
      s << "Sesame ";
      s << VERSION_MAJOR << "." << VERSION_MINOR << "." << VERSION_BUGFIX;
      s << " - Copyright (c), 2015 Karsten Heinze";

      return s.str();
   }
}

static const String VERSION_STRING( getVersionString() );

}

#endif
<|endoftext|>


<commit_before>#include <iterator>
#include <algorithm>
#include <functional>

namespace detail {
template<class RandomIt, class Key=std::less<>>
void mergesort0(RandomIt ix, RandomIt iy, Key key=Key{}) {
    if (ix == iy || std::next(ix) == iy) {
        return;
    }

    auto mid = std::next(ix, std::distance(ix, iy) / 2);

    mergesort0(ix, mid, key);
    mergesort0(mid, iy, key);

    std::inplace_merge(ix, mid, iy, key);
}

template<class RandomIt, class Key=std::less<>>
void mergesort1(RandomIt fst, RandomIt lst, Key key=Key{}) {
    if (fst == lst || std::next(fst) == lst) return;

    auto mid = std::next(fst, std::distance(fst, lst) / 2);

    mergesort1(fst, mid, key);
    mergesort1(mid, lst, key);

    std::vector<
        typename std::iterator_traits<RandomIt>::value_type
    > tmp(fst, lst);

    mid = std::next(tmp.begin(), std::distance(fst, lst) / 2);
    std::merge(tmp.begin(), mid, mid, tmp.end(), fst, key);
}
} // namespace detail

template<class RandomIt, class Key=std::less<>>
void mergesort0(RandomIt begin, RandomIt end, Key key=Key{}) {
    if (begin >= end) return;

    detail::mergesort0(begin, end, key);
}

template<class RandomIt, class Key=std::less<>>
void mergesort1(RandomIt begin, RandomIt end, Key key=Key{}) {
    if (begin >= end) return;

    detail::mergesort1(begin, end, key);
}
<commit_msg>Make naming consistent in mergesort<commit_after>#include <iterator>
#include <algorithm>
#include <functional>

namespace detail {
template<class RandomIt, class Key=std::less<>>
void mergesort0(RandomIt fst, RandomIt lst, Key key=Key{}) {
    if (fst == lst || std::next(fst) == lst) return;

    auto mid = std::next(fst, std::distance(fst, lst) / 2);

    mergesort0(fst, mid, key);
    mergesort0(mid, lst, key);

    std::inplace_merge(fst, mid, lst, key);
}

template<class RandomIt, class Key=std::less<>>
void mergesort1(RandomIt fst, RandomIt lst, Key key=Key{}) {
    if (fst == lst || std::next(fst) == lst) return;

    const auto dst = std::distance(fst, lst);

    auto mid = std::next(fst, dst / 2);

    mergesort1(fst, mid, key);
    mergesort1(mid, lst, key);

    std::vector<
        typename std::iterator_traits<RandomIt>::value_type
    > tmp(fst, lst);

    mid = std::next(tmp.begin(), dst / 2);
    std::merge(tmp.begin(), mid, mid, tmp.end(), fst, key);
}
} // namespace detail

template<class RandomIt, class Key=std::less<>>
void mergesort0(RandomIt fst, RandomIt lst, Key key=Key{}) {
    if (fst == lst) return;

    detail::mergesort0(fst, lst, key);
}

template<class RandomIt, class Key=std::less<>>
void mergesort1(RandomIt fst, RandomIt lst, Key key=Key{}) {
    if (fst == lst) return;

    detail::mergesort1(fst, lst, key);
}
<|endoftext|>


<commit_before>/***********************************************************************************************************************
*                                                                                *
* SPLASH build system v0.2                                                                                *
*                                                                                *
* Copyright (c) 2016 Andrew D. Zonenberg                                                                               *
* 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 author nor the names of any contributors may be used to endorse or promote products     *
*      derived from this software without specific prior written permission.                                           *
*                                                                                *
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS "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 AUTHORS BE HELD 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 "splashdev.h"
#include <splashcore/SplashNet.pb.h>
#include <ext/stdio_filebuf.h>

using namespace std;

void ShowUsage();
void ShowVersion();

//Map of watch descriptors to directory names
map<int, string> g_watchMap;

/**
	@brief Program entry point
 */
int main(int argc, char* argv[])
{
	Severity console_verbosity = Severity::NOTICE;

	//Parse command-line arguments
	for(int i=1; i<argc; i++)
	{
		string s(argv[i]);

		//Let the logger eat its args first
		if(ParseLoggerArguments(i, argc, argv, console_verbosity))
			continue;

		else if(s == "--help")
		{
			ShowUsage();
			return 0;
		}

		else if(s == "--version")
		{
			ShowVersion();
			return 0;
		}

		//Bad argument
		else
		{
			ShowUsage();
			return 1;
		}

	}

	//Set up logging
	g_log_sinks.emplace(g_log_sinks.begin(), new ColoredSTDLogSink(console_verbosity));

	//Print header
	if(console_verbosity >= Severity::NOTICE)
	{
		ShowVersion();
		printf("\n");
	}

	//Load the configuration so we know where the server is, etc
	g_clientSettings = new ClientSettings;

	//Connect to the server
	Socket sock(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
	if(!ConnectToServer(sock, ClientHello::CLIENT_DEVELOPER))
		return 1;

	//Send the devInfo
	SplashMsg devi;
	auto devim = devi.mutable_devinfo();
	devim->set_arch(ShellCommand("dpkg-architecture -l | grep DEB_HOST_GNU_TYPE | cut -d '=' -f 2", true));
	if(!SendMessage(sock, devi))
		return 1;

	//Recursively send file-changed notifications for everything in our working directory
	//(in case anything changed while we weren't running)
	LogVerbose("Sending initial change notifications...\n");
	double start = GetTime();
	SplashMsg icn;
	BuildChangeNotificationForDir(icn.mutable_bulkfilechanged(), g_clientSettings->GetProjectRoot());
	if(!SendMessage(sock, icn))
		return 1;
	SplashMsg icr;
	if(!RecvMessage(sock, icr))
		return 1;
	if(!ProcessBulkFileAck(sock, icr))
		return 1;
	double dt = GetTime() - start;
	LogVerbose("Change notifications sent (in %.3f sec)\n", dt);

	//Open the source directory and start an inotify watcher on it and all subdirectories
	int hnotify = inotify_init();
	if(hnotify < 0)
		LogFatal("Couldn't start inotify\n");
	LogNotice("Watching for changes to source files in: %s\n", g_clientSettings->GetProjectRoot().c_str());
	WatchDirRecursively(hnotify, g_clientSettings->GetProjectRoot());

	//TODO: signal handler so we can quit gracefully

	//Main event loop
	size_t buflen = 8192;
	char ebuf[buflen];
	while(1)
	{
		//Get the event
		ssize_t len = read(hnotify, ebuf, buflen);
		if(len <= 0)
			break;

		ssize_t offset = 0;
		while(offset < len)
		{
			inotify_event* evt = reinterpret_cast<inotify_event*>(ebuf + offset);

			//Skip events without a filename, or hidden files
			if( (evt->len != 0) && (evt->name[0] != '.') )
				WatchedFileChanged(sock, evt->mask, g_watchMap[evt->wd] + "/" + evt->name);

			//Go on to the next one
			offset += sizeof(inotify_event) + evt->len;
		}
	}

	//Done
	close(hnotify);
	delete g_clientSettings;
	return 0;
}

/**
	@brief Add watches to a directory *and* all subdirectories
 */
void WatchDirRecursively(int hnotify, string dir)
{
	//LogDebug("    Recursively watching directory %s\n", dir.c_str());

	//Watch changes to the directory
	int wd;
	if(0 > (wd = inotify_add_watch(
		hnotify,
		dir.c_str(),
		IN_CREATE | IN_DELETE | IN_MODIFY | IN_MOVED_FROM | IN_MOVED_TO | IN_DELETE_SELF)))
	{
		LogFatal("Failed to watch directory %s\n", dir.c_str());
	}

	g_watchMap[wd] = dir;

	//Look for any subdirs and watch them
	vector<string> subdirs;
	FindSubdirs(dir, subdirs);
	for(auto s : subdirs)
		WatchDirRecursively(hnotify, s);
}

void ShowVersion()
{
	printf(
		"SPLASH developer workstation daemon by Andrew D. Zonenberg.\n"
		"\n"
		"License: 3-clause BSD\n"
		"This is free software: you are free to change and redistribute it.\n"
		"There is NO WARRANTY, to the extent permitted by law.\n");
}

void ShowUsage()
{
	printf("Usage: splashdev [standard log arguments]\n");
	exit(0);
}
<commit_msg>splashdev: Do not watch build directory<commit_after>/***********************************************************************************************************************
*                                                                                *
* SPLASH build system v0.2                                                                                *
*                                                                                *
* Copyright (c) 2016 Andrew D. Zonenberg                                                                               *
* 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 author nor the names of any contributors may be used to endorse or promote products     *
*      derived from this software without specific prior written permission.                                           *
*                                                                                *
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS "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 AUTHORS BE HELD 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 "splashdev.h"
#include <splashcore/SplashNet.pb.h>
#include <ext/stdio_filebuf.h>

using namespace std;

void ShowUsage();
void ShowVersion();

//Map of watch descriptors to directory names
map<int, string> g_watchMap;

/**
	@brief Program entry point
 */
int main(int argc, char* argv[])
{
	Severity console_verbosity = Severity::NOTICE;

	//Parse command-line arguments
	for(int i=1; i<argc; i++)
	{
		string s(argv[i]);

		//Let the logger eat its args first
		if(ParseLoggerArguments(i, argc, argv, console_verbosity))
			continue;

		else if(s == "--help")
		{
			ShowUsage();
			return 0;
		}

		else if(s == "--version")
		{
			ShowVersion();
			return 0;
		}

		//Bad argument
		else
		{
			ShowUsage();
			return 1;
		}

	}

	//Set up logging
	g_log_sinks.emplace(g_log_sinks.begin(), new ColoredSTDLogSink(console_verbosity));

	//Print header
	if(console_verbosity >= Severity::NOTICE)
	{
		ShowVersion();
		printf("\n");
	}

	//Load the configuration so we know where the server is, etc
	g_clientSettings = new ClientSettings;

	//Connect to the server
	Socket sock(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
	if(!ConnectToServer(sock, ClientHello::CLIENT_DEVELOPER))
		return 1;

	//Send the devInfo
	SplashMsg devi;
	auto devim = devi.mutable_devinfo();
	devim->set_arch(ShellCommand("dpkg-architecture -l | grep DEB_HOST_GNU_TYPE | cut -d '=' -f 2", true));
	if(!SendMessage(sock, devi))
		return 1;

	//Recursively send file-changed notifications for everything in our working directory
	//(in case anything changed while we weren't running)
	LogVerbose("Sending initial change notifications...\n");
	double start = GetTime();
	SplashMsg icn;
	BuildChangeNotificationForDir(icn.mutable_bulkfilechanged(), g_clientSettings->GetProjectRoot());
	if(!SendMessage(sock, icn))
		return 1;
	SplashMsg icr;
	if(!RecvMessage(sock, icr))
		return 1;
	if(!ProcessBulkFileAck(sock, icr))
		return 1;
	double dt = GetTime() - start;
	LogVerbose("Change notifications sent (in %.3f sec)\n", dt);

	//Open the source directory and start an inotify watcher on it and all subdirectories
	int hnotify = inotify_init();
	if(hnotify < 0)
		LogFatal("Couldn't start inotify\n");
	LogNotice("Watching for changes to source files in: %s\n", g_clientSettings->GetProjectRoot().c_str());
	WatchDirRecursively(hnotify, g_clientSettings->GetProjectRoot());

	//TODO: signal handler so we can quit gracefully

	//Main event loop
	size_t buflen = 8192;
	char ebuf[buflen];
	while(1)
	{
		//Get the event
		ssize_t len = read(hnotify, ebuf, buflen);
		if(len <= 0)
			break;

		ssize_t offset = 0;
		while(offset < len)
		{
			inotify_event* evt = reinterpret_cast<inotify_event*>(ebuf + offset);

			//Skip events without a filename, or hidden files
			if( (evt->len != 0) && (evt->name[0] != '.') )
				WatchedFileChanged(sock, evt->mask, g_watchMap[evt->wd] + "/" + evt->name);

			//Go on to the next one
			offset += sizeof(inotify_event) + evt->len;
		}
	}

	//Done
	close(hnotify);
	delete g_clientSettings;
	return 0;
}

/**
	@brief Add watches to a directory *and* all subdirectories
 */
void WatchDirRecursively(int hnotify, string dir)
{
	//Do not watch the build directory for obvious reasons
	if(dir == "build")
		return;

	//LogDebug("    Recursively watching directory %s\n", dir.c_str());

	//Watch changes to the directory
	int wd;
	if(0 > (wd = inotify_add_watch(
		hnotify,
		dir.c_str(),
		IN_CREATE | IN_DELETE | IN_MODIFY | IN_MOVED_FROM | IN_MOVED_TO | IN_DELETE_SELF)))
	{
		LogFatal("Failed to watch directory %s\n", dir.c_str());
	}

	g_watchMap[wd] = dir;

	//Look for any subdirs and watch them
	vector<string> subdirs;
	FindSubdirs(dir, subdirs);
	for(auto s : subdirs)
		WatchDirRecursively(hnotify, s);
}

void ShowVersion()
{
	printf(
		"SPLASH developer workstation daemon by Andrew D. Zonenberg.\n"
		"\n"
		"License: 3-clause BSD\n"
		"This is free software: you are free to change and redistribute it.\n"
		"There is NO WARRANTY, to the extent permitted by law.\n");
}

void ShowUsage()
{
	printf("Usage: splashdev [standard log arguments]\n");
	exit(0);
}
<|endoftext|>


<commit_before>/*
Copyright (c) 2012-2014 The SSDB Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
*/
#include "ssdb_impl.h"
#include "leveldb/env.h"
#include "leveldb/iterator.h"
#include "leveldb/cache.h"
#include "leveldb/filter_policy.h"

#include "iterator.h"
#include "t_kv.h"
#include "t_hash.h"
#include "t_zset.h"
#include "t_queue.h"

SSDBImpl::SSDBImpl(){
	ldb = NULL;
	binlogs = NULL;
}

SSDBImpl::~SSDBImpl(){
	if(binlogs){
		delete binlogs;
	}
	if(ldb){
		delete ldb;
	}
	if(options.block_cache){
		delete options.block_cache;
	}
	if(options.filter_policy){
		delete options.filter_policy;
	}
}

SSDB* SSDB::open(const Options &opt, const std::string &dir){
	SSDBImpl *ssdb = new SSDBImpl();
	ssdb->options.create_if_missing = true;
	ssdb->options.max_open_files = opt.max_open_files;
	ssdb->options.filter_policy = leveldb::NewBloomFilterPolicy(10);
	ssdb->options.block_cache = leveldb::NewLRUCache(opt.cache_size * 1048576);
	ssdb->options.block_size = opt.block_size * 1024;
	ssdb->options.write_buffer_size = opt.write_buffer_size * 1024 * 1024;
	ssdb->options.compaction_speed = opt.compaction_speed;
	if(opt.compression == "yes"){
		ssdb->options.compression = leveldb::kSnappyCompression;
	}else{
		ssdb->options.compression = leveldb::kNoCompression;
	}

	leveldb::Status status;

	status = leveldb::DB::Open(ssdb->options, dir, &ssdb->ldb);
	if(!status.ok()){
		log_error("open db failed: %s", status.ToString().c_str());
		goto err;
	}
	ssdb->binlogs = new BinlogQueue(ssdb->ldb, opt.binlog, opt.binlog_capacity);

	return ssdb;
err:
	if(ssdb){
		delete ssdb;
	}
	return NULL;
}

int SSDBImpl::flushdb(){
	Transaction trans(binlogs);
	int ret = 0;
	bool stop = false;
	while(!stop){
		leveldb::Iterator *it;
		leveldb::ReadOptions iterate_options;
		iterate_options.fill_cache = false;
		leveldb::WriteOptions write_opts;

		it = ldb->NewIterator(iterate_options);
		it->SeekToFirst();
		for(int i=0; i<10000; i++){
			if(!it->Valid()){
				stop = true;
				break;
			}
			//log_debug("%s", hexmem(it->key().data(), it->key().size()).c_str());
			leveldb::Status s = ldb->Delete(write_opts, it->key());
			if(!s.ok()){
				log_error("del error: %s", s.ToString().c_str());
				stop = true;
				ret = -1;
				break;
			}
			it->Next();
		}
		delete it;
	}
	binlogs->flush();
	return ret;
}

Iterator* SSDBImpl::iterator(const std::string &start, const std::string &end, uint64_t limit){
	leveldb::Iterator *it;
	leveldb::ReadOptions iterate_options;
	iterate_options.fill_cache = false;
	it = ldb->NewIterator(iterate_options);
	it->Seek(start);
	if(it->Valid() && it->key() == start){
		it->Next();
	}
	return new Iterator(it, end, limit);
}

Iterator* SSDBImpl::rev_iterator(const std::string &start, const std::string &end, uint64_t limit){
	leveldb::Iterator *it;
	leveldb::ReadOptions iterate_options;
	iterate_options.fill_cache = false;
	it = ldb->NewIterator(iterate_options);
	it->Seek(start);
	if(!it->Valid()){
		it->SeekToLast();
	}else{
		it->Prev();
	}
	return new Iterator(it, end, limit, Iterator::BACKWARD);
}

/* raw operates */

int SSDBImpl::raw_set(const Bytes &key, const Bytes &val){
	leveldb::WriteOptions write_opts;
	leveldb::Status s = ldb->Put(write_opts, slice(key), slice(val));
	if(!s.ok()){
		log_error("set error: %s", s.ToString().c_str());
		return -1;
	}
	return 1;
}

int SSDBImpl::raw_del(const Bytes &key){
	leveldb::WriteOptions write_opts;
	leveldb::Status s = ldb->Delete(write_opts, slice(key));
	if(!s.ok()){
		log_error("del error: %s", s.ToString().c_str());
		return -1;
	}
	return 1;
}

int SSDBImpl::raw_get(const Bytes &key, std::string *val){
	leveldb::ReadOptions opts;
	opts.fill_cache = false;
	leveldb::Status s = ldb->Get(opts, slice(key), val);
	if(s.IsNotFound()){
		return 0;
	}
	if(!s.ok()){
		log_error("get error: %s", s.ToString().c_str());
		return -1;
	}
	return 1;
}

uint64_t SSDBImpl::size(){
	std::string s = "A";
	std::string e(1, 'z' + 1);
	leveldb::Range ranges[1];
	ranges[0] = leveldb::Range(s, e);
	uint64_t sizes[1];
	ldb->GetApproximateSizes(ranges, 1, sizes);
	return sizes[0];
}

std::vector<std::string> SSDBImpl::info(){
	//  "leveldb.num-files-at-level<N>" - return the number of files at level <N>,
	//     where <N> is an ASCII representation of a level number (e.g. "0").
	//  "leveldb.stats" - returns a multi-line string that describes statistics
	//     about the internal operation of the DB.
	//  "leveldb.sstables" - returns a multi-line string that describes all
	//     of the sstables that make up the db contents.
	std::vector<std::string> info;
	std::vector<std::string> keys;
	/*
	for(int i=0; i<7; i++){
		char buf[128];
		snprintf(buf, sizeof(buf), "leveldb.num-files-at-level%d", i);
		keys.push_back(buf);
	}
	*/
	keys.push_back("leveldb.stats");
	//keys.push_back("leveldb.sstables");

	for(size_t i=0; i<keys.size(); i++){
		std::string key = keys[i];
		std::string val;
		if(ldb->GetProperty(key, &val)){
			info.push_back(key);
			info.push_back(val);
		}
	}

	return info;
}

void SSDBImpl::compact(){
	ldb->CompactRange(NULL, NULL);
}

int SSDBImpl::key_range(std::vector<std::string> *keys){
	int ret = 0;
	std::string kstart, kend;
	std::string hstart, hend;
	std::string zstart, zend;
	std::string qstart, qend;

	Iterator *it;

	it = this->iterator(encode_kv_key(""), "", 1);
	if(it->next()){
		Bytes ks = it->key();
		if(ks.data()[0] == DataType::KV){
			std::string n;
			if(decode_kv_key(ks, &n) == -1){
				ret = -1;
			}else{
				kstart = n;
			}
		}
	}
	delete it;

	it = this->rev_iterator(encode_kv_key("\xff"), "", 1);
	if(it->next()){
		Bytes ks = it->key();
		if(ks.data()[0] == DataType::KV){
			std::string n;
			if(decode_kv_key(ks, &n) == -1){
				ret = -1;
			}else{
				kend = n;
			}
		}
	}
	delete it;

	it = this->iterator(encode_hsize_key(""), "", 1);
	if(it->next()){
		Bytes ks = it->key();
		if(ks.data()[0] == DataType::HSIZE){
			std::string n;
			if(decode_hsize_key(ks, &n) == -1){
				ret = -1;
			}else{
				hstart = n;
			}
		}
	}
	delete it;

	it = this->rev_iterator(encode_hsize_key("\xff"), "", 1);
	if(it->next()){
		Bytes ks = it->key();
		if(ks.data()[0] == DataType::HSIZE){
			std::string n;
			if(decode_hsize_key(ks, &n) == -1){
				ret = -1;
			}else{
				hend = n;
			}
		}
	}
	delete it;

	it = this->iterator(encode_zsize_key(""), "", 1);
	if(it->next()){
		Bytes ks = it->key();
		if(ks.data()[0] == DataType::ZSIZE){
			std::string n;
			if(decode_zsize_key(ks, &n) == -1){
				ret = -1;
			}else{
				zstart = n;
			}
		}
	}
	delete it;

	it = this->rev_iterator(encode_zsize_key("\xff"), "", 1);
	if(it->next()){
		Bytes ks = it->key();
		if(ks.data()[0] == DataType::ZSIZE){
			std::string n;
			if(decode_zsize_key(ks, &n) == -1){
				ret = -1;
			}else{
				zend = n;
			}
		}
	}
	delete it;

	it = this->iterator(encode_qsize_key(""), "", 1);
	if(it->next()){
		Bytes ks = it->key();
		if(ks.data()[0] == DataType::QSIZE){
			std::string n;
			if(decode_qsize_key(ks, &n) == -1){
				ret = -1;
			}else{
				qstart = n;
			}
		}
	}
	delete it;

	it = this->rev_iterator(encode_qsize_key("\xff"), "", 1);
	if(it->next()){
		Bytes ks = it->key();
		if(ks.data()[0] == DataType::QSIZE){
			std::string n;
			if(decode_qsize_key(ks, &n) == -1){
				ret = -1;
			}else{
				qend = n;
			}
		}
	}
	delete it;

	keys->push_back(kstart);
	keys->push_back(kend);
	keys->push_back(hstart);
	keys->push_back(hend);
	keys->push_back(zstart);
	keys->push_back(zend);
	keys->push_back(qstart);
	keys->push_back(qend);

	return ret;
}
<commit_msg>fix flushdb bug<commit_after>/*
Copyright (c) 2012-2014 The SSDB Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
*/
#include "ssdb_impl.h"
#include "leveldb/env.h"
#include "leveldb/iterator.h"
#include "leveldb/cache.h"
#include "leveldb/filter_policy.h"

#include "iterator.h"
#include "t_kv.h"
#include "t_hash.h"
#include "t_zset.h"
#include "t_queue.h"

SSDBImpl::SSDBImpl(){
	ldb = NULL;
	binlogs = NULL;
}

SSDBImpl::~SSDBImpl(){
	if(binlogs){
		delete binlogs;
	}
	if(ldb){
		delete ldb;
	}
	if(options.block_cache){
		delete options.block_cache;
	}
	if(options.filter_policy){
		delete options.filter_policy;
	}
}

SSDB* SSDB::open(const Options &opt, const std::string &dir){
	SSDBImpl *ssdb = new SSDBImpl();
	ssdb->options.create_if_missing = true;
	ssdb->options.max_open_files = opt.max_open_files;
	ssdb->options.filter_policy = leveldb::NewBloomFilterPolicy(10);
	ssdb->options.block_cache = leveldb::NewLRUCache(opt.cache_size * 1048576);
	ssdb->options.block_size = opt.block_size * 1024;
	ssdb->options.write_buffer_size = opt.write_buffer_size * 1024 * 1024;
	ssdb->options.compaction_speed = opt.compaction_speed;
	if(opt.compression == "yes"){
		ssdb->options.compression = leveldb::kSnappyCompression;
	}else{
		ssdb->options.compression = leveldb::kNoCompression;
	}

	leveldb::Status status;

	status = leveldb::DB::Open(ssdb->options, dir, &ssdb->ldb);
	if(!status.ok()){
		log_error("open db failed: %s", status.ToString().c_str());
		goto err;
	}
	ssdb->binlogs = new BinlogQueue(ssdb->ldb, opt.binlog, opt.binlog_capacity);

	return ssdb;
err:
	if(ssdb){
		delete ssdb;
	}
	return NULL;
}

int SSDBImpl::flushdb(){
	int ret = 0;
	bool stop = false;
	{
		Transaction trans(binlogs);
		while(!stop){
			leveldb::Iterator *it;
			leveldb::ReadOptions iterate_options;
			iterate_options.fill_cache = false;
			leveldb::WriteOptions write_opts;

			it = ldb->NewIterator(iterate_options);
			it->SeekToFirst();
			for(int i=0; i<10000; i++){
				if(!it->Valid()){
					stop = true;
					break;
				}
				//log_debug("%s", hexmem(it->key().data(), it->key().size()).c_str());
				leveldb::Status s = ldb->Delete(write_opts, it->key());
				if(!s.ok()){
					log_error("del error: %s", s.ToString().c_str());
					stop = true;
					ret = -1;
					break;
				}
				it->Next();
			}
			delete it;
		}
	}
	binlogs->flush();
	return ret;
}

Iterator* SSDBImpl::iterator(const std::string &start, const std::string &end, uint64_t limit){
	leveldb::Iterator *it;
	leveldb::ReadOptions iterate_options;
	iterate_options.fill_cache = false;
	it = ldb->NewIterator(iterate_options);
	it->Seek(start);
	if(it->Valid() && it->key() == start){
		it->Next();
	}
	return new Iterator(it, end, limit);
}

Iterator* SSDBImpl::rev_iterator(const std::string &start, const std::string &end, uint64_t limit){
	leveldb::Iterator *it;
	leveldb::ReadOptions iterate_options;
	iterate_options.fill_cache = false;
	it = ldb->NewIterator(iterate_options);
	it->Seek(start);
	if(!it->Valid()){
		it->SeekToLast();
	}else{
		it->Prev();
	}
	return new Iterator(it, end, limit, Iterator::BACKWARD);
}

/* raw operates */

int SSDBImpl::raw_set(const Bytes &key, const Bytes &val){
	leveldb::WriteOptions write_opts;
	leveldb::Status s = ldb->Put(write_opts, slice(key), slice(val));
	if(!s.ok()){
		log_error("set error: %s", s.ToString().c_str());
		return -1;
	}
	return 1;
}

int SSDBImpl::raw_del(const Bytes &key){
	leveldb::WriteOptions write_opts;
	leveldb::Status s = ldb->Delete(write_opts, slice(key));
	if(!s.ok()){
		log_error("del error: %s", s.ToString().c_str());
		return -1;
	}
	return 1;
}

int SSDBImpl::raw_get(const Bytes &key, std::string *val){
	leveldb::ReadOptions opts;
	opts.fill_cache = false;
	leveldb::Status s = ldb->Get(opts, slice(key), val);
	if(s.IsNotFound()){
		return 0;
	}
	if(!s.ok()){
		log_error("get error: %s", s.ToString().c_str());
		return -1;
	}
	return 1;
}

uint64_t SSDBImpl::size(){
	std::string s = "A";
	std::string e(1, 'z' + 1);
	leveldb::Range ranges[1];
	ranges[0] = leveldb::Range(s, e);
	uint64_t sizes[1];
	ldb->GetApproximateSizes(ranges, 1, sizes);
	return sizes[0];
}

std::vector<std::string> SSDBImpl::info(){
	//  "leveldb.num-files-at-level<N>" - return the number of files at level <N>,
	//     where <N> is an ASCII representation of a level number (e.g. "0").
	//  "leveldb.stats" - returns a multi-line string that describes statistics
	//     about the internal operation of the DB.
	//  "leveldb.sstables" - returns a multi-line string that describes all
	//     of the sstables that make up the db contents.
	std::vector<std::string> info;
	std::vector<std::string> keys;
	/*
	for(int i=0; i<7; i++){
		char buf[128];
		snprintf(buf, sizeof(buf), "leveldb.num-files-at-level%d", i);
		keys.push_back(buf);
	}
	*/
	keys.push_back("leveldb.stats");
	//keys.push_back("leveldb.sstables");

	for(size_t i=0; i<keys.size(); i++){
		std::string key = keys[i];
		std::string val;
		if(ldb->GetProperty(key, &val)){
			info.push_back(key);
			info.push_back(val);
		}
	}

	return info;
}

void SSDBImpl::compact(){
	ldb->CompactRange(NULL, NULL);
}

int SSDBImpl::key_range(std::vector<std::string> *keys){
	int ret = 0;
	std::string kstart, kend;
	std::string hstart, hend;
	std::string zstart, zend;
	std::string qstart, qend;

	Iterator *it;

	it = this->iterator(encode_kv_key(""), "", 1);
	if(it->next()){
		Bytes ks = it->key();
		if(ks.data()[0] == DataType::KV){
			std::string n;
			if(decode_kv_key(ks, &n) == -1){
				ret = -1;
			}else{
				kstart = n;
			}
		}
	}
	delete it;

	it = this->rev_iterator(encode_kv_key("\xff"), "", 1);
	if(it->next()){
		Bytes ks = it->key();
		if(ks.data()[0] == DataType::KV){
			std::string n;
			if(decode_kv_key(ks, &n) == -1){
				ret = -1;
			}else{
				kend = n;
			}
		}
	}
	delete it;

	it = this->iterator(encode_hsize_key(""), "", 1);
	if(it->next()){
		Bytes ks = it->key();
		if(ks.data()[0] == DataType::HSIZE){
			std::string n;
			if(decode_hsize_key(ks, &n) == -1){
				ret = -1;
			}else{
				hstart = n;
			}
		}
	}
	delete it;

	it = this->rev_iterator(encode_hsize_key("\xff"), "", 1);
	if(it->next()){
		Bytes ks = it->key();
		if(ks.data()[0] == DataType::HSIZE){
			std::string n;
			if(decode_hsize_key(ks, &n) == -1){
				ret = -1;
			}else{
				hend = n;
			}
		}
	}
	delete it;

	it = this->iterator(encode_zsize_key(""), "", 1);
	if(it->next()){
		Bytes ks = it->key();
		if(ks.data()[0] == DataType::ZSIZE){
			std::string n;
			if(decode_zsize_key(ks, &n) == -1){
				ret = -1;
			}else{
				zstart = n;
			}
		}
	}
	delete it;

	it = this->rev_iterator(encode_zsize_key("\xff"), "", 1);
	if(it->next()){
		Bytes ks = it->key();
		if(ks.data()[0] == DataType::ZSIZE){
			std::string n;
			if(decode_zsize_key(ks, &n) == -1){
				ret = -1;
			}else{
				zend = n;
			}
		}
	}
	delete it;

	it = this->iterator(encode_qsize_key(""), "", 1);
	if(it->next()){
		Bytes ks = it->key();
		if(ks.data()[0] == DataType::QSIZE){
			std::string n;
			if(decode_qsize_key(ks, &n) == -1){
				ret = -1;
			}else{
				qstart = n;
			}
		}
	}
	delete it;

	it = this->rev_iterator(encode_qsize_key("\xff"), "", 1);
	if(it->next()){
		Bytes ks = it->key();
		if(ks.data()[0] == DataType::QSIZE){
			std::string n;
			if(decode_qsize_key(ks, &n) == -1){
				ret = -1;
			}else{
				qend = n;
			}
		}
	}
	delete it;

	keys->push_back(kstart);
	keys->push_back(kend);
	keys->push_back(hstart);
	keys->push_back(hend);
	keys->push_back(zstart);
	keys->push_back(zend);
	keys->push_back(qstart);
	keys->push_back(qend);

	return ret;
}
<|endoftext|>


<commit_before>// **********************************************************************************
//
// BSD License.
// This file is part of upnpx.
//
// Copyright (c) 2010-2011, Bruno Keymolen, email: bruno.keymolen@gmail.com
// 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 "Bruno Keymolen" 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 HOLDER 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 "ssdptools.h"

#include <stdlib.h>

int GetHeaderValueFromCollection(vector<SSDP_HTTP_HEADER*> headers, u8* fieldname, int fieldnamelen, u8** value, int *len){
    int ret=0;
    int found=0;

    vector<SSDP_HTTP_HEADER*>::const_iterator it;
    SSDP_HTTP_HEADER *hdr;

    if(headers.size() <= 0){
        ret = -1;
        goto EXIT;
    }

    for(it=headers.begin();it<headers.end();it++){
        hdr = *it;
        if(caseinstringcmp(fieldname, fieldnamelen, hdr->fieldname, hdr->fieldnamelen) == 0){
            //found
            found=1;
            break;
        }
    }

    if(found){
        *value=hdr->fieldvalue;
        *len=hdr->fieldvaluelen;
    }else{
        ret =-1;
    }

EXIT:
    return ret;
}

//Possible formats:
// uuid:device-UUID
// uuid:device-UUID::upnp:rootdevice
// uuid:device-UUID::urn :schemas-upnp-org:device :deviceType :ver
// uuid:device-UUID::urn :schemas-upnp-org:service:serviceType:ver
// uuid:device-UUID::urn :domain-name     :device :deviceType :ver
// uuid:device-UUID::urn :domain-name     :service:serviceType:ver
// 1    2            3    4                5       6           7

int ParseUSN(u8* uuidraw, u32 len, ssdpuuid *uuid){
    int ret = 0;
    int colon1 = 0;
    int colon2 = 0;
    int tel;

//    int lenleft;

    //Sanity
    if(uuid == NULL || len == 0){
        return -1;
    }
    if(memcmp(uuidraw, "uuid", 4) != 0){
        return -2;
    }

    memset(uuid, 0, sizeof(ssdpuuid));

//    lenleft = len;

    //uuid
    colon1 = getchar(uuidraw, len, ':', 1);
    colon2 = getchar(uuidraw, len, ':', 2);
    if(colon1<0 || colon1+1>=len){ ret = -1;goto EXIT;}
    if(colon2<0){
        uuid->uuid=uuidraw;//+colon1+1;
        uuid->uuidlen=len;//-colon1-1;
        //uuid->uuidlen=len-colon1-1;
        goto EXIT;
    }else{
        uuid->uuid=uuidraw;//+colon1+1;
        uuid->uuidlen=colon2;
//        uuid->uuidlen=colon2-colon1-1;
    }

    //Sanity, there must be a double colon
    colon1 = getchar(uuidraw, len, ':', 2);
    colon2 = getchar(uuidraw, len, ':', 3);
    if(colon2-colon1 != 1){
        ret = -2;
        goto EXIT;
    }

    //upnp, isroot
    colon1 = getchar(uuidraw, len, ':', 3);
    if((len-colon1)>=15 && memcmp(uuidraw+colon1+1, "upnp:rootdevice", 15)==0 ){
        uuid->isrootdevice = 1;
        uuid->isdevice = 1;
        uuid->type = uuidraw+colon1+1;
        uuid->typelen = 15;
        goto EXIT;
    }

    //Sanity, there must be 4 colons after
    for(tel=4;tel<=7;tel++){
        colon1 = getchar(uuidraw, len, ':', tel);
        if(colon1 < 0){
            ret = -3;
            goto EXIT;
        }
    }

    //urn
    colon1 = getchar(uuidraw, len, ':', 3);
    colon2 = getchar(uuidraw, len, ':', 4);
    if((colon2-colon1)>=3 && memcmp(uuidraw+colon1+1, "urn", 3)!=0 ){
        ret = -4;
        goto EXIT;
    }
    uuid->fullurn = uuidraw+colon1+1;
    uuid->fullurnlen = len-colon1-1;

    colon1 = getchar(uuidraw, len, ':', 4);
    colon2 = getchar(uuidraw, len, ':', 5);
    uuid->urn=uuidraw+colon1+1;
    uuid->urnlen=colon2-colon1-1;

    //Device or service
    colon1 = getchar(uuidraw, len, ':', 5);
    colon2 = getchar(uuidraw, len, ':', 6);
    if( (colon2-colon1)>=6 && memcmp(uuidraw+colon1+1, "device", 6)==0){
        //device
        uuid->isdevice = 1;
    }else if((colon2-colon1)>=7 && memcmp(uuidraw+colon1+1, "service", 7)==0){
        //service
        uuid->isservice = 1;
    }else{
        ret = -5;
        goto EXIT;
    }

    //servicetype / devicetype
    colon1 = getchar(uuidraw, len, ':', 6);
    colon2 = getchar(uuidraw, len, ':', 7);
    uuid->type = uuidraw+colon1+1;
    uuid->typelen=colon2-colon1-1;

    //Workaround for MusicPal bug
    if(uuid->typelen==16 && memcmp(uuid->type, "RenderingControl", 16) == 0){
        uuid->isdevice = 0;
        uuid->isrootdevice = 0;
        uuid->isservice = 1;
    }

    //version
    uuid->version = uuidraw+colon2+1;
    uuid->versionlen=len-colon2-1;

EXIT:

    return ret;
}

int cachecontroltoi(u8* s, u32 l){
    u32 ret = -1;
    u32 p;

    char buf[1024];
    int buflen=1024;

    if(l >= buflen){
        return ret;
    }

    memcpy(&buf, s, l);
    buf[l]=0;

    //max-age=nn
    trimspaces(&s, &l);
    if(l >= 7 && caseinstringcmp(s, 7, (u8*)"max-age", 7) == 0){
        //search the =
        p = getchar((u8*)buf, (unsigned int)strlen(buf), '=');
        if(p > 0){
            ret = atoi(buf+p+1);
        }
    }

    return ret;
}

<commit_msg>Parse uuid values that contain colons<commit_after>// **********************************************************************************
//
// BSD License.
// This file is part of upnpx.
//
// Copyright (c) 2010-2011, Bruno Keymolen, email: bruno.keymolen@gmail.com
// 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 "Bruno Keymolen" 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 HOLDER 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 "ssdptools.h"

#include <stdlib.h>

int GetHeaderValueFromCollection(vector<SSDP_HTTP_HEADER*> headers, u8* fieldname, int fieldnamelen, u8** value, int *len){
    int ret=0;
    int found=0;

    vector<SSDP_HTTP_HEADER*>::const_iterator it;
    SSDP_HTTP_HEADER *hdr;

    if(headers.size() <= 0){
        ret = -1;
        goto EXIT;
    }

    for(it=headers.begin();it<headers.end();it++){
        hdr = *it;
        if(caseinstringcmp(fieldname, fieldnamelen, hdr->fieldname, hdr->fieldnamelen) == 0){
            //found
            found=1;
            break;
        }
    }

    if(found){
        *value=hdr->fieldvalue;
        *len=hdr->fieldvaluelen;
    }else{
        ret =-1;
    }

EXIT:
    return ret;
}

//Possible formats:
// uuid:device-UUID
// uuid:device-UUID::upnp:rootdevice
// uuid:device-UUID::urn :schemas-upnp-org:device :deviceType :ver
// uuid:device-UUID::urn :schemas-upnp-org:service:serviceType:ver
// uuid:device-UUID::urn :domain-name     :device :deviceType :ver
// uuid:device-UUID::urn :domain-name     :service:serviceType:ver
// 1    2            3    4                5       6           7

int ParseUSN(u8* uuidraw, u32 len, ssdpuuid *uuid){
    int ret = 0;
    int colon1 = 0;
    int colon2 = 0;
    int tel;
    int skip=0;

//    int lenleft;

    //Sanity
    if(uuid == NULL || len == 0){
        return -1;
    }
    if(memcmp(uuidraw, "uuid", 4) != 0){
        return -2;
    }

    memset(uuid, 0, sizeof(ssdpuuid));

//    lenleft = len;

    //uuid
    colon1 = getchar(uuidraw, len, ':', 1);
    colon2 = getchar(uuidraw, len, ':', 2);
    if(colon1<0 || colon1+1>=len){ ret = -1;goto EXIT;}
    if(colon2<0){
        uuid->uuid=uuidraw;//+colon1+1;
        uuid->uuidlen=len;//-colon1-1;
        //uuid->uuidlen=len-colon1-1;
        goto EXIT;
    }else{
        uuid->uuid=uuidraw;//+colon1+1;
        uuid->uuidlen=colon2;
//        uuid->uuidlen=colon2-colon1-1;
    }

    //Sanity, there must be a double colon
    //Find the first '::' sequence and compute the number of semicolons to it
    //store it in the skip variable, which is used for offsetting subsequent searches
    //this is needed for some devices that have a semicolon in the name
    colon1 = getchar(uuidraw, len, ':', 2);
    colon2 = -1;
    while (colon1 < len && colon2 == -1) {
        colon2 = getchar(uuidraw, len, ':', 2+skip+1);
        if (colon2-colon1 == 1) {
            uuid->uuidlen=colon1;
            colon1 = colon2;
        } else {
            colon1 = colon2;
            colon2 = -1;
            skip++;
        }
    }
    if(colon2 == -1){
        ret = -2;
        goto EXIT;
    }

    //upnp, isroot
    colon1 = getchar(uuidraw, len, ':', 3+skip);
    if((len-colon1)>=15 && memcmp(uuidraw+colon1+1, "upnp:rootdevice", 15)==0 ){
        uuid->isrootdevice = 1;
        uuid->isdevice = 1;
        uuid->type = uuidraw+colon1+1;
        uuid->typelen = 15;
        goto EXIT;
    }

    //Sanity, there must be 4 colons after
    for(tel=4+skip;tel<=7+skip;tel++){
        colon1 = getchar(uuidraw, len, ':', tel);
        if(colon1 < 0){
            ret = -3;
            goto EXIT;
        }
    }

    //urn
    colon1 = getchar(uuidraw, len, ':', 3+skip);
    colon2 = getchar(uuidraw, len, ':', 4+skip);
    if((colon2-colon1)>=3 && memcmp(uuidraw+colon1+1, "urn", 3)!=0 ){
        ret = -4;
        goto EXIT;
    }
    uuid->fullurn = uuidraw+colon1+1;
    uuid->fullurnlen = len-colon1-1;

    colon1 = getchar(uuidraw, len, ':', 4+skip);
    colon2 = getchar(uuidraw, len, ':', 5+skip);
    uuid->urn=uuidraw+colon1+1;
    uuid->urnlen=colon2-colon1-1;

    //Device or service
    colon1 = getchar(uuidraw, len, ':', 5+skip);
    colon2 = getchar(uuidraw, len, ':', 6+skip);
    if( (colon2-colon1)>=6 && memcmp(uuidraw+colon1+1, "device", 6)==0){
        //device
        uuid->isdevice = 1;
    }else if((colon2-colon1)>=7 && memcmp(uuidraw+colon1+1, "service", 7)==0){
        //service
        uuid->isservice = 1;
    }else{
        ret = -5;
        goto EXIT;
    }

    //servicetype / devicetype
    colon1 = getchar(uuidraw, len, ':', 6+skip);
    colon2 = getchar(uuidraw, len, ':', 7+skip);
    uuid->type = uuidraw+colon1+1;
    uuid->typelen=colon2-colon1-1;

    //Workaround for MusicPal bug
    if(uuid->typelen==16 && memcmp(uuid->type, "RenderingControl", 16) == 0){
        uuid->isdevice = 0;
        uuid->isrootdevice = 0;
        uuid->isservice = 1;
    }

    //version
    uuid->version = uuidraw+colon2+1;
    uuid->versionlen=len-colon2-1;

EXIT:

    return ret;
}

int cachecontroltoi(u8* s, u32 l){
    u32 ret = -1;
    u32 p;

    char buf[1024];
    int buflen=1024;

    if(l >= buflen){
        return ret;
    }

    memcpy(&buf, s, l);
    buf[l]=0;

    //max-age=nn
    trimspaces(&s, &l);
    if(l >= 7 && caseinstringcmp(s, 7, (u8*)"max-age", 7) == 0){
        //search the =
        p = getchar((u8*)buf, (unsigned int)strlen(buf), '=');
        if(p > 0){
            ret = atoi(buf+p+1);
        }
    }

    return ret;
}

<|endoftext|>


<commit_before>/*
 * SSL and TLS filter.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "ssl_filter.hxx"
#include "ssl_factory.hxx"
#include "ssl_config.hxx"
#include "ssl_quark.hxx"
#include "thread_socket_filter.hxx"
#include "pool.hxx"
#include "gerrno.h"
#include "fb_pool.hxx"
#include "SliceFifoBuffer.hxx"

#include <openssl/ssl.h>
#include <openssl/err.h>

#include <assert.h>
#include <string.h>

/**
 * Throttle if a #BIO grows larger than this number of bytes.
 */
static constexpr int SSL_THROTTLE_THRESHOLD = 16384;

struct SslFilter {
    /**
     * Buffers which can be accessed from within the thread without
     * holding locks.  These will be copied to/from the according
     * #thread_socket_filter buffers.
     */
    SliceFifoBuffer decrypted_input, plain_output;

    /**
     * Memory BIOs for passing data to/from OpenSSL.
     */
    BIO *const encrypted_input, *const encrypted_output;

    SSL *const ssl;

    bool handshaking = true;

    char *peer_subject = nullptr, *peer_issuer_subject = nullptr;

    SslFilter(SSL *_ssl)
        :encrypted_input(BIO_new(BIO_s_mem())),
         encrypted_output(BIO_new(BIO_s_mem())),
         ssl(_ssl) {
        decrypted_input.Allocate(fb_pool_get());
        SSL_set_bio(ssl, encrypted_input, encrypted_output);
    }

    ~SslFilter() {
        SSL_free(ssl);

        decrypted_input.Free(fb_pool_get());
        plain_output.FreeIfDefined(fb_pool_get());

        free(peer_subject);
        free(peer_issuer_subject);
    }
};

static void
ssl_set_error(GError **error_r)
{
    if (error_r == nullptr)
        return;

    unsigned long error = ERR_get_error();
    char buffer[120];
    g_set_error(error_r, ssl_quark(), 0, "%s",
                ERR_error_string(error, buffer));
}

/**
 * Is the #BIO full, i.e. above the #SSL_THROTTLE_THRESHOLD?
 */
gcc_pure
static bool
IsFull(BIO *bio)
{
    return BIO_pending(bio) >= SSL_THROTTLE_THRESHOLD;
}

/**
 * Move data from #src to #dest.
 */
static void
Move(BIO *dest, ForeignFifoBuffer<uint8_t> &src)
{
    auto r = src.Read();
    if (r.IsEmpty())
        return;

    if (IsFull(dest))
        /* throttle */
        return;

    int nbytes = BIO_write(dest, r.data, r.size);
    if (nbytes > 0)
        src.Consume(nbytes);
}

static void
Move(ForeignFifoBuffer<uint8_t> &dest, BIO *src)
{
    while (true) {
        auto w = dest.Write();
        if (w.IsEmpty())
            return;

        int nbytes = BIO_read(src, w.data, w.size);
        if (nbytes <= 0)
            return;

        dest.Append(nbytes);
    }
}

static char *
format_name(X509_NAME *name)
{
    if (name == nullptr)
        return nullptr;

    BIO *bio = BIO_new(BIO_s_mem());
    if (bio == nullptr)
        return nullptr;

    X509_NAME_print_ex(bio, name, 0,
                       ASN1_STRFLGS_UTF8_CONVERT | XN_FLAG_SEP_COMMA_PLUS);
    char buffer[1024];
    int length = BIO_read(bio, buffer, sizeof(buffer) - 1);
    BIO_free(bio);

    return strndup(buffer, length);
}

static char *
format_subject_name(X509 *cert)
{
    return format_name(X509_get_subject_name(cert));
}

static char *
format_issuer_subject_name(X509 *cert)
{
    return format_name(X509_get_issuer_name(cert));
}

gcc_pure
static bool
is_ssl_error(SSL *ssl, int ret)
{
    if (ret == 0)
        /* this is always an error according to the documentation of
           SSL_read(), SSL_write() and SSL_do_handshake() */
        return true;

    switch (SSL_get_error(ssl, ret)) {
    case SSL_ERROR_NONE:
    case SSL_ERROR_WANT_READ:
    case SSL_ERROR_WANT_WRITE:
    case SSL_ERROR_WANT_CONNECT:
    case SSL_ERROR_WANT_ACCEPT:
        return false;

    default:
        return true;
    }
}

static bool
check_ssl_error(SSL *ssl, int result, GError **error_r)
{
    if (is_ssl_error(ssl, result)) {
        ssl_set_error(error_r);
        return false;
    } else
        return true;
}

/**
 * @return false on error
 */
static bool
ssl_decrypt(SSL *ssl, ForeignFifoBuffer<uint8_t> &buffer, GError **error_r)
{
    /* SSL_read() must be called repeatedly until there is no more
       data (or until the buffer is full) */

    while (true) {
        auto w = buffer.Write();
        if (w.IsEmpty())
            return true;

        int result = SSL_read(ssl, w.data, w.size);
        if (result <= 0)
            return check_ssl_error(ssl, result, error_r);

        buffer.Append(result);
    }
}

/**
 * @return false on error
 */
static bool
ssl_encrypt(SSL *ssl, ForeignFifoBuffer<uint8_t> &buffer, GError **error_r)
{
    auto r = buffer.Read();
    if (r.IsEmpty())
        return true;

    int result = SSL_write(ssl, r.data, r.size);
    if (result <= 0)
        return check_ssl_error(ssl, result, error_r);

    buffer.Consume(result);
    return true;
}

static bool
ssl_encrypt(SslFilter &ssl, GError **error_r)
{
    return IsFull(ssl.encrypted_output) || /* throttle? */
        ssl_encrypt(ssl.ssl, ssl.plain_output, error_r);
}

/*
 * thread_socket_filter_handler
 *
 */

static bool
ssl_thread_socket_filter_run(ThreadSocketFilter &f, GError **error_r,
                             void *ctx)
{
    auto *const ssl = (SslFilter *)ctx;

    /* copy input (and output to make room for more output) */

    {
        std::unique_lock<std::mutex> lock(f.mutex);

        f.decrypted_input.MoveFrom(ssl->decrypted_input);
        ssl->plain_output.MoveFromAllowNull(f.plain_output);
        Move(ssl->encrypted_input, f.encrypted_input);
        Move(f.encrypted_output, ssl->encrypted_output);
    }

    /* let OpenSSL work */

    ERR_clear_error();

    if (gcc_unlikely(ssl->handshaking)) {
        int result = SSL_do_handshake(ssl->ssl);
        if (result == 1) {
            ssl->handshaking = false;

            X509 *cert = SSL_get_peer_certificate(ssl->ssl);
            if (cert != nullptr) {
                ssl->peer_subject = format_subject_name(cert);
                ssl->peer_issuer_subject = format_issuer_subject_name(cert);
                X509_free(cert);
            }
        } else if (!check_ssl_error(ssl->ssl, result, error_r))
            return false;
    }

    if (gcc_likely(!ssl->handshaking) &&
        (!ssl_encrypt(*ssl, error_r) ||
         !ssl_decrypt(ssl->ssl, ssl->decrypted_input, error_r)))
        return false;

    /* copy output */

    {
        std::unique_lock<std::mutex> lock(f.mutex);

        f.decrypted_input.MoveFrom(ssl->decrypted_input);

        /* let the main thread free our plain_output buffer */
        ssl->plain_output.SwapIfNull(f.plain_output);

        Move(f.encrypted_output, ssl->encrypted_output);
        f.drained = ssl->plain_output.IsEmpty() &&
            BIO_eof(ssl->encrypted_output);
    }

    return true;
}

static void
ssl_thread_socket_filter_destroy(gcc_unused ThreadSocketFilter &f, void *ctx)
{
    auto *const ssl = (SslFilter *)ctx;

    ssl->~SslFilter();
}

const struct ThreadSocketFilterHandler ssl_thread_socket_filter = {
    ssl_thread_socket_filter_run,
    ssl_thread_socket_filter_destroy,
};

/*
 * constructor
 *
 */

SslFilter *
ssl_filter_new(struct pool *pool, ssl_factory &factory,
               GError **error_r)
{
    assert(pool != nullptr);

    auto *_ssl = ssl_factory_make(factory);
    if (_ssl == nullptr) {
        g_set_error(error_r, ssl_quark(), 0, "SSL_new() failed");
        return nullptr;
    }

    return NewFromPool<SslFilter>(*pool, _ssl);
}

const char *
ssl_filter_get_peer_subject(SslFilter *ssl)
{
    assert(ssl != nullptr);

    return ssl->peer_subject;
}

const char *
ssl_filter_get_peer_issuer_subject(SslFilter *ssl)
{
    assert(ssl != nullptr);

    return ssl->peer_issuer_subject;
}
<commit_msg>ssl/filter: use class AllocatedString<commit_after>/*
 * SSL and TLS filter.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "ssl_filter.hxx"
#include "ssl_factory.hxx"
#include "ssl_config.hxx"
#include "ssl_quark.hxx"
#include "thread_socket_filter.hxx"
#include "pool.hxx"
#include "gerrno.h"
#include "fb_pool.hxx"
#include "SliceFifoBuffer.hxx"
#include "util/AllocatedString.hxx"

#include <openssl/ssl.h>
#include <openssl/err.h>

#include <assert.h>
#include <string.h>

/**
 * Throttle if a #BIO grows larger than this number of bytes.
 */
static constexpr int SSL_THROTTLE_THRESHOLD = 16384;

struct SslFilter {
    /**
     * Buffers which can be accessed from within the thread without
     * holding locks.  These will be copied to/from the according
     * #thread_socket_filter buffers.
     */
    SliceFifoBuffer decrypted_input, plain_output;

    /**
     * Memory BIOs for passing data to/from OpenSSL.
     */
    BIO *const encrypted_input, *const encrypted_output;

    SSL *const ssl;

    bool handshaking = true;

    AllocatedString<> peer_subject = nullptr, peer_issuer_subject = nullptr;

    SslFilter(SSL *_ssl)
        :encrypted_input(BIO_new(BIO_s_mem())),
         encrypted_output(BIO_new(BIO_s_mem())),
         ssl(_ssl) {
        decrypted_input.Allocate(fb_pool_get());
        SSL_set_bio(ssl, encrypted_input, encrypted_output);
    }

    ~SslFilter() {
        SSL_free(ssl);

        decrypted_input.Free(fb_pool_get());
        plain_output.FreeIfDefined(fb_pool_get());
    }
};

static void
ssl_set_error(GError **error_r)
{
    if (error_r == nullptr)
        return;

    unsigned long error = ERR_get_error();
    char buffer[120];
    g_set_error(error_r, ssl_quark(), 0, "%s",
                ERR_error_string(error, buffer));
}

/**
 * Is the #BIO full, i.e. above the #SSL_THROTTLE_THRESHOLD?
 */
gcc_pure
static bool
IsFull(BIO *bio)
{
    return BIO_pending(bio) >= SSL_THROTTLE_THRESHOLD;
}

/**
 * Move data from #src to #dest.
 */
static void
Move(BIO *dest, ForeignFifoBuffer<uint8_t> &src)
{
    auto r = src.Read();
    if (r.IsEmpty())
        return;

    if (IsFull(dest))
        /* throttle */
        return;

    int nbytes = BIO_write(dest, r.data, r.size);
    if (nbytes > 0)
        src.Consume(nbytes);
}

static void
Move(ForeignFifoBuffer<uint8_t> &dest, BIO *src)
{
    while (true) {
        auto w = dest.Write();
        if (w.IsEmpty())
            return;

        int nbytes = BIO_read(src, w.data, w.size);
        if (nbytes <= 0)
            return;

        dest.Append(nbytes);
    }
}

static AllocatedString<>
format_name(X509_NAME *name)
{
    if (name == nullptr)
        return nullptr;

    BIO *bio = BIO_new(BIO_s_mem());
    if (bio == nullptr)
        return nullptr;

    X509_NAME_print_ex(bio, name, 0,
                       ASN1_STRFLGS_UTF8_CONVERT | XN_FLAG_SEP_COMMA_PLUS);
    char buffer[1024];
    int length = BIO_read(bio, buffer, sizeof(buffer) - 1);
    BIO_free(bio);

    return AllocatedString<>::Duplicate(buffer, length);
}

static AllocatedString<>
format_subject_name(X509 *cert)
{
    return format_name(X509_get_subject_name(cert));
}

static AllocatedString<>
format_issuer_subject_name(X509 *cert)
{
    return format_name(X509_get_issuer_name(cert));
}

gcc_pure
static bool
is_ssl_error(SSL *ssl, int ret)
{
    if (ret == 0)
        /* this is always an error according to the documentation of
           SSL_read(), SSL_write() and SSL_do_handshake() */
        return true;

    switch (SSL_get_error(ssl, ret)) {
    case SSL_ERROR_NONE:
    case SSL_ERROR_WANT_READ:
    case SSL_ERROR_WANT_WRITE:
    case SSL_ERROR_WANT_CONNECT:
    case SSL_ERROR_WANT_ACCEPT:
        return false;

    default:
        return true;
    }
}

static bool
check_ssl_error(SSL *ssl, int result, GError **error_r)
{
    if (is_ssl_error(ssl, result)) {
        ssl_set_error(error_r);
        return false;
    } else
        return true;
}

/**
 * @return false on error
 */
static bool
ssl_decrypt(SSL *ssl, ForeignFifoBuffer<uint8_t> &buffer, GError **error_r)
{
    /* SSL_read() must be called repeatedly until there is no more
       data (or until the buffer is full) */

    while (true) {
        auto w = buffer.Write();
        if (w.IsEmpty())
            return true;

        int result = SSL_read(ssl, w.data, w.size);
        if (result <= 0)
            return check_ssl_error(ssl, result, error_r);

        buffer.Append(result);
    }
}

/**
 * @return false on error
 */
static bool
ssl_encrypt(SSL *ssl, ForeignFifoBuffer<uint8_t> &buffer, GError **error_r)
{
    auto r = buffer.Read();
    if (r.IsEmpty())
        return true;

    int result = SSL_write(ssl, r.data, r.size);
    if (result <= 0)
        return check_ssl_error(ssl, result, error_r);

    buffer.Consume(result);
    return true;
}

static bool
ssl_encrypt(SslFilter &ssl, GError **error_r)
{
    return IsFull(ssl.encrypted_output) || /* throttle? */
        ssl_encrypt(ssl.ssl, ssl.plain_output, error_r);
}

/*
 * thread_socket_filter_handler
 *
 */

static bool
ssl_thread_socket_filter_run(ThreadSocketFilter &f, GError **error_r,
                             void *ctx)
{
    auto *const ssl = (SslFilter *)ctx;

    /* copy input (and output to make room for more output) */

    {
        std::unique_lock<std::mutex> lock(f.mutex);

        f.decrypted_input.MoveFrom(ssl->decrypted_input);
        ssl->plain_output.MoveFromAllowNull(f.plain_output);
        Move(ssl->encrypted_input, f.encrypted_input);
        Move(f.encrypted_output, ssl->encrypted_output);
    }

    /* let OpenSSL work */

    ERR_clear_error();

    if (gcc_unlikely(ssl->handshaking)) {
        int result = SSL_do_handshake(ssl->ssl);
        if (result == 1) {
            ssl->handshaking = false;

            X509 *cert = SSL_get_peer_certificate(ssl->ssl);
            if (cert != nullptr) {
                ssl->peer_subject = format_subject_name(cert);
                ssl->peer_issuer_subject = format_issuer_subject_name(cert);
                X509_free(cert);
            }
        } else if (!check_ssl_error(ssl->ssl, result, error_r))
            return false;
    }

    if (gcc_likely(!ssl->handshaking) &&
        (!ssl_encrypt(*ssl, error_r) ||
         !ssl_decrypt(ssl->ssl, ssl->decrypted_input, error_r)))
        return false;

    /* copy output */

    {
        std::unique_lock<std::mutex> lock(f.mutex);

        f.decrypted_input.MoveFrom(ssl->decrypted_input);

        /* let the main thread free our plain_output buffer */
        ssl->plain_output.SwapIfNull(f.plain_output);

        Move(f.encrypted_output, ssl->encrypted_output);
        f.drained = ssl->plain_output.IsEmpty() &&
            BIO_eof(ssl->encrypted_output);
    }

    return true;
}

static void
ssl_thread_socket_filter_destroy(gcc_unused ThreadSocketFilter &f, void *ctx)
{
    auto *const ssl = (SslFilter *)ctx;

    ssl->~SslFilter();
}

const struct ThreadSocketFilterHandler ssl_thread_socket_filter = {
    ssl_thread_socket_filter_run,
    ssl_thread_socket_filter_destroy,
};

/*
 * constructor
 *
 */

SslFilter *
ssl_filter_new(struct pool *pool, ssl_factory &factory,
               GError **error_r)
{
    assert(pool != nullptr);

    auto *_ssl = ssl_factory_make(factory);
    if (_ssl == nullptr) {
        g_set_error(error_r, ssl_quark(), 0, "SSL_new() failed");
        return nullptr;
    }

    return NewFromPool<SslFilter>(*pool, _ssl);
}

const char *
ssl_filter_get_peer_subject(SslFilter *ssl)
{
    assert(ssl != nullptr);

    return ssl->peer_subject.c_str();
}

const char *
ssl_filter_get_peer_issuer_subject(SslFilter *ssl)
{
    assert(ssl != nullptr);

    return ssl->peer_issuer_subject.c_str();
}
<|endoftext|>


<commit_before>// NOTE: Instead of .c files, C++ uses .cpp files
// NOTE: Instead of .h files, C++ uses .hpp files
//   However, .hpp extensions are not specified for C++ standard libraries

// iostream: basic io streaming operations (cin, cout, etc.)
#include <iostream>
// string: true string type
#include <string>
// sstream: stringstream, which converts strings to streams
#include <sstream>
// fstream: filestream, read and write files easily as streams
#include <fstream>

// Just like Python, C++ uses namespaces to organize symbols into logical
// groupings, which helps keep things tidy
// Unlike Python, C++ uses the symbol :: to look inside a namespace
// (Python uses the . symbol, just like for a C/C++ struct)
namespace foo
{
    // std:: denotes the "standard namespace"
    // cout takes a string as a stream and prints it to stdout
    // endl is the cross-platform stream version of an end-of-line character \n
    void print() { std::cout << "This is printing from foo." << std::endl; }
}

// Multiple namespaces may be defined easily
namespace bar
{
    // This is bar::print, which is distinct from foo::print above
    void print() { std::cout << "This is printing from bar." << std::endl; }
}

// Exactly like C, a C++ program must have a main function with arguments:
//   argc : int count of commandline arguments
//   argv : array of C-strings, meaning a pointer to an array of char pointers
int main(int argc, char **argv)
{
    // specify that everything in the namespace std should
    // become available in the local scope for convenience
    // NOTE: This is forbidden the Google style guide, but is included here
    //       for completeness - generally don't do this to keep namespaces clear
    using namespace std;

    // Example of command line usage
    if ( argc != 2 )
    {
        // The stream operator << automatically converts types
        // so here the C-string (char *) of argv[0] is converted to a
        // true C++ string, then passed as a stream to cout
        //
        // Note : the std prefix is not needed due to the "using" call above
        cout << "Usage: " << argv[0] << " arg1" << endl;
        return 1;
    }
    cout << "arg1 = " << argv[1] << endl;

    // Functions within distinct namespaces can be called directly
    foo::print();
    bar::print();

    // specify that print from foo:: should be pulled into local scope
    using foo::print;

    // demonstration that the foo:: prefix is no longer needed
    print();

    // define true string variable to hold input
    string input_str;

    // define float and int types to hold parsed input
    float fnum=0;
    int   inum=0;

    // Ask for input from user as a string
    cout << "Enter a float: ";

    // get entire line until a carriage return
    getline(cin, input_str);

    // use streams to parse the string input as different types
    stringstream(input_str) >> fnum;
    stringstream(input_str) >> inum;

    // show result of parsed input
    cout << "Input as a float: " << fnum << endl;
    cout << "Input as an int : " << inum << endl;

    // file handle
    ofstream output_file;

    // open a file
    output_file.open("output_file.txt");

    // check that file opened successfully
    if ( !output_file.is_open() )
    {
        // Print error to standard error (not standard out)
        cerr << "Error: Could not open file" << endl;
    }
    else
    {
        // write to file as a stream
        output_file << "This is the first line of the file." << endl;
        output_file << "Input as a float: " << fnum << '\t'; // \t = tab character
        output_file << "Input as an int : " << inum << endl;
        // explicitly close the file
        // (the file is also closed automatically when the program terminates)
        output_file.close();
    }

    // (this is implicit if omitted)
    return 0;
}
<commit_msg>fix to .cc<commit_after>// NOTE: Instead of .c files, C++ uses .cc files
// NOTE: (In some circles, .cpp and .hpp are used, but we are following Google conventions)
//   However, .h extensions are not specified for C++ standard libraries

// iostream: basic io streaming operations (cin, cout, etc.)
#include <iostream>
// string: true string type
#include <string>
// sstream: stringstream, which converts strings to streams
#include <sstream>
// fstream: filestream, read and write files easily as streams
#include <fstream>

// Just like Python, C++ uses namespaces to organize symbols into logical
// groupings, which helps keep things tidy
// Unlike Python, C++ uses the symbol :: to look inside a namespace
// (Python uses the . symbol, just like for a C/C++ struct)
namespace foo
{
    // std:: denotes the "standard namespace"
    // cout takes a string as a stream and prints it to stdout
    // endl is the cross-platform stream version of an end-of-line character \n
    void print() { std::cout << "This is printing from foo." << std::endl; }
}

// Multiple namespaces may be defined easily
namespace bar
{
    // This is bar::print, which is distinct from foo::print above
    void print() { std::cout << "This is printing from bar." << std::endl; }
}

// Exactly like C, a C++ program must have a main function with arguments:
//   argc : int count of commandline arguments
//   argv : array of C-strings, meaning a pointer to an array of char pointers
int main(int argc, char **argv)
{
    // specify that everything in the namespace std should
    // become available in the local scope for convenience
    // NOTE: This is forbidden the Google style guide, but is included here
    //       for completeness - generally don't do this to keep namespaces clear
    using namespace std;

    // Example of command line usage
    if ( argc != 2 )
    {
        // The stream operator << automatically converts types
        // so here the C-string (char *) of argv[0] is converted to a
        // true C++ string, then passed as a stream to cout
        //
        // Note : the std prefix is not needed due to the "using" call above
        cout << "Usage: " << argv[0] << " arg1" << endl;
        return 1;
    }
    cout << "arg1 = " << argv[1] << endl;

    // Functions within distinct namespaces can be called directly
    foo::print();
    bar::print();

    // specify that print from foo:: should be pulled into local scope
    using foo::print;

    // demonstration that the foo:: prefix is no longer needed
    print();

    // define true string variable to hold input
    string input_str;

    // define float and int types to hold parsed input
    float fnum=0;
    int   inum=0;

    // Ask for input from user as a string
    cout << "Enter a float: ";

    // get entire line until a carriage return
    getline(cin, input_str);

    // use streams to parse the string input as different types
    stringstream(input_str) >> fnum;
    stringstream(input_str) >> inum;

    // show result of parsed input
    cout << "Input as a float: " << fnum << endl;
    cout << "Input as an int : " << inum << endl;

    // file handle
    ofstream output_file;

    // open a file
    output_file.open("output_file.txt");

    // check that file opened successfully
    if ( !output_file.is_open() )
    {
        // Print error to standard error (not standard out)
        cerr << "Error: Could not open file" << endl;
    }
    else
    {
        // write to file as a stream
        output_file << "This is the first line of the file." << endl;
        output_file << "Input as a float: " << fnum << '\t'; // \t = tab character
        output_file << "Input as an int : " << inum << endl;
        // explicitly close the file
        // (the file is also closed automatically when the program terminates)
        output_file.close();
    }

    // (this is implicit if omitted)
    return 0;
}
<|endoftext|>


<commit_before>#include "test_utilities.hh"

#include <sstream>
#include <cassert>

double ramp(const lwt::Input& in, size_t pos, size_t n_entries) {
  double step = 2.0 / (n_entries - 1);
  double x = ( (n_entries == 1) ? 0 : (-1 + pos * step) );
  return x / in.scale - in.offset;
}

// 2d ramp function, see declaration above
double ramp(const lwt::Input& in, size_t x, size_t y,
            size_t n_x, size_t n_y) {
  assert(x < n_x);
  assert(y < n_y);
  double s_x = 2.0 / (n_x - 1);
  double s_y = 2.0 / (n_y - 1);
  double x_m = ( (n_x == 1) ? 0 : (-1.0 + x * s_x) );
  double y_m = ( (n_y == 1) ? 0 : (-1.0 + y * s_y) );
  return x_m * y_m / in.scale - in.offset;
}

lwt::VectorMap get_values_vec(const std::vector<lwt::Input>& inputs,
                              size_t n_patterns) {
  lwt::VectorMap out;

  // ramp through the input multiplier
  const size_t total_inputs = inputs.size();
  for (size_t nnn = 0; nnn < total_inputs; nnn++) {
    const auto& input = inputs.at(nnn);
    out[input.name] = {};
    for (size_t jjj = 0; jjj < n_patterns; jjj++) {
      double ramp_val = ramp(input, nnn, jjj, total_inputs, n_patterns);
      out.at(input.name).push_back(ramp_val);
    }
  }
  return out;
}

std::vector<std::string> parse_line(std::string& line) {
  std::stringstream          line_stream(line);
  std::string                cell;

  std::vector<std::string>   result;
  while(line_stream >> cell) {
    result.push_back(cell);
  }
  return result;
}
<commit_msg>Fix for tests when input node has one value<commit_after>#include "test_utilities.hh"

#include <sstream>
#include <cassert>

double ramp(const lwt::Input& in, size_t pos, size_t n_entries) {
  double step = 2.0 / (n_entries - 1);
  double x = ( (n_entries == 1) ? -1 : (-1 + pos * step) );
  return x / in.scale - in.offset;
}

// 2d ramp function, see declaration above
double ramp(const lwt::Input& in, size_t x, size_t y,
            size_t n_x, size_t n_y) {
  assert(x < n_x);
  assert(y < n_y);
  double s_x = 2.0 / (n_x - 1);
  double s_y = 2.0 / (n_y - 1);
  double x_m = ( (n_x == 1) ? 0 : (-1.0 + x * s_x) );
  double y_m = ( (n_y == 1) ? 0 : (-1.0 + y * s_y) );
  return x_m * y_m / in.scale - in.offset;
}

lwt::VectorMap get_values_vec(const std::vector<lwt::Input>& inputs,
                              size_t n_patterns) {
  lwt::VectorMap out;

  // ramp through the input multiplier
  const size_t total_inputs = inputs.size();
  for (size_t nnn = 0; nnn < total_inputs; nnn++) {
    const auto& input = inputs.at(nnn);
    out[input.name] = {};
    for (size_t jjj = 0; jjj < n_patterns; jjj++) {
      double ramp_val = ramp(input, nnn, jjj, total_inputs, n_patterns);
      out.at(input.name).push_back(ramp_val);
    }
  }
  return out;
}

std::vector<std::string> parse_line(std::string& line) {
  std::stringstream          line_stream(line);
  std::string                cell;

  std::vector<std::string>   result;
  while(line_stream >> cell) {
    result.push_back(cell);
  }
  return result;
}
<|endoftext|>