<commit_before>/*
 * ============================================================================
 *
 *       Filename:  trimmit.cc
 *    Description:  Just merges and quality trims interleaved reads.
 *        License:  LGPL-3+
 *         Author:  Kevin Murray, spam@kdmurray.id.au
 *
 * ============================================================================
 *
 * Copyright 2015- Kevin Murray <spam@kdmurray.id.au>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <iostream>
#include <fstream>
#include <string>
#include <chrono>
#include <iomanip>

#include <getopt.h>

#include "qcpp.hh"

#include "qc-measure.hh"
#include "qc-length.hh"
#include "qc-qualtrim.hh"
#include "qc-gbs.hh"
#include "qc-adaptor.hh"

using std::chrono::system_clock;

inline void
progress(size_t n, system_clock::time_point start)
{
    std::chrono::duration<double> tdiff = system_clock::now() - start;
    double secs = tdiff.count();
    double k_reads = n / 1000.0;
    double rate = k_reads / secs;
    std::cerr << "\33[2K" << "Kept " << std::setprecision(3) << k_reads
              << "K read pairs in " << (int)secs << "s (" << (int)rate
              << "K RP/sec)\r";
}

int
usage_err()
{
    using std::cerr;
    using std::endl;
    cerr << "USAGE: trimit [options] <read_file>" << endl
         << endl;
    cerr << "OPTIONS:" << endl;
    cerr << " -q QUALITY  Minimum acceptable PHRED score. [default: 25]" << endl;
    cerr << " -l LENGTH   Remove reads less than LEN bases long [default: off]" << endl;
    cerr << " -L LENGTH   Truncate read to length LEN [default: off]" << endl;
    cerr << " -y YAML     YAML report file. [default: none]" << endl;
    cerr << " -o OUTPUT   Output file. [default: stdout]" << endl;
    cerr << " -s          Single ended mode (no trim-merge). [default: false]" << endl;
    cerr << " -b          Use broken-paired output (don't keep read pairing) [default: false]" << endl;
    cerr << " -h          Show this help message." << endl;
    cerr << endl;
    cerr << "By default good reads are printed to stdout." <<  endl;
    return EXIT_FAILURE;
}

const char *cli_opts = "q:y:o:l:bsh";

int
main (int argc, char *argv[])
{
    using namespace qcpp;

    std::string             yaml_fname;
    bool                    broken_paired = false;
    bool                    single_end = false;
    std::ofstream           read_output;
    std::string             outfile = "/dev/stdout";
    std::string             infile = "";
    size_t                  truncate_length = 0;
    size_t                  filter_length = 0;
    int                     qual_threshold = 25;

    std::cerr << argv[0] << " version " << QCPP_VERSION
                          << std::endl << std::endl;
    int c = 0;
    while ((c = getopt(argc, argv, cli_opts)) > 0) {
        switch (c) {
            case 'y':
                yaml_fname = optarg;
                break;
            case 'o':
                outfile = optarg;
                break;
            case 'b':
                broken_paired = true;
                break;
            case 's':
                single_end = true;
                break;
            case 'q':
                qual_threshold = atoi(optarg);
                break;
            case 'L':
                truncate_length = atoi(optarg);
                break;
            case 'l':
                filter_length = atoi(optarg);
                break;
            case 'h':
                usage_err();
                return EXIT_SUCCESS;
            default:
                std::cerr << "Bad arg '" << std::string(1, optopt) << "'"
                          << std::endl << std::endl;
                return usage_err();
        }
    }

    if (optind == argc) {
        std::cerr << "Must give input file!" << std::endl << std::endl;
        usage_err();
        return EXIT_SUCCESS;
    }

    infile = argv[optind];
    if (infile == "-") infile = "/dev/stdin";
    read_output.open(outfile);

    ProcessedReadStream     stream;
    uint64_t                n_pairs = 0;
    bool                    measure_qual = yaml_fname.size() > 0;

    if (measure_qual) {
        stream.append_processor<PerBaseQuality>("before qc");
    }
    if (!single_end) {
        stream.append_processor<AdaptorTrimPE>("trim or merge reads", 10);
    }
    stream.append_processor<WindowedQualTrim>("QC", SangerEncoding, qual_threshold, 1);
    if (truncate_length > 0) {
        stream.append_processor<ReadTruncator>("Fix Length", SangerEncoding,
                                               truncate_length);
    }
    if (filter_length > 0) {
        stream.append_processor<ReadLenFilter>("Length Filter", filter_length);
    }
    if (measure_qual) {
        stream.append_processor<PerBaseQuality>("after qc");
    }

    try {
        stream.open(infile);
    } catch (qcpp::IOError  &e) {
        std::cerr << "Error opening input file:" << std::endl;
        std::cerr << e.what() << std::endl;
        return EXIT_FAILURE;
    }
    system_clock::time_point start = system_clock::now();
    if (single_end) {
        Read rd;
        while (stream.parse_read(rd)) {
            read_output << rd.str();
            if (n_pairs % 10000 == 0) {
                progress(n_pairs, start);
            }
            n_pairs++;
        }
    } else {
        ReadPair rp;
        while (stream.parse_read_pair(rp)) {
            std::string rp_str = "";

            if (broken_paired) {
                if (rp.first.size() >= 64) {
                    rp_str = rp.first.str();
                }
                if (rp.second.size() >= 64) {
                    rp_str += rp.second.str();
                }
            } else {
                rp_str = rp.str();
            }

            if (n_pairs % 10000 == 0) {
                progress(n_pairs, start);
            }
            n_pairs++;

            read_output << rp_str;
        }
    }
    progress(n_pairs, start);
    std::cerr << std::endl;
    if (yaml_fname.size() > 0) {
        std::ofstream yml_output(yaml_fname);
        yml_output << stream.report();
    }
    return EXIT_SUCCESS;
}
<commit_msg>Add -Q quiet flag to trimit<commit_after>/*
 * ============================================================================
 *
 *       Filename:  trimmit.cc
 *    Description:  Just merges and quality trims interleaved reads.
 *        License:  LGPL-3+
 *         Author:  Kevin Murray, spam@kdmurray.id.au
 *
 * ============================================================================
 *
 * Copyright 2015- Kevin Murray <spam@kdmurray.id.au>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <iostream>
#include <fstream>
#include <string>
#include <chrono>
#include <iomanip>

#include <getopt.h>

#include "qcpp.hh"

#include "qc-measure.hh"
#include "qc-length.hh"
#include "qc-qualtrim.hh"
#include "qc-gbs.hh"
#include "qc-adaptor.hh"

using std::chrono::system_clock;

inline void
progress(size_t n, system_clock::time_point start)
{
    std::chrono::duration<double> tdiff = system_clock::now() - start;
    double secs = tdiff.count();
    double k_reads = n / 1000.0;
    double rate = k_reads / secs;
    std::cerr << "\33[2K" << "Kept " << std::setprecision(3) << k_reads
              << "K read pairs in " << (int)secs << "s (" << (int)rate
              << "K RP/sec)\r";
}

int
usage_err()
{
    using std::cerr;
    using std::endl;
    cerr << "USAGE: trimit [options] <read_file>" << endl
         << endl;
    cerr << "OPTIONS:" << endl;
    cerr << " -q QUALITY  Minimum acceptable PHRED score. [default: 25]" << endl;
    cerr << " -l LENGTH   Remove reads less than LEN bases long [default: off]" << endl;
    cerr << " -L LENGTH   Truncate read to length LEN [default: off]" << endl;
    cerr << " -y YAML     YAML report file. [default: none]" << endl;
    cerr << " -o OUTPUT   Output file. [default: stdout]" << endl;
    cerr << " -s          Single ended mode (no trim-merge). [default: false]" << endl;
    cerr << " -b          Use broken-paired output (don't keep read pairing) [default: false]" << endl;
    cerr << " -Q          Quiet mode, does not log progress [default: log progress to stderr]" << endl;
    cerr << " -h          Show this help message." << endl;
    cerr << endl;
    cerr << "By default good reads are printed to stdout." <<  endl;
    return EXIT_FAILURE;
}

const char *cli_opts = "q:y:o:l:L:bshQ";

int
main (int argc, char *argv[])
{
    using namespace qcpp;

    std::string             yaml_fname;
    bool                    broken_paired = false;
    bool                    single_end = false;
    bool                    quiet = false;
    std::ofstream           read_output;
    std::string             outfile = "/dev/stdout";
    std::string             infile = "";
    size_t                  truncate_length = 0;
    size_t                  filter_length = 0;
    int                     qual_threshold = 25;

    std::cerr << argv[0] << " version " << QCPP_VERSION
                          << std::endl << std::endl;
    int c = 0;
    while ((c = getopt(argc, argv, cli_opts)) > 0) {
        switch (c) {
            case 'y':
                yaml_fname = optarg;
                break;
            case 'o':
                outfile = optarg;
                break;
            case 'b':
                broken_paired = true;
                break;
            case 's':
                single_end = true;
                break;
            case 'Q':
                quiet = true;
                break;
            case 'q':
                qual_threshold = atoi(optarg);
                break;
            case 'L':
                truncate_length = atoi(optarg);
                break;
            case 'l':
                filter_length = atoi(optarg);
                break;
            case 'h':
                usage_err();
                return EXIT_SUCCESS;
            default:
                std::cerr << "Bad arg '" << std::string(1, optopt) << "'"
                          << std::endl << std::endl;
                return usage_err();
        }
    }

    if (optind == argc) {
        std::cerr << "Must give input file!" << std::endl << std::endl;
        usage_err();
        return EXIT_SUCCESS;
    }

    infile = argv[optind];
    if (infile == "-") infile = "/dev/stdin";
    read_output.open(outfile);

    ProcessedReadStream     stream;
    uint64_t                n_pairs = 0;
    bool                    measure_qual = yaml_fname.size() > 0;

    if (measure_qual) {
        stream.append_processor<PerBaseQuality>("before qc");
    }
    if (!single_end) {
        stream.append_processor<AdaptorTrimPE>("trim or merge reads", 10);
    }
    stream.append_processor<WindowedQualTrim>("QC", SangerEncoding, qual_threshold, 1);
    if (truncate_length > 0) {
        stream.append_processor<ReadTruncator>("Fix Length", SangerEncoding,
                                               truncate_length);
    }
    if (filter_length > 0) {
        stream.append_processor<ReadLenFilter>("Length Filter", filter_length);
    }
    if (measure_qual) {
        stream.append_processor<PerBaseQuality>("after qc");
    }

    try {
        stream.open(infile);
    } catch (qcpp::IOError  &e) {
        std::cerr << "Error opening input file:" << std::endl;
        std::cerr << e.what() << std::endl;
        return EXIT_FAILURE;
    }
    system_clock::time_point start = system_clock::now();
    if (single_end) {
        Read rd;
        while (stream.parse_read(rd)) {
            read_output << rd.str();
            if (!quiet && n_pairs % 10000 == 0) {
                progress(n_pairs, start);
            }
            n_pairs++;
        }
    } else {
        ReadPair rp;
        while (stream.parse_read_pair(rp)) {
            std::string rp_str = "";

            if (broken_paired) {
                if (rp.first.size() >= 64) {
                    rp_str = rp.first.str();
                }
                if (rp.second.size() >= 64) {
                    rp_str += rp.second.str();
                }
            } else {
                rp_str = rp.str();
            }

            if (!quiet && n_pairs % 10000 == 0) {
                progress(n_pairs, start);
            }
            n_pairs++;

            read_output << rp_str;
        }
    }
    progress(n_pairs, start);
    std::cerr << std::endl;
    if (yaml_fname.size() > 0) {
        std::ofstream yml_output(yaml_fname);
        yml_output << stream.report();
    }
    return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2015 - The CM Authors <legal@clickmatcher.com>
 *   All Rights Reserved.
 *
 * This file is CONFIDENTIAL -- Distribution or duplication of this material or
 * the information contained herein is strictly forbidden unless prior written
 * permission is obtained.
 */
#include <algorithm>
#include <unistd.h>
#include <fnord-base/UTF8.h>
#include "common.h"

namespace cm {

/**
 * mandatory params:
 *  v    -- pixel ver.  -- value: 1
 *  c    -- clickid     -- format "<uid>~<eventid>", e.g. "f97650cb~b28c61d5c"
 *  e    -- eventtype   -- format "{q,v}" (query, visit)
 *
 * params for eventtype=q (query):
 *  is   -- item ids    -- format "<setid>~<itemid>~<pos>,..."
 *
 * params for eventtype=v (visit):
 *  i    -- itemid      -- format "<setid>~<itemid>"
 *
 */
bool isReservedPixelParam(const std::string p) {
  return p == "c" || p == "e" || p == "i" || p == "is" || p == "v";
}

std::string cmHostname() {
  char hostname[128];
  gethostname(hostname, sizeof(hostname));
  hostname[127] = 0;
  return std::string(hostname);
}

Option<String> extractAttr(const Vector<String>& attrs, const String& attr) {
  auto prefix = attr + ":";

  for (const auto& a : attrs) {
    if (StringUtil::beginsWith(a, prefix)) {
      return Some(a.substr(prefix.length()));
    }
  }

  return None<String>();
}

String joinBagOfWords(const Set<String>& words) {
  Vector<String> v;

  for (const auto& w : words) {
    if (w.length() == 0) {
      continue;
    }

    v.emplace_back(w);
  }

  std::sort(v.begin(), v.end());

  return StringUtil::join(v, " ");
}

bool isItemEligible(
    ItemEligibility eligibility,
    const cm::JoinedQuery& query,
    const cm::JoinedQueryItem& item) {
  if (eligibility == ItemEligibility::DAWANDA_FIRST_EIGHT) {
    if (item.position < 5 || item.position > 12) {
      return false;
    }
  }

  return true;
}

}
<commit_msg>only consider qcat2 for now<commit_after>/**
 * Copyright (c) 2015 - The CM Authors <legal@clickmatcher.com>
 *   All Rights Reserved.
 *
 * This file is CONFIDENTIAL -- Distribution or duplication of this material or
 * the information contained herein is strictly forbidden unless prior written
 * permission is obtained.
 */
#include <algorithm>
#include <unistd.h>
#include <fnord-base/UTF8.h>
#include "common.h"

namespace cm {

/**
 * mandatory params:
 *  v    -- pixel ver.  -- value: 1
 *  c    -- clickid     -- format "<uid>~<eventid>", e.g. "f97650cb~b28c61d5c"
 *  e    -- eventtype   -- format "{q,v}" (query, visit)
 *
 * params for eventtype=q (query):
 *  is   -- item ids    -- format "<setid>~<itemid>~<pos>,..."
 *
 * params for eventtype=v (visit):
 *  i    -- itemid      -- format "<setid>~<itemid>"
 *
 */
bool isReservedPixelParam(const std::string p) {
  return p == "c" || p == "e" || p == "i" || p == "is" || p == "v";
}

std::string cmHostname() {
  char hostname[128];
  gethostname(hostname, sizeof(hostname));
  hostname[127] = 0;
  return std::string(hostname);
}

Option<String> extractAttr(const Vector<String>& attrs, const String& attr) {
  auto prefix = attr + ":";

  for (const auto& a : attrs) {
    if (StringUtil::beginsWith(a, prefix)) {
      return Some(a.substr(prefix.length()));
    }
  }

  return None<String>();
}

String joinBagOfWords(const Set<String>& words) {
  Vector<String> v;

  for (const auto& w : words) {
    if (w.length() == 0) {
      continue;
    }

    v.emplace_back(w);
  }

  std::sort(v.begin(), v.end());

  return StringUtil::join(v, " ");
}

bool isItemEligible(
    ItemEligibility eligibility,
    const cm::JoinedQuery& query,
    const cm::JoinedQueryItem& item) {
  if (extractAttr(query.attrs, "q_cat2").isEmpty()) {
    return false;
  }

  if (eligibility == ItemEligibility::DAWANDA_FIRST_EIGHT) {
    if (item.position < 5 || item.position > 12) {
      return false;
    }
  }

  return true;
}

}
<|endoftext|>


<commit_before>/*
This file is part of the ORK library.
Full copyright and license terms can be found in the LICENSE.txt file.
*/
#include"ork/geometry.hpp"
#include"ork/xml.hpp"

#if ORK_USE_PUGI
#include"pugixml.hpp"
#endif

namespace ork {
namespace xml {

#if ORK_USE_PUGI
void export_file(const string&filename, const exportable&object, const string&root_node_name) {
	pugi::xml_document doc;
	object.export_xml(doc.append_child(root_node_name.c_str()));
	doc.save_file(filename.c_str());
}
void load_and_parse(pugi::xml_document&xml, i_stream&fin) {
	pugi::xml_parse_result result = xml.load(fin);
	if(!result) {
		ORK_THROW(ORK("XML parse error") \
			<< ORK("\n -- Error: ") << result.description() \
			<< ORK("\n -- Offset: ") << result.offset)//<< ORK(" at [") << (source + result.offset) << ORK("]"))
	}
	else {
		ORK_LOG(ork::severity_level::trace) << ORK("XML parse success");
	}
}
#endif

double&vector::x() {
	return _data.x;
}
const double&vector::x()const {
	return _data.x;
}

double&vector::y() {
	return _data.y;
}
const double&vector::y()const {
	return _data.y;
}

double&vector::z() {
	return _data.z;
}
const double&vector::z()const {
	return _data.z;
}

glm::dvec3&vector::get() {
	return _data;
}
const glm::dvec3&vector::get()const {
	return _data;
}

string vector::as_string() const {
	string_stream stream;
	stream << ORK("(") << to_dimension(_data.x)
		<< ORK(", ") << to_dimension(_data.y)
		<< ORK(", ") << to_dimension(_data.z) << ORK(")");
	return stream.str();
}

bool vector::operator == (const vector &other) const {
	static const double tolerance = 0.0001;//TODO: This is problematic, given lack of units (e.g. meters)

	if(std::abs(_data.x - other._data.x) > tolerance) return false;
	if(std::abs(_data.y - other._data.y) > tolerance) return false;
	if(std::abs(_data.z - other._data.z) > tolerance) return false;
	return true;
}

#if ORK_USE_PUGI
vector::vector(pugi::xml_node &node) {
	_data.x = node.attribute(ORK("x")).as_double();
	_data.y = node.attribute(ORK("y")).as_double();
	_data.z = node.attribute(ORK("z")).as_double();
}
void vector::export_xml(pugi::xml_node &node) const {
	node.append_attribute(ORK("x"));
	node.attribute(ORK("x")).set_value(to_dimension(_data.x).c_str());

	node.append_attribute(ORK("y"));
	node.attribute(ORK("y")).set_value(to_dimension(_data.y).c_str());

	node.append_attribute(ORK("z"));
	node.attribute(ORK("z")).set_value(to_dimension(_data.z).c_str());
}
#endif

}//namespace xml
}//namespace ork
<commit_msg>xml::export_file now creates the directory<commit_after>/*
This file is part of the ORK library.
Full copyright and license terms can be found in the LICENSE.txt file.
*/
#include"ork/geometry.hpp"
#include"ork/xml.hpp"

#if ORK_USE_PUGI
#include"pugixml.hpp"
#endif

namespace ork {
namespace xml {

#if ORK_USE_PUGI
void export_file(const string&filename, const exportable&object, const string&root_node_name) {
	pugi::xml_document doc;
	object.export_xml(doc.append_child(root_node_name.c_str()));
	ork::ensure_directory(filename);
	doc.save_file(filename.c_str());
}
void load_and_parse(pugi::xml_document&xml, i_stream&fin) {
	pugi::xml_parse_result result = xml.load(fin);
	if(!result) {
		ORK_THROW(ORK("XML parse error") \
			<< ORK("\n -- Error: ") << result.description() \
			<< ORK("\n -- Offset: ") << result.offset)//<< ORK(" at [") << (source + result.offset) << ORK("]"))
	}
	else {
		ORK_LOG(ork::severity_level::trace) << ORK("XML parse success");
	}
}
#endif

double&vector::x() {
	return _data.x;
}
const double&vector::x()const {
	return _data.x;
}

double&vector::y() {
	return _data.y;
}
const double&vector::y()const {
	return _data.y;
}

double&vector::z() {
	return _data.z;
}
const double&vector::z()const {
	return _data.z;
}

glm::dvec3&vector::get() {
	return _data;
}
const glm::dvec3&vector::get()const {
	return _data;
}

string vector::as_string() const {
	string_stream stream;
	stream << ORK("(") << to_dimension(_data.x)
		<< ORK(", ") << to_dimension(_data.y)
		<< ORK(", ") << to_dimension(_data.z) << ORK(")");
	return stream.str();
}

bool vector::operator == (const vector &other) const {
	static const double tolerance = 0.0001;//TODO: This is problematic, given lack of units (e.g. meters)

	if(std::abs(_data.x - other._data.x) > tolerance) return false;
	if(std::abs(_data.y - other._data.y) > tolerance) return false;
	if(std::abs(_data.z - other._data.z) > tolerance) return false;
	return true;
}

#if ORK_USE_PUGI
vector::vector(pugi::xml_node &node) {
	_data.x = node.attribute(ORK("x")).as_double();
	_data.y = node.attribute(ORK("y")).as_double();
	_data.z = node.attribute(ORK("z")).as_double();
}
void vector::export_xml(pugi::xml_node &node) const {
	node.append_attribute(ORK("x"));
	node.attribute(ORK("x")).set_value(to_dimension(_data.x).c_str());

	node.append_attribute(ORK("y"));
	node.attribute(ORK("y")).set_value(to_dimension(_data.y).c_str());

	node.append_attribute(ORK("z"));
	node.attribute(ORK("z")).set_value(to_dimension(_data.z).c_str());
}
#endif

}//namespace xml
}//namespace ork
<|endoftext|>


<commit_before>/** \file   log_rotate.cc
 *  \author Dr. Johannes Ruscheinski (johannes.ruscheinski@uni-tuebingen.de)
 *
 *  \copyright 2017 Universitätsbibliothek Tübingen.  All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <iostream>
#include <stdexcept>
#include <cstdlib>
#include <cstring>
#include "FileUtil.h"
#include "MiscUtil.h"
#include "RegexMatcher.h"
#include "StringUtil.h"
#include "util.h"

const unsigned DEFAULT_MAX_ROTATIONS(5);

void Usage() {
    std::cerr << "Usage: " << ::progname
              << " [--max-rotations=max_rotations|--no-of-lines-to-keep=max_line_count] directory file_regex\n"
              << "       where the default for \"max_rotations\" is " << DEFAULT_MAX_ROTATIONS << '\n'
              << "       and \"file_regex\" must be a PCRE.  (There is no default for \"max_line_count\".)\n"
              << "       When using --no-of-lines-to-keep, the result will be either empty, if the original\n"
              << "       was empty, or the file will end in a newline even if it originally didn't.\n\n";
    std::exit(EXIT_FAILURE);
}

void SkipLines(File * const input, unsigned skip_count) {
    while (skip_count > 0) {
        std::string line;
        input->getline(&line);
        --skip_count;
    }
}

void CopyLines(File * const input, File * const output) {
    while (not input->eof()) {
        std::string line;
        input->getline(&line);
        if (unlikely(not output->write(line + "\n")))
            Error("in CopyLines: failed to write a line to \"" + output->getPath() + "\"!");
    }
}

// Keeps the last \"max_line_count\" number of lines in \"filename\".
void KeepLines(const std::string &filename, const unsigned &max_line_count) {
    const size_t original_line_count(FileUtil::CountLines(filename));
    if (original_line_count <= max_line_count)
        return;

    std::unique_ptr<File> input(FileUtil::OpenInputFileOrDie(filename));
    SkipLines(input.get(), original_line_count - max_line_count);

    FileUtil::AutoTempFile temp_file;
    std::unique_ptr<File> output(FileUtil::OpenOutputFileOrDie(temp_file.getFilePath()));
    CopyLines(input.get(), output.get());
    input->close(), output->close();
    if (not FileUtil::RenameFile(temp_file.getFilePath(), filename, /* remove_target = */ true))
        Error("in KeepLines: failed to rename \"" + temp_file.getFilePath() + "\" to \"" + filename + "\"!");
}

inline bool HasNumericExtension(const std::string &filename) {
    static RegexMatcher * const matcher(RegexMatcher::RegexMatcherFactory("\\.[0-9]+$"));
    return matcher->matched(filename);
}

int main(int argc, char *argv[]) {
    ::progname = argv[0];

    if (argc != 3 and argc != 4)
        Usage();

    unsigned max_rotations(DEFAULT_MAX_ROTATIONS), max_line_count(0);
    std::string directory_path, file_regex;
    if (argc == 3) {
        directory_path = argv[1];
        file_regex     = argv[2];
    } else { // argc == 4.
        if (StringUtil::StartsWith(argv[1], "--max-rotations=")) {
            if (StringUtil::ToUnsigned(argv[1] + std::strlen("--max-rotations="), &max_rotations)
                or max_rotations == 0)
                Error("\"" + std::string(argv[1] + std::strlen("--max-rotations="))
                      + "\" is not a valid maximum rotation count!");
        } else if (StringUtil::StartsWith(argv[1], "--no-of-lines-to-keep=")) {
            if (not StringUtil::ToUnsigned(argv[1] + std::strlen("--no-of-lines-to-keep="), &max_line_count)
                or max_line_count == 0)
                Error("\"" + std::string(argv[1] + std::strlen("--no-of-lines-to-keep="))
                      + "\" is not a valid line count!");
        } else
            Usage();
        directory_path = argv[2];
        file_regex     = argv[3];
    }

    try {
        FileUtil::Directory directory(directory_path, file_regex);
        for (const auto &entry : directory) {
            if (not HasNumericExtension(entry.getName())) {
                if (max_line_count > 0)
                    KeepLines(directory_path + "/" + entry.getName(), max_line_count);
                else
                    MiscUtil::LogRotate(entry.getName(), max_rotations);
            }
        }
    } catch (const std::exception &x) {
        Error("caught exception: " + std::string(x.what()));
    }
}
<commit_msg>Fixed an argument-processing bug.<commit_after>/** \file   log_rotate.cc
 *  \author Dr. Johannes Ruscheinski (johannes.ruscheinski@uni-tuebingen.de)
 *
 *  \copyright 2017 Universitätsbibliothek Tübingen.  All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <iostream>
#include <stdexcept>
#include <cstdlib>
#include <cstring>
#include "FileUtil.h"
#include "MiscUtil.h"
#include "RegexMatcher.h"
#include "StringUtil.h"
#include "util.h"

const unsigned DEFAULT_MAX_ROTATIONS(5);

void Usage() {
    std::cerr << "Usage: " << ::progname
              << " [--max-rotations=max_rotations|--no-of-lines-to-keep=max_line_count] directory file_regex\n"
              << "       where the default for \"max_rotations\" is " << DEFAULT_MAX_ROTATIONS << '\n'
              << "       and \"file_regex\" must be a PCRE.  (There is no default for \"max_line_count\".)\n"
              << "       When using --no-of-lines-to-keep, the result will be either empty, if the original\n"
              << "       was empty, or the file will end in a newline even if it originally didn't.\n\n";
    std::exit(EXIT_FAILURE);
}

void SkipLines(File * const input, unsigned skip_count) {
    while (skip_count > 0) {
        std::string line;
        input->getline(&line);
        --skip_count;
    }
}

void CopyLines(File * const input, File * const output) {
    while (not input->eof()) {
        std::string line;
        input->getline(&line);
        if (unlikely(not output->write(line + "\n")))
            Error("in CopyLines: failed to write a line to \"" + output->getPath() + "\"!");
    }
}

// Keeps the last \"max_line_count\" number of lines in \"filename\".
void KeepLines(const std::string &filename, const unsigned &max_line_count) {
    const size_t original_line_count(FileUtil::CountLines(filename));
    if (original_line_count <= max_line_count)
        return;

    std::unique_ptr<File> input(FileUtil::OpenInputFileOrDie(filename));
    SkipLines(input.get(), original_line_count - max_line_count);

    FileUtil::AutoTempFile temp_file;
    std::unique_ptr<File> output(FileUtil::OpenOutputFileOrDie(temp_file.getFilePath()));
    CopyLines(input.get(), output.get());
    input->close(), output->close();
    if (not FileUtil::RenameFile(temp_file.getFilePath(), filename, /* remove_target = */ true))
        Error("in KeepLines: failed to rename \"" + temp_file.getFilePath() + "\" to \"" + filename + "\"!");
}

inline bool HasNumericExtension(const std::string &filename) {
    static RegexMatcher * const matcher(RegexMatcher::RegexMatcherFactory("\\.[0-9]+$"));
    return matcher->matched(filename);
}

int main(int argc, char *argv[]) {
    ::progname = argv[0];

    if (argc != 3 and argc != 4)
        Usage();

    unsigned max_rotations(DEFAULT_MAX_ROTATIONS), max_line_count(0);
    std::string directory_path, file_regex;
    if (argc == 3) {
        directory_path = argv[1];
        file_regex     = argv[2];
    } else { // argc == 4.
        if (StringUtil::StartsWith(argv[1], "--max-rotations=")) {
            if (not StringUtil::ToUnsigned(argv[1] + std::strlen("--max-rotations="), &max_rotations)
                or max_rotations == 0)
                Error("\"" + std::string(argv[1] + std::strlen("--max-rotations="))
                      + "\" is not a valid maximum rotation count!");
        } else if (StringUtil::StartsWith(argv[1], "--no-of-lines-to-keep=")) {
            if (not StringUtil::ToUnsigned(argv[1] + std::strlen("--no-of-lines-to-keep="), &max_line_count)
                or max_line_count == 0)
                Error("\"" + std::string(argv[1] + std::strlen("--no-of-lines-to-keep="))
                      + "\" is not a valid line count!");
        } else
            Usage();
        directory_path = argv[2];
        file_regex     = argv[3];
    }

    try {
        FileUtil::Directory directory(directory_path, file_regex);
        for (const auto &entry : directory) {
            if (not HasNumericExtension(entry.getName())) {
                if (max_line_count > 0)
                    KeepLines(directory_path + "/" + entry.getName(), max_line_count);
                else
                    MiscUtil::LogRotate(entry.getName(), max_rotations);
            }
        }
    } catch (const std::exception &x) {
        Error("caught exception: " + std::string(x.what()));
    }
}
<|endoftext|>


<commit_before>#define _BSD_SOURCE

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/ptrace.h>
#include <sys/resource.h>
#include <sys/wait.h>
#include <unistd.h>
#include "ptbox.h"

pt_process *pt_alloc_process(pt_debugger *debugger) {
    return new pt_process(debugger);
}

void pt_free_process(pt_process *process) {
    delete process;
}

pt_process::pt_process(pt_debugger *debugger) :
    pid(0), callback(NULL), context(NULL), debugger(debugger),
    event_proc(NULL), event_context(NULL)
{
    memset(&exec_time, 0, sizeof exec_time);
    memset(handler, 0, sizeof handler);
    debugger->set_process(this);
}

void pt_process::set_callback(pt_handler_callback callback, void *context) {
    this->callback = callback;
    this->context = context;
}

void pt_process::set_event_proc(pt_event_callback callback, void *context) {
    this->event_proc = callback;
    this->event_context = context;
}

int pt_process::set_handler(int syscall, int handler) {
    if (syscall >= MAX_SYSCALL || syscall < 0)
        return 1;
    this->handler[syscall] = handler;
    return 0;
}

int pt_process::dispatch(int event, unsigned long param) {
    if (event_proc != NULL)
        return event_proc(event_context, event, param);
    return -1;
}

int pt_process::spawn(pt_fork_handler child, void *context) {
    pid_t pid = fork();
    if (pid == -1)
        return 1;
    if (pid == 0)
        _exit(child(context));
    this->pid = pid;
    debugger->new_process();
    return 0;
}

int pt_process::protection_fault(int syscall) {
    dispatch(PTBOX_EVENT_PROTECTION, syscall);
    dispatch(PTBOX_EVENT_EXITING, PTBOX_EXIT_PROTECTION);
    kill(pid, SIGKILL);
    return PTBOX_EXIT_PROTECTION;
}

int pt_process::monitor() {
    bool in_syscall = false, first = true, spawned = false;
    struct timespec start, end, delta;
    int status, exit_reason = PTBOX_EXIT_NORMAL;
    siginfo_t si;

    while (true) {
        clock_gettime(CLOCK_MONOTONIC, &start);
        wait4(pid, &status, 0, &_rusage);
        clock_gettime(CLOCK_MONOTONIC, &end);
        timespec_sub(&end, &start, &delta);
        timespec_add(&exec_time, &delta, &exec_time);

        if (WIFEXITED(status) || WIFSIGNALED(status))
            break;

        if (first) {
            dispatch(PTBOX_EVENT_ATTACH, 0);
            // This is right after SIGSTOP is received:
            ptrace(PTRACE_SETOPTIONS, pid, NULL, PTRACE_O_TRACESYSGOOD);
        }

        if (WIFSTOPPED(status)) {
            if (WSTOPSIG(status) == (0x80 | SIGTRAP)) {
                int syscall = debugger->syscall();
                in_syscall ^= true;
                //printf("%s syscall %d\n", in_syscall ? "Enter" : "Exit", syscall);

                if (!spawned) {
                    if (in_syscall && syscall == debugger->execve_syscall())
                        spawned = true;
                } else if (in_syscall) {
                    if (syscall < MAX_SYSCALL) {
                        switch (handler[syscall]) {
                            case PTBOX_HANDLER_ALLOW:
                                break;
                            case PTBOX_HANDLER_STDOUTERR: {
                                int arg0 = debugger->arg0();
                                if (arg0 != 1 && arg0 != 2)
                                    exit_reason = protection_fault(syscall);
                                break;
                            }
                            case PTBOX_HANDLER_CALLBACK:
                                if (callback(context, syscall))
                                    break;
                                //printf("Killed by callback: %d\n", syscall);
                                exit_reason = protection_fault(syscall);
                                continue;
                            default:
                                // Default is to kill, safety first.
                                //printf("Killed by DISALLOW or None: %d\n", syscall);
                                exit_reason = protection_fault(syscall);
                                continue;
                        }
                        if (debugger->is_exit(syscall))
                            dispatch(PTBOX_EVENT_EXITING, PTBOX_EXIT_NORMAL);
                    }
                } else if (debugger->on_return_callback) {
                    debugger->on_return_callback(debugger->on_return_context, syscall);
                    debugger->on_return_callback = NULL;
                    debugger->on_return_context = NULL;
                }
            } else {
                switch (WSTOPSIG(status)) {
                    case SIGSEGV:
                        dispatch(PTBOX_EVENT_EXITING, exit_reason = PTBOX_EXIT_SEGFAULT);
                        puts("Child Segfault");
                        kill(pid, SIGKILL);
                        break;
                    case SIGFPE:
                        puts("Child SIGFPE");
                        kill(pid, SIGKILL);
                        break;
                }
                dispatch(PTBOX_EVENT_SIGNAL, WSTOPSIG(status));
            }
        }
        ptrace(PTRACE_SYSCALL, pid, NULL, NULL);
        first = false;
    }
    dispatch(PTBOX_EVENT_EXITED, exit_reason);
    return WIFEXITED(status) ? WEXITSTATUS(status) : -WTERMSIG(status);
}
<commit_msg>Use PTRACE_EVENT_EXIT instead of sketchy is_exit syscall detection.<commit_after>#define _BSD_SOURCE

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/ptrace.h>
#include <sys/resource.h>
#include <sys/wait.h>
#include <unistd.h>
#include "ptbox.h"

pt_process *pt_alloc_process(pt_debugger *debugger) {
    return new pt_process(debugger);
}

void pt_free_process(pt_process *process) {
    delete process;
}

pt_process::pt_process(pt_debugger *debugger) :
    pid(0), callback(NULL), context(NULL), debugger(debugger),
    event_proc(NULL), event_context(NULL)
{
    memset(&exec_time, 0, sizeof exec_time);
    memset(handler, 0, sizeof handler);
    debugger->set_process(this);
}

void pt_process::set_callback(pt_handler_callback callback, void *context) {
    this->callback = callback;
    this->context = context;
}

void pt_process::set_event_proc(pt_event_callback callback, void *context) {
    this->event_proc = callback;
    this->event_context = context;
}

int pt_process::set_handler(int syscall, int handler) {
    if (syscall >= MAX_SYSCALL || syscall < 0)
        return 1;
    this->handler[syscall] = handler;
    return 0;
}

int pt_process::dispatch(int event, unsigned long param) {
    if (event_proc != NULL)
        return event_proc(event_context, event, param);
    return -1;
}

int pt_process::spawn(pt_fork_handler child, void *context) {
    pid_t pid = fork();
    if (pid == -1)
        return 1;
    if (pid == 0)
        _exit(child(context));
    this->pid = pid;
    debugger->new_process();
    return 0;
}

int pt_process::protection_fault(int syscall) {
    dispatch(PTBOX_EVENT_PROTECTION, syscall);
    dispatch(PTBOX_EVENT_EXITING, PTBOX_EXIT_PROTECTION);
    kill(pid, SIGKILL);
    return PTBOX_EXIT_PROTECTION;
}

int pt_process::monitor() {
    bool in_syscall = false, first = true, spawned = false;
    struct timespec start, end, delta;
    int status, exit_reason = PTBOX_EXIT_NORMAL;
    siginfo_t si;

    while (true) {
        clock_gettime(CLOCK_MONOTONIC, &start);
        wait4(pid, &status, 0, &_rusage);
        clock_gettime(CLOCK_MONOTONIC, &end);
        timespec_sub(&end, &start, &delta);
        timespec_add(&exec_time, &delta, &exec_time);

        if (WIFEXITED(status) || WIFSIGNALED(status))
            break;

        if (first) {
            dispatch(PTBOX_EVENT_ATTACH, 0);
            // This is right after SIGSTOP is received:
            ptrace(PTRACE_SETOPTIONS, pid, NULL, PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACEEXIT);
        }

        if (WIFSTOPPED(status)) {
            if (WSTOPSIG(status) == (0x80 | SIGTRAP)) {
                int syscall = debugger->syscall();
                in_syscall ^= true;
                //printf("%s syscall %d\n", in_syscall ? "Enter" : "Exit", syscall);

                if (!spawned) {
                    if (in_syscall && syscall == debugger->execve_syscall())
                        spawned = true;
                } else if (in_syscall) {
                    if (syscall < MAX_SYSCALL) {
                        switch (handler[syscall]) {
                            case PTBOX_HANDLER_ALLOW:
                                break;
                            case PTBOX_HANDLER_STDOUTERR: {
                                int arg0 = debugger->arg0();
                                if (arg0 != 1 && arg0 != 2)
                                    exit_reason = protection_fault(syscall);
                                break;
                            }
                            case PTBOX_HANDLER_CALLBACK:
                                if (callback(context, syscall))
                                    break;
                                //printf("Killed by callback: %d\n", syscall);
                                exit_reason = protection_fault(syscall);
                                continue;
                            default:
                                // Default is to kill, safety first.
                                //printf("Killed by DISALLOW or None: %d\n", syscall);
                                exit_reason = protection_fault(syscall);
                                continue;
                        }
                    }
                } else if (debugger->on_return_callback) {
                    debugger->on_return_callback(debugger->on_return_context, syscall);
                    debugger->on_return_callback = NULL;
                    debugger->on_return_context = NULL;
                }
            } else {
                switch (WSTOPSIG(status)) {
                    case SIGSEGV:
                        dispatch(PTBOX_EVENT_EXITING, exit_reason = PTBOX_EXIT_SEGFAULT);
                        puts("Child Segfault");
                        kill(pid, SIGKILL);
                        break;
                    case SIGFPE:
                        puts("Child SIGFPE");
                        kill(pid, SIGKILL);
                        break;
                    case SIGTRAP:
                        switch (status >> 16) {
                            case PTRACE_EVENT_EXIT:
                                if (exit_reason != PTBOX_EXIT_NORMAL)
                                    dispatch(PTBOX_EVENT_EXITING, PTBOX_EXIT_NORMAL);
                        }
                        break;
                }
                dispatch(PTBOX_EVENT_SIGNAL, WSTOPSIG(status));
            }
        }
        ptrace(PTRACE_SYSCALL, pid, NULL, NULL);
        first = false;
    }
    dispatch(PTBOX_EVENT_EXITED, exit_reason);
    return WIFEXITED(status) ? WEXITSTATUS(status) : -WTERMSIG(status);
}
<|endoftext|>


<commit_before>#ifndef ITER_STARMAP_H_
#define ITER_STARMAP_H_

#include "internal/iter_tuples.hpp"
#include "internal/iterator_wrapper.hpp"
#include "internal/iterbase.hpp"

#include <array>
#include <cassert>
#include <iterator>
#include <memory>
#include <type_traits>
#include <utility>

namespace iter {
  namespace impl {
    template <typename Func, typename Container>
    class StarMapper;

    template <typename Func, typename TupType, std::size_t... Is>
    class TupleStarMapper;

    struct StarMapFn;
  }
}

// NOTE I don't know why, but clang gets very confused by having  in the
// Iterators' member functions for these classes

// starmap with a container_<T> where T is one of tuple, pair, array
template <typename Func, typename Container>
class iter::impl::StarMapper {
 private:
  mutable Func func_;
  Container container_;

  using StarIterDeref = std::remove_reference_t<decltype(
      call_with_tuple(func_, std::declval<iterator_deref<Container>>()))>;

  StarMapper(Func f, Container&& c)
      : func_(std::move(f)), container_(std::forward<Container>(c)) {}

  friend StarMapFn;

 public:
  template <typename ContainerT>
  class Iterator
      : public std::iterator<std::input_iterator_tag, StarIterDeref> {
   private:
    template <typename>
    friend class Iterator;
    Func* func_;
    IteratorWrapper<ContainerT> sub_iter_;

   public:
    Iterator(Func& f, IteratorWrapper<ContainerT>&& sub_iter)
        : func_(&f), sub_iter_(std::move(sub_iter)) {}

    template <typename T>
    bool operator!=(const Iterator<T>& other) const {
      return sub_iter_ != other.sub_iter_;
    }

    template <typename T>
    bool operator==(const Iterator<T>& other) const {
      return !(*this != other);
    }

    Iterator& operator++() {
      ++sub_iter_;
      return *this;
    }

    Iterator operator++(int) {
      auto ret = *this;
      ++*this;
      return ret;
    }

    decltype(auto) operator*() {
      return call_with_tuple(*func_, *sub_iter_);
    }

    auto operator-> () -> ArrowProxy<decltype(**this)> {
      return {**this};
    }
  };

  Iterator<Container> begin() {
    return {func_, get_begin(container_)};
  }

  Iterator<Container> end() {
    return {func_, get_end(container_)};
  }

  Iterator<AsConst<Container>> begin() const {
    return {func_, get_begin(impl::as_const(container_))};
  }

  Iterator<AsConst<Container>> end() const {
    return {func_, get_end(impl::as_const(container_))};
  }
};

// starmap for a tuple or pair of tuples or pairs
template <typename Func, typename TupType, std::size_t... Is>
class iter::impl::TupleStarMapper {
 private:
  mutable Func func_;
  TupType tup_;

 private:
  static_assert(sizeof...(Is) == std::tuple_size<std::decay_t<TupType>>::value,
      "tuple size doesn't match size of Is");

  friend StarMapFn;

  TupleStarMapper(Func f, TupType t)
      : func_(std::move(f)), tup_(std::forward<TupType>(t)) {}

  // this is a wrapper class to hold the aliases and functions needed for the
  // Iterator.
  template <typename TupTypeT>
  class IteratorData {
   public:
    template <std::size_t Idx>
    static decltype(auto) get_and_call_with_tuple(Func& f, TupTypeT& t) {
      return call_with_tuple(f, std::get<Idx>(t));
    }

    using ResultType = decltype(get_and_call_with_tuple<0>(func_, tup_));
    using CallerFunc = ResultType (*)(Func&, TupTypeT&);

    constexpr static std::array<CallerFunc, sizeof...(Is)> callers{
        {get_and_call_with_tuple<Is>...}};

    using TraitsValue = std::remove_reference_t<ResultType>;

    IteratorData() = delete;
  };

 public:
  template <typename TupTypeT>
  class Iterator : public std::iterator<std::input_iterator_tag,
                       typename IteratorData<TupTypeT>::TraitsValue> {
   private:
    template <typename>
    friend class Iterator;
    Func* func_;
    std::remove_reference_t<TupTypeT>* tup_;
    std::size_t index_;

   public:
    Iterator(Func& f, TupTypeT& t, std::size_t i)
        : func_{&f}, tup_{&t}, index_{i} {}

    decltype(auto) operator*() {
      return IteratorData<TupTypeT>::callers[index_](*func_, *tup_);
    }

    auto operator-> () {
      return ArrowProxy<decltype(**this)>{**this};
    }

    Iterator& operator++() {
      ++index_;
      return *this;
    }

    Iterator operator++(int) {
      auto ret = *this;
      ++*this;
      return ret;
    }

    template <typename T>
    bool operator!=(const Iterator<T>& other) const {
      return index_ != other.index_;
    }

    template <typename T>
    bool operator==(const Iterator<T>& other) const {
      return !(*this != other);
    }
  };

  Iterator<TupType> begin() {
    return {func_, tup_, 0};
  }

  Iterator<TupType> end() {
    return {func_, tup_, sizeof...(Is)};
  }

  Iterator<AsConst<TupType>> begin() const {
    return {func_, impl::as_const(tup_), 0};
  }

  Iterator<AsConst<TupType>> end() const {
    return {func_, impl::as_const(tup_), sizeof...(Is)};
  }
};

template <typename Func, typename TupType, std::size_t... Is>
template <typename T>
constexpr std::array<typename iter::impl::TupleStarMapper<Func, TupType,
                         Is...>::template IteratorData<T>::CallerFunc,
    sizeof...(Is)>
    iter::impl::TupleStarMapper<Func, TupType, Is...>::IteratorData<T>::callers;

struct iter::impl::StarMapFn : PipeableAndBindFirst<StarMapFn> {
 private:
  template <typename Func, typename TupType, std::size_t... Is>
  TupleStarMapper<Func, TupType, Is...> helper_with_tuples(
      Func func, TupType&& tup, std::index_sequence<Is...>) const {
    return {std::move(func), std::forward<TupType>(tup)};
  }

  // handles tuple-like types
  template <typename Func, typename TupType>
  auto helper(Func func, TupType&& tup, std::true_type) const {
    return helper_with_tuples(std::move(func), std::forward<TupType>(tup),
        std::make_index_sequence<std::tuple_size<std::decay_t<TupType>>::
                                      value>{});
  }

  // handles everything else
  template <typename Func, typename Container>
  StarMapper<Func, Container> helper(
      Func func, Container&& container, std::false_type) const {
    return {std::move(func), std::forward<Container>(container)};
  }

  template <typename T, typename = void>
  struct is_tuple_like : public std::false_type {};

  template <typename T>
  struct is_tuple_like<T,
      std::void_t<decltype(std::tuple_size<std::decay_t<T>>::value)>>
      : public std::true_type {};

 public:
  template <typename Func, typename Seq>
  auto operator()(Func func, Seq&& sequence) const {
    return helper(
        std::move(func), std::forward<Seq>(sequence), is_tuple_like<Seq>{});
  }

  using PipeableAndBindFirst<StarMapFn>::operator();
};

namespace iter {
  constexpr impl::StarMapFn starmap{};
}

#endif
<commit_msg>if constexpr instead of tag dispatch<commit_after>#ifndef ITER_STARMAP_H_
#define ITER_STARMAP_H_

#include "internal/iter_tuples.hpp"
#include "internal/iterator_wrapper.hpp"
#include "internal/iterbase.hpp"

#include <array>
#include <cassert>
#include <iterator>
#include <memory>
#include <type_traits>
#include <utility>

namespace iter {
  namespace impl {
    template <typename Func, typename Container>
    class StarMapper;

    template <typename Func, typename TupType, std::size_t... Is>
    class TupleStarMapper;

    struct StarMapFn;
  }
}

// NOTE I don't know why, but clang gets very confused by having  in the
// Iterators' member functions for these classes

// starmap with a container_<T> where T is one of tuple, pair, array
template <typename Func, typename Container>
class iter::impl::StarMapper {
 private:
  mutable Func func_;
  Container container_;

  using StarIterDeref = std::remove_reference_t<decltype(
      call_with_tuple(func_, std::declval<iterator_deref<Container>>()))>;

  StarMapper(Func f, Container&& c)
      : func_(std::move(f)), container_(std::forward<Container>(c)) {}

  friend StarMapFn;

 public:
  template <typename ContainerT>
  class Iterator
      : public std::iterator<std::input_iterator_tag, StarIterDeref> {
   private:
    template <typename>
    friend class Iterator;
    Func* func_;
    IteratorWrapper<ContainerT> sub_iter_;

   public:
    Iterator(Func& f, IteratorWrapper<ContainerT>&& sub_iter)
        : func_(&f), sub_iter_(std::move(sub_iter)) {}

    template <typename T>
    bool operator!=(const Iterator<T>& other) const {
      return sub_iter_ != other.sub_iter_;
    }

    template <typename T>
    bool operator==(const Iterator<T>& other) const {
      return !(*this != other);
    }

    Iterator& operator++() {
      ++sub_iter_;
      return *this;
    }

    Iterator operator++(int) {
      auto ret = *this;
      ++*this;
      return ret;
    }

    decltype(auto) operator*() {
      return call_with_tuple(*func_, *sub_iter_);
    }

    auto operator-> () -> ArrowProxy<decltype(**this)> {
      return {**this};
    }
  };

  Iterator<Container> begin() {
    return {func_, get_begin(container_)};
  }

  Iterator<Container> end() {
    return {func_, get_end(container_)};
  }

  Iterator<AsConst<Container>> begin() const {
    return {func_, get_begin(impl::as_const(container_))};
  }

  Iterator<AsConst<Container>> end() const {
    return {func_, get_end(impl::as_const(container_))};
  }
};

// starmap for a tuple or pair of tuples or pairs
template <typename Func, typename TupType, std::size_t... Is>
class iter::impl::TupleStarMapper {
 private:
  mutable Func func_;
  TupType tup_;

 private:
  static_assert(sizeof...(Is) == std::tuple_size<std::decay_t<TupType>>::value,
      "tuple size doesn't match size of Is");

  friend StarMapFn;

  TupleStarMapper(Func f, TupType t)
      : func_(std::move(f)), tup_(std::forward<TupType>(t)) {}

  // this is a wrapper class to hold the aliases and functions needed for the
  // Iterator.
  template <typename TupTypeT>
  class IteratorData {
   public:
    template <std::size_t Idx>
    static decltype(auto) get_and_call_with_tuple(Func& f, TupTypeT& t) {
      return call_with_tuple(f, std::get<Idx>(t));
    }

    using ResultType = decltype(get_and_call_with_tuple<0>(func_, tup_));
    using CallerFunc = ResultType (*)(Func&, TupTypeT&);

    constexpr static std::array<CallerFunc, sizeof...(Is)> callers{
        {get_and_call_with_tuple<Is>...}};

    using TraitsValue = std::remove_reference_t<ResultType>;

    IteratorData() = delete;
  };

 public:
  template <typename TupTypeT>
  class Iterator : public std::iterator<std::input_iterator_tag,
                       typename IteratorData<TupTypeT>::TraitsValue> {
   private:
    template <typename>
    friend class Iterator;
    Func* func_;
    std::remove_reference_t<TupTypeT>* tup_;
    std::size_t index_;

   public:
    Iterator(Func& f, TupTypeT& t, std::size_t i)
        : func_{&f}, tup_{&t}, index_{i} {}

    decltype(auto) operator*() {
      return IteratorData<TupTypeT>::callers[index_](*func_, *tup_);
    }

    auto operator-> () {
      return ArrowProxy<decltype(**this)>{**this};
    }

    Iterator& operator++() {
      ++index_;
      return *this;
    }

    Iterator operator++(int) {
      auto ret = *this;
      ++*this;
      return ret;
    }

    template <typename T>
    bool operator!=(const Iterator<T>& other) const {
      return index_ != other.index_;
    }

    template <typename T>
    bool operator==(const Iterator<T>& other) const {
      return !(*this != other);
    }
  };

  Iterator<TupType> begin() {
    return {func_, tup_, 0};
  }

  Iterator<TupType> end() {
    return {func_, tup_, sizeof...(Is)};
  }

  Iterator<AsConst<TupType>> begin() const {
    return {func_, impl::as_const(tup_), 0};
  }

  Iterator<AsConst<TupType>> end() const {
    return {func_, impl::as_const(tup_), sizeof...(Is)};
  }
};

template <typename Func, typename TupType, std::size_t... Is>
template <typename T>
constexpr std::array<typename iter::impl::TupleStarMapper<Func, TupType,
                         Is...>::template IteratorData<T>::CallerFunc,
    sizeof...(Is)>
    iter::impl::TupleStarMapper<Func, TupType, Is...>::IteratorData<T>::callers;

struct iter::impl::StarMapFn : PipeableAndBindFirst<StarMapFn> {
 private:
  template <typename Func, typename TupType, std::size_t... Is>
  TupleStarMapper<Func, TupType, Is...> helper_with_tuples(
      Func func, TupType&& tup, std::index_sequence<Is...>) const {
    return {std::move(func), std::forward<TupType>(tup)};
  }

  template <typename T, typename = void>
  struct is_tuple_like : std::false_type {};

  template <typename T>
  struct is_tuple_like<T,
      std::void_t<decltype(std::tuple_size<std::decay_t<T>>::value)>>
      : std::true_type {};

 public:
  template <typename Func, typename Seq>
  auto operator()(Func func, Seq&& sequence) const {
    if constexpr (is_tuple_like<Seq>{}) {
      return helper_with_tuples(std::move(func), std::forward<Seq>(sequence),
          std::make_index_sequence<std::tuple_size<std::decay_t<Seq>>::
                  value>{});
    } else {
      return StarMapper<Func, Seq>{
          std::move(func), std::forward<Seq>(sequence)};
    }
  }

  using PipeableAndBindFirst<StarMapFn>::operator();
};

namespace iter {
  constexpr impl::StarMapFn starmap{};
}

#endif
<|endoftext|>


<commit_before>/*
  Copyright (c) 2014-2015 DataStax

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*/

// Based on the ring buffer implementation in
// NodeBIO (https://github.com/joyent/node/blob/master/src/node_crypto_bio.h).
// The following is the license for that implementation:

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

#ifndef __CASS_RING_BUFFER_HPP_INCLUDED__
#define __CASS_RING_BUFFER_HPP_INCLUDED__

#include "fixed_vector.hpp"

#include <uv.h>

namespace cass {
namespace rb {

class RingBuffer {
 private:
  // NOTE: Size is maximum TLS frame length, this is required if we want
  // to fit whole ClientHello into one Buffer of RingBuffer.
  static const size_t BUFFER_LENGTH = 16 * 1024 + 5;

  class Buffer {
   public:
    Buffer() : read_pos_(0), write_pos_(0), next_(NULL) {
    }

    size_t read_pos_;
    size_t write_pos_;
    Buffer* next_;
    char data_[BUFFER_LENGTH];
  };

 public:
  struct Position {
    Position(Buffer* buf, size_t pos)
      : buf(buf) , pos(pos) {}
    Buffer* buf;
    size_t pos;
  };

  RingBuffer()
    : length_(0)
    , read_head_(&head_)
    , write_head_(&head_) {
    // Loop head
    head_.next_ = &head_;
  }

  ~RingBuffer();

  Position write_position() {
    return Position(write_head_, write_head_->write_pos_);
  }

  // Move read head to next buffer if needed
  void try_move_read_head();

  // Allocate new buffer for write if needed
  void try_allocate_for_write();

  // Read `len` bytes maximum into `out`, return actual number of read bytes
  size_t read(char* out, size_t size);

  // Memory optimization:
  // Deallocate children of write head's child if they're empty
  void free_empty();

  // Return pointers and sizes of multiple internal data chunks available for
  // reading from position
  template <size_t N>
  size_t peek_multiple(Position pos, FixedVector<uv_buf_t, N>* bufs);

  // Find first appearance of `delim` in buffer or `limit` if `delim`
  // wasn't found.
  size_t index_of(char delim, size_t limit);

  // Discard all available data
  void reset();

  // Put `len` bytes from `data` into buffer
  void write(const char* data, size_t size);

  // Return pointer to internal data and amount of
  // contiguous data available for future writes
  char* peek_writable(size_t* size);

  // Commit reserved data
  void commit(size_t size);

  // Return size of buffer in bytes
  size_t inline length() {
    return length_;
  }

 private:
  size_t length_;
  Buffer head_;
  Buffer* read_head_;
  Buffer* write_head_;
};

template <size_t N>
size_t RingBuffer::peek_multiple(Position pos, FixedVector<uv_buf_t, N>* bufs) {
  Buffer* buf = pos.buf;
  size_t offset = pos.pos;
  size_t total = 0;

  while (true) {
    char* base = (buf->data_ + offset);
    size_t len = (buf->write_pos_ - offset);
    bufs->push_back(uv_buf_init(base, len));

    /* Don't get past write head */
    if (buf == write_head_)
      break;
    else
      buf = buf->next_;

    offset = buf->read_pos_;
  }

  return total;
}

} // namespace rb
} // namespace cass

#endif
<commit_msg>Fixed leak caused by RingBuffer::peek_multiple() always returning zero<commit_after>/*
  Copyright (c) 2014-2015 DataStax

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*/

// Based on the ring buffer implementation in
// NodeBIO (https://github.com/joyent/node/blob/master/src/node_crypto_bio.h).
// The following is the license for that implementation:

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

#ifndef __CASS_RING_BUFFER_HPP_INCLUDED__
#define __CASS_RING_BUFFER_HPP_INCLUDED__

#include "fixed_vector.hpp"

#include <uv.h>

namespace cass {
namespace rb {

class RingBuffer {
 private:
  // NOTE: Size is maximum TLS frame length, this is required if we want
  // to fit whole ClientHello into one Buffer of RingBuffer.
  static const size_t BUFFER_LENGTH = 16 * 1024 + 5;

  class Buffer {
   public:
    Buffer() : read_pos_(0), write_pos_(0), next_(NULL) {
    }

    size_t read_pos_;
    size_t write_pos_;
    Buffer* next_;
    char data_[BUFFER_LENGTH];
  };

 public:
  struct Position {
    Position(Buffer* buf, size_t pos)
      : buf(buf) , pos(pos) {}
    Buffer* buf;
    size_t pos;
  };

  RingBuffer()
    : length_(0)
    , read_head_(&head_)
    , write_head_(&head_) {
    // Loop head
    head_.next_ = &head_;
  }

  ~RingBuffer();

  Position write_position() {
    return Position(write_head_, write_head_->write_pos_);
  }

  // Move read head to next buffer if needed
  void try_move_read_head();

  // Allocate new buffer for write if needed
  void try_allocate_for_write();

  // Read `len` bytes maximum into `out`, return actual number of read bytes
  size_t read(char* out, size_t size);

  // Memory optimization:
  // Deallocate children of write head's child if they're empty
  void free_empty();

  // Return pointers and sizes of multiple internal data chunks available for
  // reading from position
  template <size_t N>
  size_t peek_multiple(Position pos, FixedVector<uv_buf_t, N>* bufs);

  // Find first appearance of `delim` in buffer or `limit` if `delim`
  // wasn't found.
  size_t index_of(char delim, size_t limit);

  // Discard all available data
  void reset();

  // Put `len` bytes from `data` into buffer
  void write(const char* data, size_t size);

  // Return pointer to internal data and amount of
  // contiguous data available for future writes
  char* peek_writable(size_t* size);

  // Commit reserved data
  void commit(size_t size);

  // Return size of buffer in bytes
  size_t inline length() {
    return length_;
  }

 private:
  size_t length_;
  Buffer head_;
  Buffer* read_head_;
  Buffer* write_head_;
};

template <size_t N>
size_t RingBuffer::peek_multiple(Position pos, FixedVector<uv_buf_t, N>* bufs) {
  Buffer* buf = pos.buf;
  size_t offset = pos.pos;
  size_t total = 0;

  while (true) {
    char* base = (buf->data_ + offset);
    size_t len = (buf->write_pos_ - offset);
    bufs->push_back(uv_buf_init(base, len));
    total += len;

    /* Don't get past write head */
    if (buf == write_head_)
      break;
    else
      buf = buf->next_;

    offset = buf->read_pos_;
  }

  return total;
}

} // namespace rb
} // namespace cass

#endif
<|endoftext|>


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

  Program:   Visualization Library
  Module:    CArray.cc
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Description:
---------------------------------------------------------------------------
This file is part of the Visualization Library. No part of this file
or its contents may be copied, reproduced or altered in any way
without the express written consent of the authors.

Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen 1993, 1994

=========================================================================*/
//
//  Dynamic, self adjusting char array
//
//
#include "CArray.hh"

vlCharArray::Initialize(const int sz, const int ext)
{
  if ( this->Array != 0 ) delete [] this->Array;

  this->Size = ( sz > 0 ? sz : 1);
  if ( (this->Array = new char[sz]) == 0 ) return 0;
  this->Extend = ( ext > 0 ? ext : 1);
  this->MaxId = -1;

  return 1;
}

vlCharArray::vlCharArray(const int sz, const int ext)
{
  this->Size = ( sz > 0 ? sz : 1);
  this->Array = new char[sz];
  this->Extend = ( ext > 0 ? ext : 1);
  this->MaxId = -1;
}

vlCharArray::~vlCharArray()
{
  delete [] this->Array;
}

vlCharArray::vlCharArray(const vlCharArray& ia)
{
  int i;

  this->MaxId = ia.MaxId;
  this->Size = ia.Size;
  this->Extend = ia.Extend;

  this->Array = new char[this->Size];
  for (i=0; i<this->MaxId; i++)
    this->Array[i] = ia.Array[i];

}

vlCharArray& vlCharArray::operator=(vlCharArray& ia)
{
  int i;

  if ( this != &ia )
    {
    delete [] this->Array;

    this->MaxId = ia.MaxId;
    this->Size = ia.Size;
    this->Extend = ia.Extend;

    this->Array = new char[this->Size];
    for (i=0; i<=this->MaxId; i++)
      this->Array[i] = ia.Array[i];
    }
  return *this;
}

//
// Copy on write if used by more than one object
//
vlCharArray& vlCharArray::operator+=(vlCharArray& ia)
{
  int i, sz;

  if ( this->Size <= (sz = this->MaxId + ia.MaxId + 2) ) this->Resize(sz);

  for (i=0; i<=ia.MaxId; i++)
    {
    this->Array[this->MaxId+1+i] = ia.Array[i];
    }
  this->MaxId += ia.MaxId + 1;

}

void vlCharArray::PrintSelf(ostream& os, vlIndent indent)
{
  if (this->ShouldIPrint(vlCharArray::GetClassName()))
    {
    vlObject::PrintSelf(os,indent);

    os << indent << "Array: " << this->Array << "\n";
    os << indent << "Size: " << this->Size << "\n";
    os << indent << "MaxId: " << this->MaxId << "\n";
    os << indent << "Extend size: " << this->Extend << "\n";
    }
}

//
// Private function does "reallocate"
//
char *vlCharArray::Resize(const int sz)
{
  int i;
  char *newArray;
  int newSize;

  if ( sz >= this->Size ) newSize = this->Size +
    this->Extend*(((sz-this->Size)/this->Extend)+1);
  else newSize = sz;

  if ( (newArray = new char[newSize]) == 0 )
    {
    vlErrorMacro(<< "Cannot allocate memory\n");
    return 0;
    }

  for (i=0; i<sz && i<this->Size; i++)
      newArray[i] = this->Array[i];

  this->Size = newSize;
  delete [] this->Array;
  this->Array = newArray;

  return this->Array;
}
<commit_msg>fixed prototype conflict<commit_after>/*=========================================================================

  Program:   Visualization Library
  Module:    CArray.cc
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Description:
---------------------------------------------------------------------------
This file is part of the Visualization Library. No part of this file
or its contents may be copied, reproduced or altered in any way
without the express written consent of the authors.

Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen 1993, 1994

=========================================================================*/
//
//  Dynamic, self adjusting char array
//
//
#include "CArray.hh"

vlCharArray::Initialize(const int sz, const int ext)
{
  if ( this->Array != 0 ) delete [] this->Array;

  this->Size = ( sz > 0 ? sz : 1);
  if ( (this->Array = new char[sz]) == 0 ) return 0;
  this->Extend = ( ext > 0 ? ext : 1);
  this->MaxId = -1;

  return 1;
}

vlCharArray::vlCharArray(const int sz, const int ext)
{
  this->Size = ( sz > 0 ? sz : 1);
  this->Array = new char[sz];
  this->Extend = ( ext > 0 ? ext : 1);
  this->MaxId = -1;
}

vlCharArray::~vlCharArray()
{
  delete [] this->Array;
}

vlCharArray::vlCharArray(const vlCharArray& ia)
{
  int i;

  this->MaxId = ia.MaxId;
  this->Size = ia.Size;
  this->Extend = ia.Extend;

  this->Array = new char[this->Size];
  for (i=0; i<this->MaxId; i++)
    this->Array[i] = ia.Array[i];

}

vlCharArray& vlCharArray::operator=(vlCharArray& ia)
{
  int i;

  if ( this != &ia )
    {
    delete [] this->Array;

    this->MaxId = ia.MaxId;
    this->Size = ia.Size;
    this->Extend = ia.Extend;

    this->Array = new char[this->Size];
    for (i=0; i<=this->MaxId; i++)
      this->Array[i] = ia.Array[i];
    }
  return *this;
}

//
// Copy on write if used by more than one object
//
vlCharArray& vlCharArray::operator+=(vlCharArray& ia)
{
  int i, sz;

  if ( this->Size <= (sz = this->MaxId + ia.MaxId + 2) ) this->Resize(sz);

  for (i=0; i<=ia.MaxId; i++)
    {
    this->Array[this->MaxId+1+i] = ia.Array[i];
    }
  this->MaxId += ia.MaxId + 1;
  return *this;
}

void vlCharArray::PrintSelf(ostream& os, vlIndent indent)
{
  if (this->ShouldIPrint(vlCharArray::GetClassName()))
    {
    vlObject::PrintSelf(os,indent);

    os << indent << "Array: " << this->Array << "\n";
    os << indent << "Size: " << this->Size << "\n";
    os << indent << "MaxId: " << this->MaxId << "\n";
    os << indent << "Extend size: " << this->Extend << "\n";
    }
}

//
// Private function does "reallocate"
//
char *vlCharArray::Resize(const int sz)
{
  int i;
  char *newArray;
  int newSize;

  if ( sz >= this->Size ) newSize = this->Size +
    this->Extend*(((sz-this->Size)/this->Extend)+1);
  else newSize = sz;

  if ( (newArray = new char[newSize]) == 0 )
    {
    vlErrorMacro(<< "Cannot allocate memory\n");
    return 0;
    }

  for (i=0; i<sz && i<this->Size; i++)
      newArray[i] = this->Array[i];

  this->Size = newSize;
  delete [] this->Array;
  this->Array = newArray;

  return this->Array;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <string>
#include <cstdint>

#include "linenoise.h"
#include <db.h>

#include <humblelogging/api.h>
#include <boost/algorithm/string.hpp>

using namespace std;

HUMBLE_LOGGER(logger, "default");

void completion(const char *bufRaw, linenoiseCompletions *lc)
{
  std::string buf(bufRaw);
  if(boost::starts_with(buf, "q"))
  {
    linenoiseAddCompletion(lc,"quit");
  }
  else if(boost::starts_with(buf, "e"))
  {
    linenoiseAddCompletion(lc,"exit");
  }
  else if(boost::starts_with(buf, "i"))
  {
    linenoiseAddCompletion(lc,"import");
  }
  else if(boost::starts_with(buf, "s"))
  {
    linenoiseAddCompletion(lc, "save");
  }
  else if(boost::starts_with(buf, "l"))
  {
    linenoiseAddCompletion(lc, "load");
  }
  else if(boost::starts_with(buf, "o"))
  {
    linenoiseAddCompletion(lc, "optimize");
  }
}

int main(int argc, char** argv)
{
  char* lineBuffer = NULL;

  humble::logging::Factory &fac = humble::logging::Factory::getInstance();
  fac.setConfiguration(humble::logging::DefaultConfiguration::createFromString(
    "logger.level(*)=info\n"
  ));
  fac.setDefaultFormatter(new humble::logging::PatternFormatter("[%date] %m\n"));
  fac.registerAppender(new humble::logging::ConsoleAppender());

  linenoiseHistoryLoad("annis4_history.txt");
  linenoiseSetCompletionCallback(completion);

  // our main database
  annis::DB db;

  bool exit = false;
  while(!exit && (lineBuffer = linenoise("annis4> ")) != NULL)
  {
    std::string line(lineBuffer);
    linenoiseHistoryAdd(lineBuffer);
    linenoiseHistorySave("annis4_history.txt");

    // split the line into it's components
    vector<string> args;
    boost::split(args,line, boost::is_any_of(" "));
    std::string cmd = "";
    if(args.size() > 0)
    {
      cmd = args[0];
      args.erase(args.begin());
    }
    try
    {
      if (cmd == "import")
      {
        if(args.size() > 0)
        {
          std::cout << "Import relANNIS from " << args[0] << std::endl;
          db.loadRelANNIS(args[0]);
        }
        else
        {
          std::cout << "You have to give a path as argument" << std::endl;
        }
      }
      else if(cmd == "save")
      {
        if(args.size() > 0)
        {
          std::cout << "Save to " << args[0] << std::endl;
          db.save(args[0]);
        }
        else
        {
          std::cout << "You have to give a path as argument" << std::endl;
        }
      }
      else if(cmd == "load")
      {
        if(args.size() > 0)
        {
          std::cout << "Loading from " << args[0] << std::endl;
          db.load(args[0]);
        }
        else
        {
          std::cout << "You have to give a path as argument" << std::endl;
        }
      }
      else if(cmd == "info")
      {
        std::cout << db.info() << std::endl;
      }
      else if(cmd == "optimize")
      {
        std::cout << "Optimizing..." << std::endl;
        db.optimizeAll();
        std::cout << "Finished." << std::endl;
      }
      else if (cmd == "quit" || cmd == "exit")
      {
        exit = true;
      }
      else
      {
        std::cout << "Unknown command \"" << cmd << "\"" << std::endl;
      }
    }
    catch(std::string ex)
    {
      std::cerr << "Exception: " << ex << std::endl;
    }
    free(lineBuffer);
  }
  std::cout << "Exiting" << std::endl;

  return 0;
}

<commit_msg>allow to dynically execute a query in a4_runner<commit_after>#include <iostream>
#include <string>
#include <cstdint>

#include "linenoise.h"
#include <db.h>
#include <jsonqueryparser.h>

#include <humblelogging/api.h>
#include <boost/algorithm/string.hpp>

using namespace std;

HUMBLE_LOGGER(logger, "default");

void completion(const char *bufRaw, linenoiseCompletions *lc)
{
  std::string buf(bufRaw);
  if(boost::starts_with(buf, "q"))
  {
    linenoiseAddCompletion(lc,"quit");
  }
  else if(boost::starts_with(buf, "e"))
  {
    linenoiseAddCompletion(lc,"exit");
  }
  else if(boost::starts_with(buf, "i"))
  {
    linenoiseAddCompletion(lc,"import");
  }
  else if(boost::starts_with(buf, "s"))
  {
    linenoiseAddCompletion(lc, "save");
  }
  else if(boost::starts_with(buf, "l"))
  {
    linenoiseAddCompletion(lc, "load");
  }
  else if(boost::starts_with(buf, "o"))
  {
    linenoiseAddCompletion(lc, "optimize");
  }
  else if(boost::starts_with(buf, "c"))
  {
    linenoiseAddCompletion(lc, "count");
  }
  else if(boost::starts_with(buf, "f"))
  {
    linenoiseAddCompletion(lc, "find");
  }
}

int main(int argc, char** argv)
{
  char* lineBuffer = NULL;

  humble::logging::Factory &fac = humble::logging::Factory::getInstance();
  fac.setConfiguration(humble::logging::DefaultConfiguration::createFromString(
    "logger.level(*)=info\n"
  ));
  fac.setDefaultFormatter(new humble::logging::PatternFormatter("[%date] %m\n"));
  fac.registerAppender(new humble::logging::ConsoleAppender());

  linenoiseHistoryLoad("annis4_history.txt");
  linenoiseSetCompletionCallback(completion);

  // our main database
  annis::DB db;

  bool exit = false;
  while(!exit && (lineBuffer = linenoise("annis4> ")) != NULL)
  {
    std::string line(lineBuffer);
    linenoiseHistoryAdd(lineBuffer);
    linenoiseHistorySave("annis4_history.txt");

    // split the line into it's components
    vector<string> args;
    boost::split(args,line, boost::is_any_of(" "));
    std::string cmd = "";
    if(args.size() > 0)
    {
      cmd = args[0];
      args.erase(args.begin());
    }
    try
    {
      if (cmd == "import")
      {
        if(args.size() > 0)
        {
          std::cout << "Import relANNIS from " << args[0] << std::endl;
          db.loadRelANNIS(args[0]);
        }
        else
        {
          std::cout << "You have to give a path as argument" << std::endl;
        }
      }
      else if(cmd == "save")
      {
        if(args.size() > 0)
        {
          std::cout << "Save to " << args[0] << std::endl;
          db.save(args[0]);
        }
        else
        {
          std::cout << "You have to give a path as argument" << std::endl;
        }
      }
      else if(cmd == "load")
      {
        if(args.size() > 0)
        {
          std::cout << "Loading from " << args[0] << std::endl;
          db.load(args[0]);
        }
        else
        {
          std::cout << "You have to give a path as argument" << std::endl;
        }
      }
      else if(cmd == "info")
      {
        std::cout << db.info() << std::endl;
      }
      else if(cmd == "optimize")
      {
        std::cout << "Optimizing..." << std::endl;
        db.optimizeAll();
        std::cout << "Finished." << std::endl;
      }
      else if(cmd == "count")
      {
        if(args.size() > 0)
        {
          std::string json = boost::join(args, " ");
          std::cout << "Counting..." << std::endl;
          std::stringstream ss;
          ss << json;
          std::shared_ptr<annis::Query> q = annis::JSONQueryParser::parse(db, ss);
          int counter =0;
          while(q->hasNext())
          {
            q->next();
            counter++;
          }
          std::cout << counter << " matches" << std::endl;
        }
        else
        {
          std::cout << "you need to give the query JSON as argument" << std::endl;
        }
      }
      else if(cmd == "find")
      {
        if(args.size() > 0)
        {
          std::string json = boost::join(args, " ");
          std::cout << "Finding..." << std::endl;
          std::stringstream ss;
          ss << json;
          std::shared_ptr<annis::Query> q = annis::JSONQueryParser::parse(db, ss);
          int counter =0;
          while(q->hasNext())
          {
            std::vector<annis::Match> m = q->next();
            for(auto i = 0; i < m.size(); i++)
            {
              const auto& n = m[i];
              std::cout << db.getNodeDebugName(n.node) << " " << db.strings.str(n.anno.ns)
                << "::" << db.strings.str(n.anno.name) << "->" << db.strings.str(n.anno.val);
              if(i < m.size()-1)
              {
               std::cout << ", ";
              }
            }
            std::cout << std::endl;
            counter++;
          }
          std::cout << counter << " matches" << std::endl;
        }
        else
        {
          std::cout << "you need to give the query JSON as argument" << std::endl;
        }
      }
      else if (cmd == "quit" || cmd == "exit")
      {
        exit = true;
      }
      else
      {
        std::cout << "Unknown command \"" << cmd << "\"" << std::endl;
      }
    }
    catch(std::string ex)
    {
      std::cerr << "Exception: " << ex << std::endl;
    }
    free(lineBuffer);
  }
  std::cout << "Exiting" << std::endl;

  return 0;
}

<|endoftext|>


<commit_before>/* Copyright 1994, 1995 by Abacus Research and
 * Development, Inc.  All rights reserved.
 */

/* screen-dump.c; dump the mac screen to a tiff file */

#include <base/common.h>

#include <stdarg.h>

#include <QuickDraw.h>
#include <CQuickDraw.h>
#include <MemoryMgr.h>

#include <quickdraw/cquick.h>
#include <mman/mman.h>
#include <mman/tempalloc.h>
#include <prefs/prefs.h>
#include <rsys/uniquefile.h>
#include <file/file.h>
#include <rsys/screen-dump.h>
#include <rsys/paths.h>
#include <rsys/unixio.h>

using namespace Executor;

#define II_little_endian 0x4949
#define MM_big_endian 0x4D4D

#define BYTE 1
#define ASCII 2
#define SHORT 3
#define LONG 4
#define RATIONAL 5

#define SBYTE 6
#undef UNDEFINED /* svgalib defines this. */
#define UNDEFINED 7
#define SSHORT 8
#define SLONG 9
#define SRATIONAL 10

#define FLOAT 11
#define DOUBLE 12

#define ImageWidth 256
#define ImageLength 257
#define BitsPerSample 258
#define Compression 259
#define PhotometricInterpretation 262
#define StripOffsets 273
#define RowsPerStrip 278
#define StripByteCounts 279
#define XResolution 282
#define YResolution 283
#define ResolutionUnit 296
#define ColorMap 320

static void
ifd_add_entry(struct ifd *ifd, int tag, int type, ...)
{
    va_list ap;
    struct directory_entry *current_entry;

    va_start(ap, type);

    current_entry = &ifd->entries[ifd->count];
    ifd->count++;

    /* default values */
    current_entry->tag = tag;
    current_entry->type = type;
    current_entry->count = 1;

    switch(type)
    {
        case SHORT:
            current_entry->value_offset_16 = (int16_t)va_arg(ap, int32_t);
            break;
        case LONG:
            current_entry->value_offset = va_arg(ap, int32_t);
            break;
        case -1:
            current_entry->type = va_arg(ap, int32_t);
            current_entry->count = va_arg(ap, int32_t);
            current_entry->value_offset = va_arg(ap, int32_t);
            break;
        default:
            gui_fatal("unknown tag type");
            break;
    }
    va_end(ap);
}

static void
dump_indirect_pm(PixMap *pm)
{
    PixMap *tiff_pm;

    void *fbuf;
    int fbuf_size;
    int row_bytes;
    int width, height;
    int bpp;

    struct header *header;
    int header_size;

    static const int n_ifd_entries = 10;
    struct ifd *ifd;
    int ifd_size;

    int8_t *tif;
    int tif_size;

    int32_t *strip_offsets;
    int strip_offsets_size;
    int strip_offsets_offset;

    int32_t *strip_byte_counts;
    int strip_byte_counts_size;
    int strip_byte_counts_offset;

    int16_t *color_map;
    int color_map_size;
    int color_map_offset;

    int i;
    int retval;
    int fd;

    Str255 temp_file_name;

    TEMP_ALLOC_DECL(temp_fbuf_bits);
    TEMP_ALLOC_DECL(temp_tif_bits);

    height = RECT_HEIGHT(&pm->bounds);
    width = RECT_WIDTH(&pm->bounds);

    bpp = pm->pixelSize;

    if(bpp != 8 && bpp != 4)
    {
        tiff_pm = (PixMap *)alloca(sizeof *tiff_pm);

        /* compute the bpp of the pixmap that will be converted to a tif */
        bpp = bpp <= 4 ? 4 : 8;

        fbuf_size = width * height;
        TEMP_ALLOC_ALLOCATE(fbuf, temp_fbuf_bits, fbuf_size);
        row_bytes = (width * bpp + 31) / 32 * 4;

        tiff_pm->baseAddr = (Ptr)fbuf;
        tiff_pm->rowBytes = row_bytes | PIXMAP_DEFAULT_ROW_BYTES;
        tiff_pm->bounds = pm->bounds;

        pixmap_set_pixel_fields(tiff_pm, bpp);

        tiff_pm->pmTable = pm->pmTable;

        CopyBits((BitMap *)pm, (BitMap *)tiff_pm,
                 &pm->bounds, &tiff_pm->bounds,
                 srcCopy, nullptr);
    }
    else
    {
        tiff_pm = pm;
        fbuf = BITMAP_BASEADDR(pm);
        row_bytes = BITMAP_ROWBYTES(pm);
        fbuf_size = height * row_bytes;
    }

    header_size = sizeof *header;
    ifd_size = sizeof *ifd + (n_ifd_entries - 1) * sizeof *ifd->entries;

    color_map_size = 3 * (1 << bpp) * sizeof *color_map;
    color_map_offset = header_size + ifd_size;

    strip_offsets_size = sizeof *strip_offsets * height;
    strip_offsets_offset = color_map_offset + color_map_size;

    strip_byte_counts_size = sizeof *strip_byte_counts * height;
    strip_byte_counts_offset = strip_offsets_offset + strip_offsets_size;

    tif_size = (header_size + ifd_size + color_map_size
                + strip_offsets_size + strip_byte_counts_size);
    TEMP_ALLOC_ALLOCATE(tif, temp_tif_bits, tif_size);

    header = (struct header *)&tif[0];
    ifd = (struct ifd *)&tif[header_size];
    color_map = (int16_t *)&tif[color_map_offset];
    strip_offsets = (int32_t *)&tif[strip_offsets_offset];
    strip_byte_counts = (int32_t *)&tif[strip_byte_counts_offset];

#if defined(LITTLEENDIAN)
    header->byte_order = II_little_endian;
#else
    header->byte_order = MM_big_endian;
#endif

    header->magic_number = 42;
    header->ifd_offset = header_size;

    memset(ifd, 0, ifd_size);

    /* NOTE: order matters here, the ifd directory entries must be
     sorted by tag */
    /* NOTE: if you change the number of entries here; make sure to
     update `n_ifd_entries' appropriately */
    ifd_add_entry(ifd, ImageWidth, SHORT, width);
    ifd_add_entry(ifd, ImageLength, SHORT, height);
    ifd_add_entry(ifd, BitsPerSample, SHORT, bpp);
    ifd_add_entry(ifd, Compression, SHORT, 1);
    ifd_add_entry(ifd, PhotometricInterpretation, SHORT, 3);
    ifd_add_entry(ifd, StripOffsets, -1,
                  LONG, height,
                  strip_offsets_offset);
    ifd_add_entry(ifd, RowsPerStrip, SHORT, 1);
    ifd_add_entry(ifd, StripByteCounts, -1,
                  LONG, height, strip_byte_counts_offset);

#if 0
  ifd_add_entry (ifd, XResolution,		RATIONAL, 1, 1);
  ifd_add_entry (ifd, YResolution,		RATIONAL, 1, 1);
#endif
    ifd_add_entry(ifd, ResolutionUnit, SHORT, 1);
    ifd_add_entry(ifd, ColorMap, -1,
                  SHORT, 3 * (1 << bpp), color_map_offset);

    gui_assert(ifd->count == n_ifd_entries);

    {
        ColorSpec *color_table;
        int color_table_size;

        memset(color_map, 0xFF, color_map_size);

        color_table_size = CTAB_SIZE(tiff_pm->pmTable);
        color_table = CTAB_TABLE(tiff_pm->pmTable);

        for(i = 0; i <= color_table_size; i++)
        {
            color_map[i] = color_table[i].rgb.red;
            color_map[i + (1 << bpp)] = color_table[i].rgb.green;
            color_map[i + (2 << bpp)] = color_table[i].rgb.blue;
        }
    }

    for(i = 0; i < height; i++)
        strip_offsets[i] = tif_size + row_bytes * i;

    for(i = 0; i < height; i++)
        strip_byte_counts[i] = row_bytes;

    /* now open up a file and write this sucker out */
    if(!unique_file_name(ROMlib_ScreenDumpFile.c_str(), "excscrn*.tif",
                         temp_file_name))
        return;

    fd = open((char *)temp_file_name + 1,
               O_CREAT | O_TRUNC | O_WRONLY | O_BINARY, 0666);
    if(fd == -1)
    {
        warning_errno("open `%s' failed", temp_file_name + 1);
        return;
    }

    retval = write(fd, tif, tif_size);
    if(retval == -1 || retval != tif_size)
    {
        warning_errno("`write (..., tif, ...)' failed");
        goto done;
    }

    retval = write(fd, fbuf, fbuf_size);
    if(retval == -1 || retval != fbuf_size)
    {
        warning_errno("`write (..., fbuf, ...)' failed");
        goto done;
    }

done:
    close(fd);
}

static void
dump_direct_pm(PixMap *pm)
{
    /* ### fix this! */
    warning_unimplemented("can't dump direct pixel pixmap");
}

typedef void (*dump_fn_t)(PixMap *);

dump_fn_t dump_fns[] = {
    dump_indirect_pm, dump_indirect_pm,
    dump_indirect_pm, dump_indirect_pm,
    dump_direct_pm, dump_direct_pm,
};

void Executor::do_dump_screen(void)
{
    GDHandle gd;
    PixMapHandle gd_pmh;

    gd = LM(MainDevice);
    gd_pmh = GD_PMAP(gd);

    HLockGuard guard(gd_pmh);
    PixMap *gd_pm;
    int log2_bpp;

    gd_pm = *gd_pmh;
    log2_bpp = ROMlib_log2[gd_pm->pixelSize];

    (*dump_fns[log2_bpp])(gd_pm);
}
<commit_msg>fix tiff-format export for screenshots<commit_after>/* Copyright 1994, 1995 by Abacus Research and
 * Development, Inc.  All rights reserved.
 */

/* screen-dump.c; dump the mac screen to a tiff file */

#include <base/common.h>

#include <stdarg.h>

#include <QuickDraw.h>
#include <CQuickDraw.h>
#include <MemoryMgr.h>

#include <quickdraw/cquick.h>
#include <mman/mman.h>
#include <mman/tempalloc.h>
#include <prefs/prefs.h>
#include <rsys/uniquefile.h>
#include <file/file.h>
#include <rsys/screen-dump.h>
#include <rsys/paths.h>
#include <rsys/unixio.h>

using namespace Executor;

#define II_little_endian 0x4949
#define MM_big_endian 0x4D4D

#define BYTE 1
#define ASCII 2
#define SHORT 3
#define LONG 4
#define RATIONAL 5

#define SBYTE 6
#undef UNDEFINED /* svgalib defines this. */
#define UNDEFINED 7
#define SSHORT 8
#define SLONG 9
#define SRATIONAL 10

#define FLOAT 11
#define DOUBLE 12

#define ImageWidth 256
#define ImageLength 257
#define BitsPerSample 258
#define Compression 259
#define PhotometricInterpretation 262
#define StripOffsets 273
#define RowsPerStrip 278
#define StripByteCounts 279
#define XResolution 282
#define YResolution 283
#define ResolutionUnit 296
#define ColorMap 320

static void
ifd_add_entry(struct ifd *ifd, int tag, int type, ...)
{
    va_list ap;
    struct directory_entry *current_entry;

    va_start(ap, type);

    current_entry = &ifd->entries[ifd->count];
    ifd->count++;

    /* default values */
    current_entry->tag = tag;
    current_entry->type = type;
    current_entry->count = 1;

    switch(type)
    {
        case SHORT:
            current_entry->value_offset_16 = (int16_t)va_arg(ap, int32_t);
            break;
        case LONG:
            current_entry->value_offset = va_arg(ap, int32_t);
            break;
        case -1:
            current_entry->type = va_arg(ap, int32_t);
            current_entry->count = va_arg(ap, int32_t);
            current_entry->value_offset = va_arg(ap, int32_t);
            break;
        default:
            gui_fatal("unknown tag type");
            break;
    }
    va_end(ap);
}

static void
dump_indirect_pm(PixMap *pm)
{
    PixMap *tiff_pm;

    void *fbuf;
    int fbuf_size;
    int row_bytes;
    int width, height;
    int bpp;

    struct header *header;
    int header_size;

    static const int n_ifd_entries = 10;
    struct ifd *ifd;
    int ifd_size;

    int8_t *tif;
    int tif_size;

    int32_t *strip_offsets;
    int strip_offsets_size;
    int strip_offsets_offset;

    int32_t *strip_byte_counts;
    int strip_byte_counts_size;
    int strip_byte_counts_offset;

    int16_t *color_map;
    int color_map_size;
    int color_map_offset;

    int i;
    int retval;
    int fd;

    Str255 temp_file_name;

    TEMP_ALLOC_DECL(temp_fbuf_bits);
    TEMP_ALLOC_DECL(temp_tif_bits);

    height = RECT_HEIGHT(&pm->bounds);
    width = RECT_WIDTH(&pm->bounds);

    bpp = pm->pixelSize;

    if(bpp != 8 && bpp != 4)
    {
        tiff_pm = (PixMap *)alloca(sizeof *tiff_pm);

        /* compute the bpp of the pixmap that will be converted to a tif */
        bpp = bpp <= 4 ? 4 : 8;

        fbuf_size = width * height;
        TEMP_ALLOC_ALLOCATE(fbuf, temp_fbuf_bits, fbuf_size);
        row_bytes = (width * bpp + 31) / 32 * 4;

        tiff_pm->baseAddr = (Ptr)fbuf;
        tiff_pm->rowBytes = row_bytes | PIXMAP_DEFAULT_ROW_BYTES;
        tiff_pm->bounds = pm->bounds;

        pixmap_set_pixel_fields(tiff_pm, bpp);

        tiff_pm->pmTable = pm->pmTable;

        CopyBits((BitMap *)pm, (BitMap *)tiff_pm,
                 &pm->bounds, &tiff_pm->bounds,
                 srcCopy, nullptr);
    }
    else
    {
        tiff_pm = pm;
        fbuf = BITMAP_BASEADDR(pm);
        row_bytes = BITMAP_ROWBYTES(pm);
        fbuf_size = height * row_bytes;
    }

    header_size = sizeof *header;
    ifd_size = sizeof *ifd + (n_ifd_entries - 1) * sizeof *ifd->entries
        + 4;    // offset to next TIFF directory, remains 0

    color_map_size = 3 * (1 << bpp) * sizeof *color_map;
    color_map_offset = header_size + ifd_size;

    strip_offsets_size = sizeof *strip_offsets * height;
    strip_offsets_offset = color_map_offset + color_map_size;

    strip_byte_counts_size = sizeof *strip_byte_counts * height;
    strip_byte_counts_offset = strip_offsets_offset + strip_offsets_size;

    tif_size = (header_size + ifd_size + color_map_size
                + strip_offsets_size + strip_byte_counts_size);
    TEMP_ALLOC_ALLOCATE(tif, temp_tif_bits, tif_size);

    header = (struct header *)&tif[0];
    ifd = (struct ifd *)&tif[header_size];
    color_map = (int16_t *)&tif[color_map_offset];
    strip_offsets = (int32_t *)&tif[strip_offsets_offset];
    strip_byte_counts = (int32_t *)&tif[strip_byte_counts_offset];

#if defined(LITTLEENDIAN)
    header->byte_order = II_little_endian;
#else
    header->byte_order = MM_big_endian;
#endif

    header->magic_number = 42;
    header->ifd_offset = header_size;

    memset(ifd, 0, ifd_size);

    /* NOTE: order matters here, the ifd directory entries must be
     sorted by tag */
    /* NOTE: if you change the number of entries here; make sure to
     update `n_ifd_entries' appropriately */
    ifd_add_entry(ifd, ImageWidth, SHORT, width);
    ifd_add_entry(ifd, ImageLength, SHORT, height);
    ifd_add_entry(ifd, BitsPerSample, SHORT, bpp);
    ifd_add_entry(ifd, Compression, SHORT, 1);
    ifd_add_entry(ifd, PhotometricInterpretation, SHORT, 3);
    ifd_add_entry(ifd, StripOffsets, -1,
                  LONG, height,
                  strip_offsets_offset);
    ifd_add_entry(ifd, RowsPerStrip, SHORT, 1);
    ifd_add_entry(ifd, StripByteCounts, -1,
                  LONG, height, strip_byte_counts_offset);

#if 0
  ifd_add_entry (ifd, XResolution,		RATIONAL, 1, 1);
  ifd_add_entry (ifd, YResolution,		RATIONAL, 1, 1);
#endif
    ifd_add_entry(ifd, ResolutionUnit, SHORT, 1);
    ifd_add_entry(ifd, ColorMap, -1,
                  SHORT, 3 * (1 << bpp), color_map_offset);

    gui_assert(ifd->count == n_ifd_entries);

    {
        ColorSpec *color_table;
        int color_table_size;

        memset(color_map, 0xFF, color_map_size);

        color_table_size = CTAB_SIZE(tiff_pm->pmTable);
        color_table = CTAB_TABLE(tiff_pm->pmTable);

        for(i = 0; i <= color_table_size; i++)
        {
            color_map[i] = color_table[i].rgb.red;
            color_map[i + (1 << bpp)] = color_table[i].rgb.green;
            color_map[i + (2 << bpp)] = color_table[i].rgb.blue;
        }
    }

    for(i = 0; i < height; i++)
        strip_offsets[i] = tif_size + row_bytes * i;

    for(i = 0; i < height; i++)
        strip_byte_counts[i] = row_bytes;

    /* now open up a file and write this sucker out */
    if(!unique_file_name(ROMlib_ScreenDumpFile.c_str(), "excscrn*.tif",
                         temp_file_name))
        return;

    fd = open((char *)temp_file_name + 1,
               O_CREAT | O_TRUNC | O_WRONLY | O_BINARY, 0666);
    if(fd == -1)
    {
        warning_errno("open `%s' failed", temp_file_name + 1);
        return;
    }

    retval = write(fd, tif, tif_size);
    if(retval == -1 || retval != tif_size)
    {
        warning_errno("`write (..., tif, ...)' failed");
        goto done;
    }

    retval = write(fd, fbuf, fbuf_size);
    if(retval == -1 || retval != fbuf_size)
    {
        warning_errno("`write (..., fbuf, ...)' failed");
        goto done;
    }

done:
    close(fd);
}

static void
dump_direct_pm(PixMap *pm)
{
    /* ### fix this! */
    warning_unimplemented("can't dump direct pixel pixmap");
}

typedef void (*dump_fn_t)(PixMap *);

dump_fn_t dump_fns[] = {
    dump_indirect_pm, dump_indirect_pm,
    dump_indirect_pm, dump_indirect_pm,
    dump_direct_pm, dump_direct_pm,
};

void Executor::do_dump_screen(void)
{
    GDHandle gd;
    PixMapHandle gd_pmh;

    gd = LM(MainDevice);
    gd_pmh = GD_PMAP(gd);

    HLockGuard guard(gd_pmh);
    PixMap *gd_pm;
    int log2_bpp;

    gd_pm = *gd_pmh;
    log2_bpp = ROMlib_log2[gd_pm->pixelSize];

    (*dump_fns[log2_bpp])(gd_pm);
}
<|endoftext|>