<commit_before>/**
 * Copyright © 2017 INFN Torino - INDIGO-DataCloud
 *
 * 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.
 */
#include "RPCManager.h"

#include <fcntl.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <string.h>
#include <sys/signal.h>
#include <sys/socket.h>
#include <unistd.h>
#include <cerrno>
#include <cstring>
#include <iostream>
#include <xmlrpc-c/registry.hpp>
#include <xmlrpc-c/server_abyss.hpp>

#include "Fass.h"
#include "FassLog.h"
#include "RequestSystem.h"
#include "RequestOneProxy.h"
#include "Request.h"

RPCManager::RPCManager(
        const string& _one_endpoint,
        const string& _port,
//        int _port,
        int _max_conn,
        int _max_conn_backlog,
        int _keepalive_timeout,
        int _keepalive_max_conn,
        int _timeout,
        const string _xml_log_file,
        const string call_log_format,
        const string _listen_address,
        int _message_size):
            one_endpoint(_one_endpoint),
            port(_port),
            socket_fd(-1),
            max_conn(_max_conn),
            max_conn_backlog(_max_conn_backlog),
            keepalive_timeout(_keepalive_timeout),
            keepalive_max_conn(_keepalive_max_conn),
            timeout(_timeout),
            xml_log_file(_xml_log_file),
            listen_address(_listen_address),
            message_size(_message_size) {
    Request::set_call_log_format(call_log_format);

    xmlrpc_limit_set(XMLRPC_XML_SIZE_LIMIT_ID, message_size);

    /// No Action Manager class, by now. Think if needed in the future
    // am.addListener(this);
}

extern "C" void * rm_xml_server_loop(void *arg) {
    RPCManager *    rm;

    if ( arg == 0 ) {
        return 0;
    }

    rm = static_cast<RPCManager *>(arg);
    /// Set cancel state for the thread
    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, 0);

    pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, 0);

    /// Start the server

    xmlrpc_c::serverAbyss::constrOpt opt = xmlrpc_c::serverAbyss::constrOpt();

    opt.registryP(&rm->RPCManagerRegistry);
    opt.keepaliveTimeout(rm->keepalive_timeout);
    opt.keepaliveMaxConn(rm->keepalive_max_conn);
    opt.timeout(rm->timeout);
    opt.socketFd(rm->socket_fd);

    if (!rm->xml_log_file.empty()) {
        opt.logFileName(rm->xml_log_file);
    }

    opt.maxConn(rm->max_conn);
    opt.maxConnBacklog(rm->max_conn_backlog);

    rm->AbyssServer = new xmlrpc_c::serverAbyss(opt);

    rm->AbyssServer->run();

    return 0;
}

void RPCManager::register_xml_methods(){
    // Fass& fass = Fass::instance();

    /// methods go here
    // TODO(valzacc or svallero): new methods

    /// System Methods
    xmlrpc_c::methodPtr system_version(new SystemVersion());
    /// ONE Proxy Methods
    xmlrpc_c::defaultMethodPtr one_proxy(new RequestOneProxy(one_endpoint,
                                                             message_size,
                                                             timeout));
    // add to registry
    RPCManagerRegistry.addMethod("fass.system.version", system_version);
    RPCManagerRegistry.setDefaultMethod(one_proxy);
}

bool RPCManager::start(){
    // cout << "Starting RPC Manager..." << endl;

    pthread_attr_t  pattr;
    ostringstream   oss;

    FassLog::log("RPCM", Log::INFO, "Starting RPC Manager...");

    int rc = setup_socket();

    if ( rc != 0 ) {
        return false;
    }

    register_xml_methods();

    // Action loop
    // pthread_attr_init (&pattr);
    // pthread_attr_setdetachstate (&pattr, PTHREAD_CREATE_JOINABLE);

    // pthread_create(&rm_thread,&pattr,rm_action_loop,(void *)this);

    /// Server loop
    pthread_attr_init(&pattr);
    pthread_attr_setdetachstate(&pattr, PTHREAD_CREATE_JOINABLE);

    oss << "Starting XML-RPC server, port " << port << " ...";
    FassLog::log("RPCM", Log::INFO, oss);

    pthread_create(&rm_xml_server_thread, &pattr, rm_xml_server_loop,
                   reinterpret_cast<void *>(this));

    return true;
}

bool RPCManager::setup_socket() {
    int                 rc;
    int                 yes = 1;
    struct sockaddr_in  rm_addr;

    socket_fd = socket(AF_INET, SOCK_STREAM, 0);

    if ( socket_fd == -1 ) {
        ostringstream oss;

        oss << "Cannot open server socket: " << strerror(errno);
        FassLog::log("RPCM", Log::ERROR, oss);

        return false;
    }

    rc = setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));

    if ( rc == -1 ) {
        ostringstream oss;

        oss << "Cannot set socket options: " << strerror(errno);
        FassLog::log("RPCM", Log::ERROR, oss);

        close(socket_fd);

        return false;
    }
    fcntl(socket_fd, F_SETFD, FD_CLOEXEC);  // set close-on-exec
    rm_addr.sin_family      = AF_INET;
    // converts the unsigned short integer hostshort
    // from host byte order to network byte order
    rm_addr.sin_port        = htons(atoi(port.c_str()));

    // converts the Internet host address cp
    // from IPv4 numbers-and-dots notation
    // into binary data in network byte order
    rc = inet_aton(listen_address.c_str(), &rm_addr.sin_addr);

    if ( rc == 0 ) {
        ostringstream oss;

        oss << "Invalid listen address: " << listen_address;
        FassLog::log("RPCM", Log::ERROR, oss);

        close(socket_fd);

        return false;
    }

    rc = bind(socket_fd, (struct sockaddr *) &(rm_addr), sizeof(struct sockaddr));

    if ( rc == -1) {
        ostringstream oss;

        oss << "Cannot bind to " << listen_address
            << ":" << port << " : " << strerror(errno);
        FassLog::log("RPCM", Log::ERROR, oss);

        close(socket_fd);

        return false;
    }

    return 0;
}
<commit_msg>Update RPCManager.cc<commit_after>/**
 * Copyright © 2017 INFN Torino - INDIGO-DataCloud
 *
 * 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.
 */
#include "RPCManager.h"

#include <fcntl.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <string.h>
#include <sys/signal.h>
#include <sys/socket.h>
#include <unistd.h>
#include <cerrno>
#include <cstring>
#include <iostream>
#include <xmlrpc-c/registry.hpp>
#include <xmlrpc-c/server_abyss.hpp>

#include "Fass.h"
#include "FassLog.h"
#include "RequestSystem.h"
#include "RequestOneProxy.h"
#include "Request.h"

RPCManager::RPCManager(
        const string& _one_endpoint,
        const string& _port,
//        int _port,
        int _max_conn,
        int _max_conn_backlog,
        int _keepalive_timeout,
        int _keepalive_max_conn,
        int _timeout,
        const string _xml_log_file,
        const string call_log_format,
        const string _listen_address,
        int _message_size):
            one_endpoint(_one_endpoint),
            port(_port),
            socket_fd(-1),
            max_conn(_max_conn),
            max_conn_backlog(_max_conn_backlog),
            keepalive_timeout(_keepalive_timeout),
            keepalive_max_conn(_keepalive_max_conn),
            timeout(_timeout),
            xml_log_file(_xml_log_file),
            listen_address(_listen_address),
            message_size(_message_size) {
    Request::set_call_log_format(call_log_format);

    xmlrpc_limit_set(XMLRPC_XML_SIZE_LIMIT_ID, message_size);

    /// No Action Manager class, by now. Think if needed in the future
    // am.addListener(this);
}

extern "C" void * rm_xml_server_loop(void *arg) {
    RPCManager *    rm;

    if ( arg == 0 ) {
        return 0;
    }

    rm = static_cast<RPCManager *>(arg);
    /// Set cancel state for the thread
    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, 0);

    pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, 0);

    /// Start the server

    xmlrpc_c::serverAbyss::constrOpt opt = xmlrpc_c::serverAbyss::constrOpt();

    opt.registryP(&rm->RPCManagerRegistry);
    opt.keepaliveTimeout(rm->keepalive_timeout);
    opt.keepaliveMaxConn(rm->keepalive_max_conn);
    opt.timeout(rm->timeout);
    opt.socketFd(rm->socket_fd);

    if (!rm->xml_log_file.empty()) {
        opt.logFileName(rm->xml_log_file);
    }

    opt.maxConn(rm->max_conn);
    opt.maxConnBacklog(rm->max_conn_backlog);

    rm->AbyssServer = new xmlrpc_c::serverAbyss(opt);

    rm->AbyssServer->run();

    return 0;
}

void RPCManager::register_xml_methods() {
    // Fass& fass = Fass::instance();

    /// methods go here
    // TODO(valzacc or svallero): new methods

    /// System Methods
    xmlrpc_c::methodPtr system_version(new SystemVersion());
    /// ONE Proxy Methods
    xmlrpc_c::defaultMethodPtr one_proxy(new RequestOneProxy(one_endpoint,
                                                             message_size,
                                                             timeout));
    // add to registry
    RPCManagerRegistry.addMethod("fass.system.version", system_version);
    RPCManagerRegistry.setDefaultMethod(one_proxy);
}

bool RPCManager::start() {
    // cout << "Starting RPC Manager..." << endl;

    pthread_attr_t  pattr;
    ostringstream   oss;

    FassLog::log("RPCM", Log::INFO, "Starting RPC Manager...");

    int rc = setup_socket();

    if ( rc != 0 ) {
        return false;
    }

    register_xml_methods();

    // Action loop
    // pthread_attr_init (&pattr);
    // pthread_attr_setdetachstate (&pattr, PTHREAD_CREATE_JOINABLE);

    // pthread_create(&rm_thread,&pattr,rm_action_loop,(void *)this);

    /// Server loop
    pthread_attr_init(&pattr);
    pthread_attr_setdetachstate(&pattr, PTHREAD_CREATE_JOINABLE);

    oss << "Starting XML-RPC server, port " << port << " ...";
    FassLog::log("RPCM", Log::INFO, oss);

    pthread_create(&rm_xml_server_thread, &pattr, rm_xml_server_loop,
                   reinterpret_cast<void *>(this));

    return true;
}

bool RPCManager::setup_socket() {
    int                 rc;
    int                 yes = 1;
    struct sockaddr_in  rm_addr;

    socket_fd = socket(AF_INET, SOCK_STREAM, 0);

    if ( socket_fd == -1 ) {
        ostringstream oss;

        oss << "Cannot open server socket: " << strerror(errno);
        FassLog::log("RPCM", Log::ERROR, oss);

        return false;
    }

    rc = setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));

    if ( rc == -1 ) {
        ostringstream oss;

        oss << "Cannot set socket options: " << strerror(errno);
        FassLog::log("RPCM", Log::ERROR, oss);

        close(socket_fd);

        return false;
    }
    fcntl(socket_fd, F_SETFD, FD_CLOEXEC);  // set close-on-exec
    rm_addr.sin_family      = AF_INET;
    // converts the unsigned short integer hostshort
    // from host byte order to network byte order
    rm_addr.sin_port        = htons(atoi(port.c_str()));

    // converts the Internet host address cp
    // from IPv4 numbers-and-dots notation
    // into binary data in network byte order
    rc = inet_aton(listen_address.c_str(), &rm_addr.sin_addr);

    if ( rc == 0 ) {
        ostringstream oss;

        oss << "Invalid listen address: " << listen_address;
        FassLog::log("RPCM", Log::ERROR, oss);

        close(socket_fd);

        return false;
    }

    rc = bind(socket_fd, (struct sockaddr *) &(rm_addr),
              sizeof(struct sockaddr));

    if ( rc == -1) {
        ostringstream oss;
        oss << "Cannot bind to " << listen_address
            << ":" << port << " : " << strerror(errno);
        FassLog::log("RPCM", Log::ERROR, oss);

        close(socket_fd);

        return false;
    }

    return 0;
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2017 ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla 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.
 *
 * Scylla 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 Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <boost/range/adaptor/transformed.hpp>
#include <boost/range/algorithm/copy.hpp>

#include "core/sstring.hh"
#include "core/thread.hh"

#include "database.hh"
#include "mutation_reader.hh"
#include "schema_builder.hh"
#include "partition_slice_builder.hh"
#include "tmpdir.hh"
#include "sstable_mutation_readers.hh"
#include "cell_locking.hh"

#include "tests/test-utils.hh"
#include "tests/mutation_assertions.hh"
#include "tests/mutation_reader_assertions.hh"
#include "tests/result_set_assertions.hh"
#include "tests/simple_schema.hh"
#include "tests/sstable_utils.hh"
#include "tests/sstable_test.hh"

thread_local disk_error_signal_type commit_error;
thread_local disk_error_signal_type general_disk_error;

struct sst_factory {
    schema_ptr s;
    sstring path;
    unsigned gen;
    int level;

    sst_factory(schema_ptr s, const sstring& path, unsigned gen, int level)
        : s(s)
        , path(path)
        , gen(gen)
        , level(level)
    {}

    sstables::shared_sstable operator()() {
        auto sst = sstables::make_sstable(s, path, gen, sstables::sstable::version_types::la, sstables::sstable::format_types::big);
        sst->set_unshared();

        //TODO set sstable level, to make the test more interesting

        return sst;
    }
};

SEASTAR_TEST_CASE(combined_mutation_reader_test) {
    return seastar::async([] {
        //logging::logger_registry().set_logger_level("database", logging::log_level::trace);

        simple_schema s;

        const auto pkeys = s.make_pkeys(4);
        const auto ckeys = s.make_ckeys(4);

        std::vector<mutation> base_mutations = boost::copy_range<std::vector<mutation>>(
                pkeys | boost::adaptors::transformed([&s](const auto& k) { return mutation(k, s.schema()); }));

        // Data layout:
        //   d[xx]
        // b[xx][xx]c
        // a[x    x]

        int i{0};

        // sstable d
        std::vector<mutation> table_d_mutations;

        i = 1;
        table_d_mutations.emplace_back(base_mutations[i]);
        s.add_row(table_d_mutations.back(), ckeys[i], sprint("val_d_%i", i));

        i = 2;
        table_d_mutations.emplace_back(base_mutations[i]);
        s.add_row(table_d_mutations.back(), ckeys[i], sprint("val_d_%i", i));
        const auto t_static_row = s.add_static_row(table_d_mutations.back(), sprint("%i_static_val", i));

        // sstable b
        std::vector<mutation> table_b_mutations;

        i = 0;
        table_b_mutations.emplace_back(base_mutations[i]);
        s.add_row(table_b_mutations.back(), ckeys[i], sprint("val_b_%i", i));

        i = 1;
        table_b_mutations.emplace_back(base_mutations[i]);
        s.add_row(table_b_mutations.back(), ckeys[i], sprint("val_b_%i", i));

        // sstable c
        std::vector<mutation> table_c_mutations;

        i = 2;
        table_c_mutations.emplace_back(base_mutations[i]);
        const auto t_row = s.add_row(table_c_mutations.back(), ckeys[i], sprint("val_c_%i", i));

        i = 3;
        table_c_mutations.emplace_back(base_mutations[i]);
        s.add_row(table_c_mutations.back(), ckeys[i], sprint("val_c_%i", i));

        // sstable a
        std::vector<mutation> table_a_mutations;

        i = 0;
        table_a_mutations.emplace_back(base_mutations[i]);
        s.add_row(table_a_mutations.back(), ckeys[i], sprint("val_a_%i", i));

        i = 3;
        table_a_mutations.emplace_back(base_mutations[i]);
        s.add_row(table_a_mutations.back(), ckeys[i], sprint("val_a_%i", i));

        auto tmp = make_lw_shared<tmpdir>();

        std::cout << tmp->path << std::endl;

        unsigned gen{0};

        std::vector<sstables::shared_sstable> tables = {
                make_sstable_containing(sst_factory(s.schema(), tmp->path, gen++, 0), table_a_mutations),
                make_sstable_containing(sst_factory(s.schema(), tmp->path, gen++, 1), table_b_mutations),
                make_sstable_containing(sst_factory(s.schema(), tmp->path, gen++, 1), table_c_mutations),
                make_sstable_containing(sst_factory(s.schema(), tmp->path, gen++, 2), table_d_mutations)
        };

        auto cs = sstables::make_compaction_strategy(sstables::compaction_strategy_type::leveled, {});
        auto sstables = make_lw_shared<sstables::sstable_set>(cs.make_sstable_set(s.schema()));

        std::vector<mutation_reader> sstable_mutation_readers;

        for (auto table : tables) {
            sstables->insert(table);

            sstable_mutation_readers.emplace_back(make_mutation_reader<sstable_range_wrapping_reader>(
                    table,
                    s.schema(),
                    query::full_partition_range,
                    query::full_slice,
                    seastar::default_priority_class(),
                    streamed_mutation::forwarding::no,
                    ::mutation_reader::forwarding::yes));
        }

        auto list_reader = make_combined_reader(std::move(sstable_mutation_readers), ::mutation_reader::forwarding::yes);

        auto incremental_reader = make_range_sstable_reader(
                s.schema(),
                sstables,
                query::full_partition_range,
                query::full_slice,
                seastar::default_priority_class(),
                nullptr,
                streamed_mutation::forwarding::no,
                ::mutation_reader::forwarding::yes);

        // merge c[0] with d[1]
        i = 2;
        auto c_d_merged = mutation(pkeys[i], s.schema());
        s.add_row(c_d_merged, ckeys[i], sprint("val_c_%i", i), t_row);
        s.add_static_row(c_d_merged, sprint("%i_static_val", i), t_static_row);

        assert_that(std::move(list_reader))
            .produces(table_a_mutations.front())
            .produces(table_b_mutations[1])
            .produces(c_d_merged)
            .produces(table_a_mutations.back());

        assert_that(std::move(incremental_reader))
            .produces(table_a_mutations.front())
            .produces(table_b_mutations[1])
            .produces(c_d_merged)
            .produces(table_a_mutations.back());
    });
};
<commit_msg>combined_mutation_reader_test: remove leftover debug logging<commit_after>/*
 * Copyright (C) 2017 ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla 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.
 *
 * Scylla 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 Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <boost/range/adaptor/transformed.hpp>
#include <boost/range/algorithm/copy.hpp>

#include "core/sstring.hh"
#include "core/thread.hh"

#include "database.hh"
#include "mutation_reader.hh"
#include "schema_builder.hh"
#include "partition_slice_builder.hh"
#include "tmpdir.hh"
#include "sstable_mutation_readers.hh"
#include "cell_locking.hh"

#include "tests/test-utils.hh"
#include "tests/mutation_assertions.hh"
#include "tests/mutation_reader_assertions.hh"
#include "tests/result_set_assertions.hh"
#include "tests/simple_schema.hh"
#include "tests/sstable_utils.hh"
#include "tests/sstable_test.hh"

thread_local disk_error_signal_type commit_error;
thread_local disk_error_signal_type general_disk_error;

struct sst_factory {
    schema_ptr s;
    sstring path;
    unsigned gen;
    int level;

    sst_factory(schema_ptr s, const sstring& path, unsigned gen, int level)
        : s(s)
        , path(path)
        , gen(gen)
        , level(level)
    {}

    sstables::shared_sstable operator()() {
        auto sst = sstables::make_sstable(s, path, gen, sstables::sstable::version_types::la, sstables::sstable::format_types::big);
        sst->set_unshared();

        //TODO set sstable level, to make the test more interesting

        return sst;
    }
};

SEASTAR_TEST_CASE(combined_mutation_reader_test) {
    return seastar::async([] {
        //logging::logger_registry().set_logger_level("database", logging::log_level::trace);

        simple_schema s;

        const auto pkeys = s.make_pkeys(4);
        const auto ckeys = s.make_ckeys(4);

        std::vector<mutation> base_mutations = boost::copy_range<std::vector<mutation>>(
                pkeys | boost::adaptors::transformed([&s](const auto& k) { return mutation(k, s.schema()); }));

        // Data layout:
        //   d[xx]
        // b[xx][xx]c
        // a[x    x]

        int i{0};

        // sstable d
        std::vector<mutation> table_d_mutations;

        i = 1;
        table_d_mutations.emplace_back(base_mutations[i]);
        s.add_row(table_d_mutations.back(), ckeys[i], sprint("val_d_%i", i));

        i = 2;
        table_d_mutations.emplace_back(base_mutations[i]);
        s.add_row(table_d_mutations.back(), ckeys[i], sprint("val_d_%i", i));
        const auto t_static_row = s.add_static_row(table_d_mutations.back(), sprint("%i_static_val", i));

        // sstable b
        std::vector<mutation> table_b_mutations;

        i = 0;
        table_b_mutations.emplace_back(base_mutations[i]);
        s.add_row(table_b_mutations.back(), ckeys[i], sprint("val_b_%i", i));

        i = 1;
        table_b_mutations.emplace_back(base_mutations[i]);
        s.add_row(table_b_mutations.back(), ckeys[i], sprint("val_b_%i", i));

        // sstable c
        std::vector<mutation> table_c_mutations;

        i = 2;
        table_c_mutations.emplace_back(base_mutations[i]);
        const auto t_row = s.add_row(table_c_mutations.back(), ckeys[i], sprint("val_c_%i", i));

        i = 3;
        table_c_mutations.emplace_back(base_mutations[i]);
        s.add_row(table_c_mutations.back(), ckeys[i], sprint("val_c_%i", i));

        // sstable a
        std::vector<mutation> table_a_mutations;

        i = 0;
        table_a_mutations.emplace_back(base_mutations[i]);
        s.add_row(table_a_mutations.back(), ckeys[i], sprint("val_a_%i", i));

        i = 3;
        table_a_mutations.emplace_back(base_mutations[i]);
        s.add_row(table_a_mutations.back(), ckeys[i], sprint("val_a_%i", i));

        auto tmp = make_lw_shared<tmpdir>();

        unsigned gen{0};

        std::vector<sstables::shared_sstable> tables = {
                make_sstable_containing(sst_factory(s.schema(), tmp->path, gen++, 0), table_a_mutations),
                make_sstable_containing(sst_factory(s.schema(), tmp->path, gen++, 1), table_b_mutations),
                make_sstable_containing(sst_factory(s.schema(), tmp->path, gen++, 1), table_c_mutations),
                make_sstable_containing(sst_factory(s.schema(), tmp->path, gen++, 2), table_d_mutations)
        };

        auto cs = sstables::make_compaction_strategy(sstables::compaction_strategy_type::leveled, {});
        auto sstables = make_lw_shared<sstables::sstable_set>(cs.make_sstable_set(s.schema()));

        std::vector<mutation_reader> sstable_mutation_readers;

        for (auto table : tables) {
            sstables->insert(table);

            sstable_mutation_readers.emplace_back(make_mutation_reader<sstable_range_wrapping_reader>(
                    table,
                    s.schema(),
                    query::full_partition_range,
                    query::full_slice,
                    seastar::default_priority_class(),
                    streamed_mutation::forwarding::no,
                    ::mutation_reader::forwarding::yes));
        }

        auto list_reader = make_combined_reader(std::move(sstable_mutation_readers), ::mutation_reader::forwarding::yes);

        auto incremental_reader = make_range_sstable_reader(
                s.schema(),
                sstables,
                query::full_partition_range,
                query::full_slice,
                seastar::default_priority_class(),
                nullptr,
                streamed_mutation::forwarding::no,
                ::mutation_reader::forwarding::yes);

        // merge c[0] with d[1]
        i = 2;
        auto c_d_merged = mutation(pkeys[i], s.schema());
        s.add_row(c_d_merged, ckeys[i], sprint("val_c_%i", i), t_row);
        s.add_static_row(c_d_merged, sprint("%i_static_val", i), t_static_row);

        assert_that(std::move(list_reader))
            .produces(table_a_mutations.front())
            .produces(table_b_mutations[1])
            .produces(c_d_merged)
            .produces(table_a_mutations.back());

        assert_that(std::move(incremental_reader))
            .produces(table_a_mutations.front())
            .produces(table_b_mutations[1])
            .produces(c_d_merged)
            .produces(table_a_mutations.back());
    });
};
<|endoftext|>


<commit_before>#include "config.h"

ConfigReader::ConfigReader(std::string filename, std::string filedir) {
	readConfig(filename, filedir);
}

void ConfigReader::readConfig(std::string filename, std::string filedir) {
	std::ifstream configFile;
	std::string absConfFile = filedir + "/" + filename;
	configFile.open(absConfFile.c_str());
	if (configFile.fail()) {
		std::perror("Config file does not exist or could not be opened");
		std::exit(0);
	}
	char configuration;
	int lineNumber = 1;
	std::string sectionType = "", sectionName = "", varName = "", currentValue = "", concatingVar = "";
	bool inBlock = false, typingSection = false, namingSection = false, escaped = false, escapedNow = false, commentable = true, writing = false, acceptVar = false, concatable = false, concatening = false;
	std::vector<std::string> includes;
	std::tr1::unordered_map<std::string, std::string> oneBlock;
	while (configFile.good()) {
		configuration = configFile.get();
		if (configuration == '\n')
			lineNumber++;

		if (!inBlock && sectionType == "")
			typingSection = true;

		if (commentable && configuration == '#') {
			while (configuration != '\n' && configFile.good()) {
				configuration = configFile.get(); // do nothing with it--ignore the line
			}
			lineNumber++; // count it as a line, since the \n won't reach the part of the loop where the line number increments
		} else if ((configuration == ' ' || configuration == '\t' || configuration == '\r' || configuration == '\n') && !writing) {
			// ignore whitespace that's not part of a string
		} else if (typingSection) {
			while (configuration != ' ' && configFile.good()) {
				sectionType += configuration;
				configuration = configFile.get();
			}
			typingSection = false;
			namingSection = true;
		} else if (namingSection) {
			while (configuration != ' ' && configuration != '{' && configuration != ';' && configFile.good()) {
				sectionName += configuration;
				configuration = configFile.get();
			}
			if (!configFile.good()) {
				std::ostringstream lineSS;
				lineSS << lineNumber;
				std::string message = "An error occurred reading a section name from the configuration file.  This error occurred on line " + lineSS.str();
				std::perror(message.c_str());
				std::exit(0);
			}
			namingSection = false;
			if (configuration == '{') { // handle this now since next iteration will handle the next character
				inBlock = true;
				acceptVar = true;
			}
			if (configuration == ';' && sectionType == "include")
				includes.push_back(sectionName);
		} else if (configuration == '{') {
			inBlock = true;
			acceptVar = true;
		} else if (configuration == '}' && !writing) {
			if (!inBlock) {
				std::ostringstream lineSS;
				lineSS << lineNumber;
				std::string message = "An end brace occurred outside a block before a corresponding opening brace existed in the configuration file.  The offending brace can be found on line " + lineSS.str();
				std::perror(message.c_str());
				std::exit(0);
			}
			inBlock = false;
			typingSection = true;
			if (sectionType == "server")
				serverConfig.insert(std::pair<std::string, std::tr1::unordered_map<std::string, std::string> > (sectionName, oneBlock));
			else if (sectionType == "serverconf")
				serverKeepConfig.insert(std::pair<std::string, std::tr1::unordered_map<std::string, std::string> > (sectionName, oneBlock));
			else if (sectionType == "module")
				modLoadConfig.insert(std::pair<std::string, std::tr1::unordered_map<std::string, std::string> > (sectionName, oneBlock));
			else if (sectionType == "moduleconf")
				modKeepConfig.insert(std::pair<std::string, std::tr1::unordered_map<std::string, std::string> > (sectionName, oneBlock));
			else {
				std::ostringstream lineSS;
				lineSS << lineNumber;
				std::string message = "An invalid block type was declared in the configuration file.  This block is of type " + sectionType + " and ends on line " + lineSS.str();
				std::perror(message.c_str());
				std::exit(0);
			}
			sectionType = "";
			sectionName = "";
			oneBlock.clear();
		} else if (configuration == '\\' && !escaped)
			escaped = escapedNow = true;
		else if (escaped && configuration == '"')
			currentValue += "\"";
		else if (!escaped && configuration == '"') {
			if (writing) {
				writing = false;
				commentable = true;
				concatable = true;
			} else {
				writing = true;
				commentable = false;
				concatable = false;
				concatening = false;
			}
		} else if (writing) {
			currentValue += configuration;
		} else if (configuration == '=') {
			acceptVar = false;
			concatening = true;
		} else if (!escaped && !writing && configuration == ';') { // parse the end of a statement
			if (!inBlock) {
				if (sectionType == "include")
					includes.push_back(sectionName);
				else {
					std::ostringstream lineSS;
					lineSS << lineNumber;
					std::string message = "An invalid semicolon was found in the configuration file on line " + lineSS.str();
					std::perror(message.c_str());
					std::exit(0);
				}
			} else {
				if (concatening)
					currentValue += oneBlock[concatingVar];
				oneBlock.insert(std::pair<std::string, std::string> (varName, currentValue));
			}
			varName = "";
			currentValue = "";
			concatingVar = "";
			acceptVar = true;
			concatable = false;
			concatening = false;
		} else if (acceptVar)
			varName += configuration;
		else if (concatable && configuration == '+') {
			concatable = false;
			concatening = true;
		} else if (concatening && configuration == '+') {
			concatening = false;
			concatable = true;
			currentValue += oneBlock[concatingVar];
			concatingVar = "";
		} else if (concatening)
			concatingVar += configuration;

		if (!escapedNow && escaped) {
			escaped = false;
		}
 		escapedNow = false;
	}
	configFile.close();
	for (unsigned int i = 0; i < includes.size(); i++)
		readConfig(includes[i], filedir);
}

std::tr1::unordered_map<std::string, std::tr1::unordered_map<std::string, std::string> > ConfigReader::getServerConfig(bool connecting) {
	if (connecting)
		return serverConfig;
	return serverKeepConfig;
}

std::tr1::unordered_map<std::string, std::tr1::unordered_map<std::string, std::string> > ConfigReader::getModConfig(bool loading) {
	if (loading)
		return modLoadConfig;
	return modKeepConfig;
}<commit_msg>Allow whitespace other than spaces to break section types and section names.<commit_after>#include "config.h"

ConfigReader::ConfigReader(std::string filename, std::string filedir) {
	readConfig(filename, filedir);
}

void ConfigReader::readConfig(std::string filename, std::string filedir) {
	std::ifstream configFile;
	std::string absConfFile = filedir + "/" + filename;
	configFile.open(absConfFile.c_str());
	if (configFile.fail()) {
		std::perror("Config file does not exist or could not be opened");
		std::exit(0);
	}
	char configuration;
	int lineNumber = 1;
	std::string sectionType = "", sectionName = "", varName = "", currentValue = "", concatingVar = "";
	bool inBlock = false, typingSection = false, namingSection = false, escaped = false, escapedNow = false, commentable = true, writing = false, acceptVar = false, concatable = false, concatening = false;
	std::vector<std::string> includes;
	std::tr1::unordered_map<std::string, std::string> oneBlock;
	while (configFile.good()) {
		configuration = configFile.get();
		if (configuration == '\n')
			lineNumber++;

		if (!inBlock && sectionType == "")
			typingSection = true;

		if (commentable && configuration == '#') {
			while (configuration != '\n' && configFile.good()) {
				configuration = configFile.get(); // do nothing with it--ignore the line
			}
			lineNumber++; // count it as a line, since the \n won't reach the part of the loop where the line number increments
		} else if ((configuration == ' ' || configuration == '\t' || configuration == '\r' || configuration == '\n') && !writing) {
			// ignore whitespace that's not part of a string
		} else if (typingSection) {
			while (configuration != ' ' && configuration != '\t' && configuration != '\r' && configuration != '\n' && configFile.good()) {
				sectionType += configuration;
				configuration = configFile.get();
			}
			typingSection = false;
			namingSection = true;
		} else if (namingSection) {
			while (configuration != ' ' && configuration != '\t' && configuration != '\r' && configuration != '\n' && configuration != '{' && configuration != ';' && configFile.good()) {
				sectionName += configuration;
				configuration = configFile.get();
			}
			if (!configFile.good()) {
				std::ostringstream lineSS;
				lineSS << lineNumber;
				std::string message = "An error occurred reading a section name from the configuration file.  This error occurred on line " + lineSS.str();
				std::perror(message.c_str());
				std::exit(0);
			}
			namingSection = false;
			if (configuration == '{') { // handle this now since next iteration will handle the next character
				inBlock = true;
				acceptVar = true;
			}
			if (configuration == ';' && sectionType == "include")
				includes.push_back(sectionName);
		} else if (configuration == '{') {
			inBlock = true;
			acceptVar = true;
		} else if (configuration == '}' && !writing) {
			if (!inBlock) {
				std::ostringstream lineSS;
				lineSS << lineNumber;
				std::string message = "An end brace occurred outside a block before a corresponding opening brace existed in the configuration file.  The offending brace can be found on line " + lineSS.str();
				std::perror(message.c_str());
				std::exit(0);
			}
			inBlock = false;
			typingSection = true;
			if (sectionType == "server")
				serverConfig.insert(std::pair<std::string, std::tr1::unordered_map<std::string, std::string> > (sectionName, oneBlock));
			else if (sectionType == "serverconf")
				serverKeepConfig.insert(std::pair<std::string, std::tr1::unordered_map<std::string, std::string> > (sectionName, oneBlock));
			else if (sectionType == "module")
				modLoadConfig.insert(std::pair<std::string, std::tr1::unordered_map<std::string, std::string> > (sectionName, oneBlock));
			else if (sectionType == "moduleconf")
				modKeepConfig.insert(std::pair<std::string, std::tr1::unordered_map<std::string, std::string> > (sectionName, oneBlock));
			else {
				std::ostringstream lineSS;
				lineSS << lineNumber;
				std::string message = "An invalid block type was declared in the configuration file.  This block is of type " + sectionType + " and ends on line " + lineSS.str();
				std::perror(message.c_str());
				std::exit(0);
			}
			sectionType = "";
			sectionName = "";
			oneBlock.clear();
		} else if (configuration == '\\' && !escaped)
			escaped = escapedNow = true;
		else if (escaped && configuration == '"')
			currentValue += "\"";
		else if (!escaped && configuration == '"') {
			if (writing) {
				writing = false;
				commentable = true;
				concatable = true;
			} else {
				writing = true;
				commentable = false;
				concatable = false;
				concatening = false;
			}
		} else if (writing) {
			currentValue += configuration;
		} else if (configuration == '=') {
			acceptVar = false;
			concatening = true;
		} else if (!escaped && !writing && configuration == ';') { // parse the end of a statement
			if (!inBlock) {
				if (sectionType == "include")
					includes.push_back(sectionName);
				else {
					std::ostringstream lineSS;
					lineSS << lineNumber;
					std::string message = "An invalid semicolon was found in the configuration file on line " + lineSS.str();
					std::perror(message.c_str());
					std::exit(0);
				}
			} else {
				if (concatening)
					currentValue += oneBlock[concatingVar];
				oneBlock.insert(std::pair<std::string, std::string> (varName, currentValue));
			}
			varName = "";
			currentValue = "";
			concatingVar = "";
			acceptVar = true;
			concatable = false;
			concatening = false;
		} else if (acceptVar)
			varName += configuration;
		else if (concatable && configuration == '+') {
			concatable = false;
			concatening = true;
		} else if (concatening && configuration == '+') {
			concatening = false;
			concatable = true;
			currentValue += oneBlock[concatingVar];
			concatingVar = "";
		} else if (concatening)
			concatingVar += configuration;

		if (!escapedNow && escaped) {
			escaped = false;
		}
 		escapedNow = false;
	}
	configFile.close();
	for (unsigned int i = 0; i < includes.size(); i++)
		readConfig(includes[i], filedir);
}

std::tr1::unordered_map<std::string, std::tr1::unordered_map<std::string, std::string> > ConfigReader::getServerConfig(bool connecting) {
	if (connecting)
		return serverConfig;
	return serverKeepConfig;
}

std::tr1::unordered_map<std::string, std::tr1::unordered_map<std::string, std::string> > ConfigReader::getModConfig(bool loading) {
	if (loading)
		return modLoadConfig;
	return modKeepConfig;
}<|endoftext|>


<commit_before>// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.

#include "atom/common/crash_reporter/crash_reporter_win.h"

#include <string>

#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/memory/singleton.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "content/public/common/result_codes.h"
#include "gin/public/debug.h"
#include "sandbox/win/src/nt_internals.h"

#pragma intrinsic(_AddressOfReturnAddress)
#pragma intrinsic(_ReturnAddress)

#ifdef _WIN64
// See http://msdn.microsoft.com/en-us/library/ddssxxy8.aspx
typedef struct _UNWIND_INFO {
  unsigned char Version : 3;
  unsigned char Flags : 5;
  unsigned char SizeOfProlog;
  unsigned char CountOfCodes;
  unsigned char FrameRegister : 4;
  unsigned char FrameOffset : 4;
  ULONG ExceptionHandler;
} UNWIND_INFO, *PUNWIND_INFO;
#endif

namespace crash_reporter {

namespace {

// Minidump with stacks, PEB, TEB, and unloaded module list.
const MINIDUMP_TYPE kSmallDumpType = static_cast<MINIDUMP_TYPE>(
    MiniDumpWithProcessThreadData |  // Get PEB and TEB.
    MiniDumpWithUnloadedModules);  // Get unloaded modules when available.

const wchar_t kWaitEventFormat[] = L"$1CrashServiceWaitEvent";
const wchar_t kPipeNameFormat[] = L"\\\\.\\pipe\\$1 Crash Service";

typedef NTSTATUS (WINAPI* NtTerminateProcessPtr)(HANDLE ProcessHandle,
                                                 NTSTATUS ExitStatus);
char* g_real_terminate_process_stub = NULL;

void TerminateProcessWithoutDump() {
  // Patched stub exists based on conditions (See InitCrashReporter).
  // As a side note this function also gets called from
  // WindowProcExceptionFilter.
  if (g_real_terminate_process_stub == NULL) {
    ::TerminateProcess(::GetCurrentProcess(), content::RESULT_CODE_KILLED);
  } else {
    NtTerminateProcessPtr real_terminate_proc =
        reinterpret_cast<NtTerminateProcessPtr>(
            static_cast<char*>(g_real_terminate_process_stub));
    real_terminate_proc(::GetCurrentProcess(), content::RESULT_CODE_KILLED);
  }
}

#ifdef _WIN64
int CrashForExceptionInNonABICompliantCodeRange(
    PEXCEPTION_RECORD ExceptionRecord,
    ULONG64 EstablisherFrame,
    PCONTEXT ContextRecord,
    PDISPATCHER_CONTEXT DispatcherContext) {
  EXCEPTION_POINTERS info = { ExceptionRecord, ContextRecord };
  if (!CrashReporter::GetInstance())
    return EXCEPTION_CONTINUE_SEARCH;
  return static_cast<CrashReporterWin*>(CrashReporter::GetInstance())->
      CrashForException(&info);
}

struct ExceptionHandlerRecord {
  RUNTIME_FUNCTION runtime_function;
  UNWIND_INFO unwind_info;
  unsigned char thunk[12];
};

void RegisterNonABICompliantCodeRange(void* start, size_t size_in_bytes) {
  ExceptionHandlerRecord* record =
      reinterpret_cast<ExceptionHandlerRecord*>(start);

  // We assume that the first page of the code range is executable and
  // committed and reserved for breakpad. What could possibly go wrong?

  // All addresses are 32bit relative offsets to start.
  record->runtime_function.BeginAddress = 0;
  record->runtime_function.EndAddress =
      base::checked_cast<DWORD>(size_in_bytes);
  record->runtime_function.UnwindData =
      offsetof(ExceptionHandlerRecord, unwind_info);

  // Create unwind info that only specifies an exception handler.
  record->unwind_info.Version = 1;
  record->unwind_info.Flags = UNW_FLAG_EHANDLER;
  record->unwind_info.SizeOfProlog = 0;
  record->unwind_info.CountOfCodes = 0;
  record->unwind_info.FrameRegister = 0;
  record->unwind_info.FrameOffset = 0;
  record->unwind_info.ExceptionHandler =
      offsetof(ExceptionHandlerRecord, thunk);

  // Hardcoded thunk.
  // mov imm64, rax
  record->thunk[0] = 0x48;
  record->thunk[1] = 0xb8;
  void* handler = &CrashForExceptionInNonABICompliantCodeRange;
  memcpy(&record->thunk[2], &handler, 8);

  // jmp rax
  record->thunk[10] = 0xff;
  record->thunk[11] = 0xe0;

  // Protect reserved page against modifications.
  DWORD old_protect;
  CHECK(VirtualProtect(
      start, sizeof(ExceptionHandlerRecord), PAGE_EXECUTE_READ, &old_protect));
  CHECK(RtlAddFunctionTable(
      &record->runtime_function, 1, reinterpret_cast<DWORD64>(start)));
}

void UnregisterNonABICompliantCodeRange(void* start) {
  ExceptionHandlerRecord* record =
      reinterpret_cast<ExceptionHandlerRecord*>(start);

  CHECK(RtlDeleteFunctionTable(&record->runtime_function));
}
#endif  // _WIN64

}  // namespace

CrashReporterWin::CrashReporterWin() {
}

CrashReporterWin::~CrashReporterWin() {
}

void CrashReporterWin::InitBreakpad(const std::string& product_name,
                                    const std::string& version,
                                    const std::string& company_name,
                                    const std::string& submit_url,
                                    bool auto_submit,
                                    bool skip_system_crash_handler) {
  skip_system_crash_handler_ = skip_system_crash_handler;

  base::FilePath temp_dir;
  if (!base::GetTempDir(&temp_dir)) {
    LOG(ERROR) << "Cannot get temp directory";
    return;
  }

  base::string16 pipe_name = ReplaceStringPlaceholders(
      kPipeNameFormat, base::UTF8ToUTF16(product_name), NULL);
  base::string16 wait_name = ReplaceStringPlaceholders(
      kWaitEventFormat, base::UTF8ToUTF16(product_name), NULL);

  // Wait until the crash service is started.
  HANDLE wait_event = ::CreateEventW(NULL, TRUE, FALSE, wait_name.c_str());
  if (wait_event != NULL) {
    WaitForSingleObject(wait_event, 1000);
    CloseHandle(wait_event);
  }

  // ExceptionHandler() attaches our handler and ~ExceptionHandler() detaches
  // it, so we must explicitly reset *before* we instantiate our new handler
  // to allow any previous handler to detach in the correct order.
  breakpad_.reset();

  breakpad_.reset(new google_breakpad::ExceptionHandler(
      temp_dir.value(),
      FilterCallback,
      MinidumpCallback,
      this,
      google_breakpad::ExceptionHandler::HANDLER_ALL,
      kSmallDumpType,
      pipe_name.c_str(),
      GetCustomInfo(product_name, version, company_name)));

  if (!breakpad_->IsOutOfProcess())
    LOG(ERROR) << "Cannot initialize out-of-process crash handler";

#ifdef _WIN64
  // Hook up V8 to breakpad.
  {
    // gin::Debug::SetCodeRangeCreatedCallback only runs the callback when
    // Isolate is just created, so we have to manually run following code here.
    void* code_range = nullptr;
    size_t size = 0;
    v8::Isolate::GetCurrent()->GetCodeRange(&code_range, &size);
    if (code_range && size)
      RegisterNonABICompliantCodeRange(code_range, size);
  }
  gin::Debug::SetCodeRangeDeletedCallback(UnregisterNonABICompliantCodeRange);
#endif
}

void CrashReporterWin::SetUploadParameters() {
  upload_parameters_["platform"] = "win32";
}

int CrashReporterWin::CrashForException(EXCEPTION_POINTERS* info) {
  if (breakpad_) {
    breakpad_->WriteMinidumpForException(info);
    TerminateProcessWithoutDump();
  }
  return EXCEPTION_CONTINUE_SEARCH;
}

// static
bool CrashReporterWin::FilterCallback(void* context,
                                      EXCEPTION_POINTERS* exinfo,
                                      MDRawAssertionInfo* assertion) {
  return true;
}

// static
bool CrashReporterWin::MinidumpCallback(const wchar_t* dump_path,
                                        const wchar_t* minidump_id,
                                        void* context,
                                        EXCEPTION_POINTERS* exinfo,
                                        MDRawAssertionInfo* assertion,
                                        bool succeeded) {
  CrashReporterWin* self = static_cast<CrashReporterWin*>(context);
  if (succeeded && !self->skip_system_crash_handler_)
    return true;
  else
    return false;
}

google_breakpad::CustomClientInfo* CrashReporterWin::GetCustomInfo(
    const std::string& product_name,
    const std::string& version,
    const std::string& company_name) {
  custom_info_entries_.clear();
  custom_info_entries_.reserve(2 + upload_parameters_.size());

  custom_info_entries_.push_back(google_breakpad::CustomInfoEntry(
      L"prod", L"Electron"));
  custom_info_entries_.push_back(google_breakpad::CustomInfoEntry(
      L"ver", base::UTF8ToWide(version).c_str()));

  for (StringMap::const_iterator iter = upload_parameters_.begin();
       iter != upload_parameters_.end(); ++iter) {
    custom_info_entries_.push_back(google_breakpad::CustomInfoEntry(
        base::UTF8ToWide(iter->first).c_str(),
        base::UTF8ToWide(iter->second).c_str()));
  }

  custom_info_.entries = &custom_info_entries_.front();
  custom_info_.count = custom_info_entries_.size();
  return &custom_info_;
}

// static
CrashReporterWin* CrashReporterWin::GetInstance() {
  return Singleton<CrashReporterWin>::get();
}

// static
CrashReporter* CrashReporter::GetInstance() {
  return CrashReporterWin::GetInstance();
}

}  // namespace crash_reporter
<commit_msg>win: Guard against failure of RtlAddFunctionTable<commit_after>// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.

#include "atom/common/crash_reporter/crash_reporter_win.h"

#include <string>

#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/memory/singleton.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "content/public/common/result_codes.h"
#include "gin/public/debug.h"
#include "sandbox/win/src/nt_internals.h"

#pragma intrinsic(_AddressOfReturnAddress)
#pragma intrinsic(_ReturnAddress)

#ifdef _WIN64
// See http://msdn.microsoft.com/en-us/library/ddssxxy8.aspx
typedef struct _UNWIND_INFO {
  unsigned char Version : 3;
  unsigned char Flags : 5;
  unsigned char SizeOfProlog;
  unsigned char CountOfCodes;
  unsigned char FrameRegister : 4;
  unsigned char FrameOffset : 4;
  ULONG ExceptionHandler;
} UNWIND_INFO, *PUNWIND_INFO;
#endif

namespace crash_reporter {

namespace {

// Minidump with stacks, PEB, TEB, and unloaded module list.
const MINIDUMP_TYPE kSmallDumpType = static_cast<MINIDUMP_TYPE>(
    MiniDumpWithProcessThreadData |  // Get PEB and TEB.
    MiniDumpWithUnloadedModules);  // Get unloaded modules when available.

const wchar_t kWaitEventFormat[] = L"$1CrashServiceWaitEvent";
const wchar_t kPipeNameFormat[] = L"\\\\.\\pipe\\$1 Crash Service";

typedef NTSTATUS (WINAPI* NtTerminateProcessPtr)(HANDLE ProcessHandle,
                                                 NTSTATUS ExitStatus);
char* g_real_terminate_process_stub = NULL;

void TerminateProcessWithoutDump() {
  // Patched stub exists based on conditions (See InitCrashReporter).
  // As a side note this function also gets called from
  // WindowProcExceptionFilter.
  if (g_real_terminate_process_stub == NULL) {
    ::TerminateProcess(::GetCurrentProcess(), content::RESULT_CODE_KILLED);
  } else {
    NtTerminateProcessPtr real_terminate_proc =
        reinterpret_cast<NtTerminateProcessPtr>(
            static_cast<char*>(g_real_terminate_process_stub));
    real_terminate_proc(::GetCurrentProcess(), content::RESULT_CODE_KILLED);
  }
}

#ifdef _WIN64
int CrashForExceptionInNonABICompliantCodeRange(
    PEXCEPTION_RECORD ExceptionRecord,
    ULONG64 EstablisherFrame,
    PCONTEXT ContextRecord,
    PDISPATCHER_CONTEXT DispatcherContext) {
  EXCEPTION_POINTERS info = { ExceptionRecord, ContextRecord };
  if (!CrashReporter::GetInstance())
    return EXCEPTION_CONTINUE_SEARCH;
  return static_cast<CrashReporterWin*>(CrashReporter::GetInstance())->
      CrashForException(&info);
}

struct ExceptionHandlerRecord {
  RUNTIME_FUNCTION runtime_function;
  UNWIND_INFO unwind_info;
  unsigned char thunk[12];
};

bool RegisterNonABICompliantCodeRange(void* start, size_t size_in_bytes) {
  ExceptionHandlerRecord* record =
      reinterpret_cast<ExceptionHandlerRecord*>(start);

  // We assume that the first page of the code range is executable and
  // committed and reserved for breakpad. What could possibly go wrong?

  // All addresses are 32bit relative offsets to start.
  record->runtime_function.BeginAddress = 0;
  record->runtime_function.EndAddress =
      base::checked_cast<DWORD>(size_in_bytes);
  record->runtime_function.UnwindData =
      offsetof(ExceptionHandlerRecord, unwind_info);

  // Create unwind info that only specifies an exception handler.
  record->unwind_info.Version = 1;
  record->unwind_info.Flags = UNW_FLAG_EHANDLER;
  record->unwind_info.SizeOfProlog = 0;
  record->unwind_info.CountOfCodes = 0;
  record->unwind_info.FrameRegister = 0;
  record->unwind_info.FrameOffset = 0;
  record->unwind_info.ExceptionHandler =
      offsetof(ExceptionHandlerRecord, thunk);

  // Hardcoded thunk.
  // mov imm64, rax
  record->thunk[0] = 0x48;
  record->thunk[1] = 0xb8;
  void* handler = &CrashForExceptionInNonABICompliantCodeRange;
  memcpy(&record->thunk[2], &handler, 8);

  // jmp rax
  record->thunk[10] = 0xff;
  record->thunk[11] = 0xe0;

  // Protect reserved page against modifications.
  DWORD old_protect;
  return VirtualProtect(start, sizeof(ExceptionHandlerRecord),
                        PAGE_EXECUTE_READ, &old_protect) &&
         RtlAddFunctionTable(&record->runtime_function, 1,
                             reinterpret_cast<DWORD64>(start));
}

void UnregisterNonABICompliantCodeRange(void* start) {
  ExceptionHandlerRecord* record =
      reinterpret_cast<ExceptionHandlerRecord*>(start);

  RtlDeleteFunctionTable(&record->runtime_function);
}
#endif  // _WIN64

}  // namespace

CrashReporterWin::CrashReporterWin() {
}

CrashReporterWin::~CrashReporterWin() {
}

void CrashReporterWin::InitBreakpad(const std::string& product_name,
                                    const std::string& version,
                                    const std::string& company_name,
                                    const std::string& submit_url,
                                    bool auto_submit,
                                    bool skip_system_crash_handler) {
  skip_system_crash_handler_ = skip_system_crash_handler;

  base::FilePath temp_dir;
  if (!base::GetTempDir(&temp_dir)) {
    LOG(ERROR) << "Cannot get temp directory";
    return;
  }

  base::string16 pipe_name = ReplaceStringPlaceholders(
      kPipeNameFormat, base::UTF8ToUTF16(product_name), NULL);
  base::string16 wait_name = ReplaceStringPlaceholders(
      kWaitEventFormat, base::UTF8ToUTF16(product_name), NULL);

  // Wait until the crash service is started.
  HANDLE wait_event = ::CreateEventW(NULL, TRUE, FALSE, wait_name.c_str());
  if (wait_event != NULL) {
    WaitForSingleObject(wait_event, 1000);
    CloseHandle(wait_event);
  }

  // ExceptionHandler() attaches our handler and ~ExceptionHandler() detaches
  // it, so we must explicitly reset *before* we instantiate our new handler
  // to allow any previous handler to detach in the correct order.
  breakpad_.reset();

  breakpad_.reset(new google_breakpad::ExceptionHandler(
      temp_dir.value(),
      FilterCallback,
      MinidumpCallback,
      this,
      google_breakpad::ExceptionHandler::HANDLER_ALL,
      kSmallDumpType,
      pipe_name.c_str(),
      GetCustomInfo(product_name, version, company_name)));

  if (!breakpad_->IsOutOfProcess())
    LOG(ERROR) << "Cannot initialize out-of-process crash handler";

#ifdef _WIN64
  bool registered = false;
  // Hook up V8 to breakpad.
  {
    // gin::Debug::SetCodeRangeCreatedCallback only runs the callback when
    // Isolate is just created, so we have to manually run following code here.
    void* code_range = nullptr;
    size_t size = 0;
    v8::Isolate::GetCurrent()->GetCodeRange(&code_range, &size);
    if (code_range && size)
      registered = RegisterNonABICompliantCodeRange(code_range, size);
  }
  if (registered)
    gin::Debug::SetCodeRangeDeletedCallback(UnregisterNonABICompliantCodeRange);
#endif
}

void CrashReporterWin::SetUploadParameters() {
  upload_parameters_["platform"] = "win32";
}

int CrashReporterWin::CrashForException(EXCEPTION_POINTERS* info) {
  if (breakpad_) {
    breakpad_->WriteMinidumpForException(info);
    TerminateProcessWithoutDump();
  }
  return EXCEPTION_CONTINUE_SEARCH;
}

// static
bool CrashReporterWin::FilterCallback(void* context,
                                      EXCEPTION_POINTERS* exinfo,
                                      MDRawAssertionInfo* assertion) {
  return true;
}

// static
bool CrashReporterWin::MinidumpCallback(const wchar_t* dump_path,
                                        const wchar_t* minidump_id,
                                        void* context,
                                        EXCEPTION_POINTERS* exinfo,
                                        MDRawAssertionInfo* assertion,
                                        bool succeeded) {
  CrashReporterWin* self = static_cast<CrashReporterWin*>(context);
  if (succeeded && !self->skip_system_crash_handler_)
    return true;
  else
    return false;
}

google_breakpad::CustomClientInfo* CrashReporterWin::GetCustomInfo(
    const std::string& product_name,
    const std::string& version,
    const std::string& company_name) {
  custom_info_entries_.clear();
  custom_info_entries_.reserve(2 + upload_parameters_.size());

  custom_info_entries_.push_back(google_breakpad::CustomInfoEntry(
      L"prod", L"Electron"));
  custom_info_entries_.push_back(google_breakpad::CustomInfoEntry(
      L"ver", base::UTF8ToWide(version).c_str()));

  for (StringMap::const_iterator iter = upload_parameters_.begin();
       iter != upload_parameters_.end(); ++iter) {
    custom_info_entries_.push_back(google_breakpad::CustomInfoEntry(
        base::UTF8ToWide(iter->first).c_str(),
        base::UTF8ToWide(iter->second).c_str()));
  }

  custom_info_.entries = &custom_info_entries_.front();
  custom_info_.count = custom_info_entries_.size();
  return &custom_info_;
}

// static
CrashReporterWin* CrashReporterWin::GetInstance() {
  return Singleton<CrashReporterWin>::get();
}

// static
CrashReporter* CrashReporter::GetInstance() {
  return CrashReporterWin::GetInstance();
}

}  // namespace crash_reporter
<|endoftext|>


<commit_before>#include "steamhelper.h"

#include <QProcess>
#include <QSettings>
#include <QDir>
#include <QFile>
#include <QRegExp>
#include <QTextStream>

bool SteamHelper::doesExist()
{
    #if defined(__linux__)
        QProcess which;
        which.start("which", QStringList() << "steam");
        which.waitForFinished();
        return which.exitCode() == 0;
    #elif defined(_WIN32) || defined(_WIN64)
        QSettings settings("HKEY_CURRENT_USER\\Software\\Valve\\Steam", QSettings::NativeFormat);
        return settings.contains("SteamPath");
    #elif defined(__APPLE__)
        QDir folder = QDir(QDir::home().filePath("Library/Application Support/Steam"));
        return folder.exists();
    #endif
}

QString SteamHelper::getFolder()
{
    if (!doesExist())
    {
        return "";
    }

    #if defined(__linux__)
        return QDir(QDir::homePath() + "/.local/share/Steam").canonicalPath();
    #elif defined(_WIN32) || defined(_WIN64)
        QSettings settings("HKEY_CURRENT_USER\\Software\\Valve\\Steam", QSettings::NativeFormat);
        return QDir(settings.value("SteamPath").toString()).canonicalPath();
    #elif defined(__APPLE__)
        return QDir(QDir::home().filePath("Library/Application Support/Steam")).canonicalPath();
    #endif
}

QMap<QString, QString> SteamHelper::getVdfKeyVals(QString vdfPath)
{
    QFile vdfFile(vdfPath);

    if (!vdfFile.open(QIODevice::ReadOnly))
    {
        return QMap<QString, QString>();
    }

    QTextStream fileStream(&vdfFile);

    QRegExp keyValPairRegex("^(?:\\s+)?\"(.+)\"\\s+\"(.+)\"(?:\\s+)?$");

    QMap<QString, QString> keyVals;

    while (!fileStream.atEnd())
    {
        QString line = fileStream.readLine();
        if (line.contains(keyValPairRegex))
        {
            keyValPairRegex.indexIn(line);
            QString key = keyValPairRegex.cap(1);
            QString val = keyValPairRegex.cap(2);
            keyVals[key] = val;
        }
    }

    return keyVals;
}

QList<QString> SteamHelper::getLibFolders()
{
    if (!doesExist())
    {
        return QList<QString>();
    }

    QDir steamappsPath = QDir(getFolder());
    if (steamappsPath.exists("steamapps"))
    {
        steamappsPath.cd("steamapps");
    }
    else if (steamappsPath.exists("SteamApps"))
    {
        steamappsPath.cd("SteamApps");
    }
    else
    {
        return QList<QString>();
    }
    QString libraryFoldersPath = steamappsPath.filePath("libraryfolders.vdf");

    QMap<QString, QString> keyVals = getVdfKeyVals(libraryFoldersPath);

    QList<QString> libFolders;

    for (QString key : keyVals.keys())
    {
        if (key != "TimeNextStatsReport" && key != "ContentStatsID")
        {
            libFolders << keyVals[key];
        }
    }

    return libFolders;
}

QMap<QString, QString> SteamHelper::getGamesInFolder(QString folderPath)
{
    QDir folder(folderPath);
    if (folder.exists("steamapps"))
    {
        folder.cd("steamapps");
    }
    else if (folder.exists("SteamApps"))
    {
        folder.cd("SteamApps");
    }
    else
    {
        return QMap<QString, QString>();
    }

    folder.setNameFilters(QStringList("appmanifest_*.acf"));
    QFileInfoList appmanifests = folder.entryInfoList();

    QMap<QString, QString> games;

    for (QFileInfo appmanifest : appmanifests)
    {
        QMap<QString, QString> keyVals = getVdfKeyVals(appmanifest.canonicalFilePath());

        if (!keyVals.contains("name")) { continue; }
        if (keyVals.contains("appid"))
        {
            games[keyVals["name"]] = keyVals["appid"];
        }
        else if (keyVals.contains("appID"))
        {
            games[keyVals["name"]] = keyVals["appID"];
        }
        else
        {
            continue;
        }
    }

    return games;
}

QMap<QString, QString> SteamHelper::getGames()
{
    if (!doesExist())
    {
        return QMap<QString, QString>();
    }

    QString steamPath = getFolder();
    QDir steamappsPath(steamPath);
    if (steamappsPath.exists("steamapps"))
    {
        steamappsPath.cd("steamapps");
    }
    else if (steamappsPath.exists("SteamApps"))
    {
        steamappsPath.cd("SteamApps");
    }
    else
    {
        return QMap<QString, QString>();
    }

    QMap<QString, QString> gamesList;

    QList<QString> libraryFolders = getLibFolders();
    libraryFolders << steamPath;

    for (QString folder : libraryFolders)
    {
        QMap<QString, QString> games = getGamesInFolder(folder);

        for (QString game : games.keys())
        {
            if (gamesList.contains(game)) { continue; }
            gamesList[game] = games[game];
        }
    }

    return gamesList;
}
<commit_msg>Add docs for SteamHelper class<commit_after>#include "steamhelper.h"

#include <QProcess>
#include <QSettings>
#include <QDir>
#include <QFile>
#include <QRegExp>
#include <QTextStream>

/** Checks if Steam exists on the system
*   \return true if Steam is installed, false otherwise
*/
bool SteamHelper::doesExist()
{
    #if defined(__linux__)
        QProcess which;
        which.start("which", QStringList() << "steam");
        which.waitForFinished();
        return which.exitCode() == 0;
    #elif defined(_WIN32) || defined(_WIN64)
        QSettings settings("HKEY_CURRENT_USER\\Software\\Valve\\Steam", QSettings::NativeFormat);
        return settings.contains("SteamPath");
    #elif defined(__APPLE__)
        QDir folder = QDir(QDir::home().filePath("Library/Application Support/Steam"));
        return folder.exists();
    #endif
}

/** Gets the path to Steam
*   \return The path to the Steam installation folder
*/
QString SteamHelper::getFolder()
{
    if (!doesExist())
    {
        return "";
    }

    #if defined(__linux__)
        return QDir(QDir::homePath() + "/.local/share/Steam").canonicalPath();
    #elif defined(_WIN32) || defined(_WIN64)
        QSettings settings("HKEY_CURRENT_USER\\Software\\Valve\\Steam", QSettings::NativeFormat);
        return QDir(settings.value("SteamPath").toString()).canonicalPath();
    #elif defined(__APPLE__)
        return QDir(QDir::home().filePath("Library/Application Support/Steam")).canonicalPath();
    #endif
}

/** Returns a map of key/value pairs in a VDF file.
*   Really hacky. Ignores objects (e.g. a = "b", b { z = "s" }, c { z = "z" })
*   z will be "z" because the objects get ignored. Will break if Valve
*   complicates the one file that this is used for.
*
*   \param vdfPath a path to the VDF file to be read
*   \return A QMap of key/value pairs in a VDF file.
*/
QMap<QString, QString> SteamHelper::getVdfKeyVals(QString vdfPath)
{
    QFile vdfFile(vdfPath);

    if (!vdfFile.open(QIODevice::ReadOnly))
    {
        return QMap<QString, QString>();
    }

    QTextStream fileStream(&vdfFile);

    QRegExp keyValPairRegex("^(?:\\s+)?\"(.+)\"\\s+\"(.+)\"(?:\\s+)?$");

    QMap<QString, QString> keyVals;

    while (!fileStream.atEnd())
    {
        QString line = fileStream.readLine();
        if (line.contains(keyValPairRegex))
        {
            keyValPairRegex.indexIn(line);
            QString key = keyValPairRegex.cap(1);
            QString val = keyValPairRegex.cap(2);
            keyVals[key] = val;
        }
    }

    return keyVals;
}

/** Gets list of Steam library folders
*   \return A QList with paths to Steam library folders. Does NOT include main folder.
*/
QList<QString> SteamHelper::getLibFolders()
{
    if (!doesExist())
    {
        return QList<QString>();
    }

    QDir steamappsPath = QDir(getFolder());
    if (steamappsPath.exists("steamapps"))
    {
        steamappsPath.cd("steamapps");
    }
    else if (steamappsPath.exists("SteamApps"))
    {
        steamappsPath.cd("SteamApps");
    }
    else
    {
        return QList<QString>();
    }
    QString libraryFoldersPath = steamappsPath.filePath("libraryfolders.vdf");

    QMap<QString, QString> keyVals = getVdfKeyVals(libraryFoldersPath);

    QList<QString> libFolders;

    for (QString key : keyVals.keys())
    {
        if (key != "TimeNextStatsReport" && key != "ContentStatsID")
        {
            libFolders << keyVals[key];
        }
    }

    return libFolders;
}

/** Get a list of all games in a Steam library folder
*   \param folderPath A path to the Steam library folder
*   \return A map of games. Key is the name, value is the appID.
*/
QMap<QString, QString> SteamHelper::getGamesInFolder(QString folderPath)
{
    QDir folder(folderPath);
    if (folder.exists("steamapps"))
    {
        folder.cd("steamapps");
    }
    else if (folder.exists("SteamApps"))
    {
        folder.cd("SteamApps");
    }
    else
    {
        return QMap<QString, QString>();
    }

    folder.setNameFilters(QStringList("appmanifest_*.acf"));
    QFileInfoList appmanifests = folder.entryInfoList();

    QMap<QString, QString> games;

    for (QFileInfo appmanifest : appmanifests)
    {
        QMap<QString, QString> keyVals = getVdfKeyVals(appmanifest.canonicalFilePath());

        if (!keyVals.contains("name")) { continue; }
        if (keyVals.contains("appid"))
        {
            games[keyVals["name"]] = keyVals["appid"];
        }
        else if (keyVals.contains("appID"))
        {
            games[keyVals["name"]] = keyVals["appID"];
        }
        else
        {
            continue;
        }
    }

    return games;
}

/** Get a map of ALL games in all Steam library folders.
*   \return A map of games. Key is the name, value is the appID.
*/
QMap<QString, QString> SteamHelper::getGames()
{
    if (!doesExist())
    {
        return QMap<QString, QString>();
    }

    QString steamPath = getFolder();
    QDir steamappsPath(steamPath);
    if (steamappsPath.exists("steamapps"))
    {
        steamappsPath.cd("steamapps");
    }
    else if (steamappsPath.exists("SteamApps"))
    {
        steamappsPath.cd("SteamApps");
    }
    else
    {
        return QMap<QString, QString>();
    }

    QMap<QString, QString> gamesList;

    QList<QString> libraryFolders = getLibFolders();
    libraryFolders << steamPath;

    for (QString folder : libraryFolders)
    {
        QMap<QString, QString> games = getGamesInFolder(folder);

        for (QString game : games.keys())
        {
            if (gamesList.contains(game)) { continue; }
            gamesList[game] = games[game];
        }
    }

    return gamesList;
}
<|endoftext|>


<commit_before>#include "generator.h"

#include <cassert>
#include <cstring>
#include <deque>
#include <iostream>
#include <map>

#include "dictionary.h"
#include "label.h"

static void compileCall(FILE* f, const char* wordName, const Tokens& tokens,
        Tokens::const_iterator* it, bool* state, Dictionary* dictionary) {
    ++*it;
    bool tailCall = (*it != tokens.end() && (*it)->type == SemiColon);
    --*it;
    fprintf(f, tailCall ? "\tjmp %s\n" : "\tjsr %s\n", label(wordName).c_str());
    if (tailCall) {
        ++*it;  // Skips ;
        *state = false;
    }
    dictionary->markAsUsed(wordName);
}

void generateAsm(FILE* f, const Tokens& tokens, Dictionary* dictionary) {
    std::deque<int> stack;
    int localLabel = 0;
    bool state = false;
    std::set<int> undefinedVariables;
    int variableLabel = 0;
    std::map<std::string, int> variableLabels;

    for (auto it = tokens.begin(); it != tokens.end(); ++it) {
        switch (it->type) {
            case Cells:
                if (state) {
                    compileCall(f, "2*", tokens, &it, &state, dictionary);
                } else {
                    stack.back() *= 2;
                }
                break;
            case Allot:
                assert(!stack.empty());
                fprintf(f, "* = * + %i\n", stack.back());
                stack.pop_back();
                break;
            case Create:
                ++it;
                if (it == tokens.end() || it->type != WordName) {
                    fprintf(stderr, "create must be followed by a word name!");
                    exit(1);
                }
                // printf("Create '%s'\n", it->stringData);
                fprintf(f, "\n%s:\n", label(it->stringData).c_str());
                dictionary->addWord(it->stringData);
                free(it->stringData);
                break;
            case String:
                fprintf(f, "\tjsr litstring\n!byte %i\n!text \"%s\"\n",
                        (int)strlen(it->stringData), it->stringData);
                dictionary->markAsUsed("litstring");
                free(it->stringData);
                break;
            case Variable:
                // puts("Variable");
                ++it;
                if (it == tokens.end() || it->type != WordName) {
                    fprintf(stderr, "variable must be followed by a word name!");
                    exit(1);
                }
                fprintf(f, "\n%s:\n", label(it->stringData).c_str());
                dictionary->addWord(it->stringData);
                fprintf(f, "\tlda #<+\n\tldy #>+\n\tjmp pushya\n+\n!word vl_%i\n", variableLabel);
                undefinedVariables.insert(variableLabel);
                variableLabels[it->stringData] = variableLabel;
                ++variableLabel;
                dictionary->markAsUsed("pushya");
                free(it->stringData);
                break;
            case Store:
                if (!state) {
                    int variableLabel = stack.back();
                    stack.pop_back();
                    int value = stack.back();
                    stack.pop_back();
                    fprintf(f, "vl_%i = %i\n", variableLabel, value);
                    undefinedVariables.erase(variableLabel);
                    break;
                } else {
                    compileCall(f, "!", tokens, &it, &state, dictionary);
                }
                break;
            case WordName:
                // printf("WordName %s\n", it->stringData);
                assert(it->stringData);
                if (state) {
                    compileCall(f, it->stringData, tokens, &it, &state, dictionary);
                    free(it->stringData);
                } else {
                    char* wordName = it->stringData;
                    if (variableLabels.find(wordName) != variableLabels.end()) {
                        stack.push_back(variableLabels[wordName]);
                        free(it->stringData);
                    } else {
                        fprintf(stderr, "Variable '%s' not defined\n", wordName);
                        exit(1);
                    }
                }
                break;
            case Number:
                // puts("Number");
                if (state) {
                    dictionary->markAsUsed("lit");
                    fprintf(f, "\tjsr lit\n\t!word %i\n", it->intData);
                } else {
                    stack.push_back(it->intData);
                }
                break;
            case Code:
                // puts("Code");
                {
                    char* p = it->stringData;
                    std::string wordName;
                    while (!isspace(*p)) {
                        wordName.push_back(*p);
                        ++p;
                    }
                    dictionary->addWord(wordName.c_str());
                    if (*p == '\n') {
                        ++p;
                    }
                    if (label(wordName.c_str()) != wordName) {
                        fprintf(f, "%s:\t; %s\n%s\n", label(wordName.c_str()).c_str(),
                                wordName.c_str(), p);
                    } else {
                        fprintf(f, "%s:\n%s\n", wordName.c_str(), p);
                    }
                }
                free(it->stringData);
                break;
            case Colon:
                ++it;
                if (it == tokens.end() || it->type != WordName) {
                    fprintf(stderr, ": must be followed by a word name! (is type %i)\n", it->type);
                    exit(1);
                }
                fprintf(f, "\n%s:", label(it->stringData).c_str());
                // printf("Colon %s\n", it->stringData);
                dictionary->addWord(it->stringData);
                if (it->stringData != label(it->stringData)) {
                    fprintf(f, "\t; %s", it->stringData);
                }
                fprintf(f, "\n");
                free(it->stringData);
                state = true;
                break;
            case Drop:
                fputs("\tinx\t; drop\n", f);
                break;
            case SemiColon:
                fputs("\trts\n", f);
                state = false;
                break;
            case If:
                fprintf(f, "\tjsr ifcmp\n\tbeq .l%i\n", localLabel);
                dictionary->markAsUsed("ifcmp");
                stack.push_back(localLabel++);
                break;
            case Else:
                fprintf(f, "\tjmp .l%i\n.l%i:\n", localLabel, stack.back());
                stack.pop_back();
                stack.push_back(localLabel++);
                break;
            case Then:
                fprintf(f, ".l%i:\n", stack.back());
                stack.pop_back();
                break;
            case Begin:
                stack.push_back(localLabel);
                fprintf(f, ".l%i:\n", localLabel++);
                break;
            case Again:
                fprintf(f, "\tjmp .l%i\n", stack.back());
                stack.pop_back();
                break;
            case Value:
                ++it;
                if (it == tokens.end() || it->type != WordName) {
                    fprintf(stderr, "value must be followed by a word name!");
                    exit(1);
                }
                fprintf(f, "\n%s:\n", label(it->stringData).c_str());
                dictionary->addWord(it->stringData);
                fprintf(f, "\tlda #%i\n", stack.back() & 0xff);
                fprintf(f, "\tldy #%i\n", stack.back() >> 8);
                fprintf(f, "\tjmp pushya\n");
                stack.pop_back();
                dictionary->markAsUsed("pushya");
                free(it->stringData);
                break;
        }
    }
}
<commit_msg>fixed possible memleak<commit_after>#include "generator.h"

#include <cassert>
#include <cstring>
#include <deque>
#include <iostream>
#include <map>

#include "dictionary.h"
#include "label.h"

static void compileCall(FILE* f, const char* wordName, const Tokens& tokens,
        Tokens::const_iterator* it, bool* state, Dictionary* dictionary) {
    ++*it;
    bool tailCall = (*it != tokens.end() && (*it)->type == SemiColon);
    --*it;
    fprintf(f, tailCall ? "\tjmp %s\n" : "\tjsr %s\n", label(wordName).c_str());
    if (tailCall) {
        ++*it;  // Skips ;
        *state = false;
    }
    dictionary->markAsUsed(wordName);
}

void generateAsm(FILE* f, const Tokens& tokens, Dictionary* dictionary) {
    std::deque<int> stack;
    int localLabel = 0;
    bool state = false;
    std::set<int> undefinedVariables;
    int variableLabel = 0;
    std::map<std::string, int> variableLabels;

    for (auto it = tokens.begin(); it != tokens.end(); ++it) {
        switch (it->type) {
            case Cells:
                if (state) {
                    compileCall(f, "2*", tokens, &it, &state, dictionary);
                } else {
                    stack.back() *= 2;
                }
                break;
            case Allot:
                assert(!stack.empty());
                fprintf(f, "* = * + %i\n", stack.back());
                stack.pop_back();
                break;
            case Create:
                ++it;
                if (it == tokens.end() || it->type != WordName) {
                    fprintf(stderr, "create must be followed by a word name!");
                    exit(1);
                }
                // printf("Create '%s'\n", it->stringData);
                fprintf(f, "\n%s:\n", label(it->stringData).c_str());
                dictionary->addWord(it->stringData);
                free(it->stringData);
                break;
            case String:
                fprintf(f, "\tjsr litstring\n!byte %i\n!text \"%s\"\n",
                        (int)strlen(it->stringData), it->stringData);
                dictionary->markAsUsed("litstring");
                free(it->stringData);
                break;
            case Variable:
                // puts("Variable");
                ++it;
                if (it == tokens.end() || it->type != WordName) {
                    fprintf(stderr, "variable must be followed by a word name!");
                    exit(1);
                }
                fprintf(f, "\n%s:\n", label(it->stringData).c_str());
                dictionary->addWord(it->stringData);
                fprintf(f, "\tlda #<+\n\tldy #>+\n\tjmp pushya\n+\n!word vl_%i\n", variableLabel);
                undefinedVariables.insert(variableLabel);
                variableLabels[it->stringData] = variableLabel;
                ++variableLabel;
                dictionary->markAsUsed("pushya");
                free(it->stringData);
                break;
            case Store:
                if (!state) {
                    int variableLabel = stack.back();
                    stack.pop_back();
                    int value = stack.back();
                    stack.pop_back();
                    fprintf(f, "vl_%i = %i\n", variableLabel, value);
                    undefinedVariables.erase(variableLabel);
                    break;
                } else {
                    compileCall(f, "!", tokens, &it, &state, dictionary);
                }
                break;
            case WordName:
                // printf("WordName %s\n", it->stringData);
                assert(it->stringData);
                if (state) {
                    char* wordName = it->stringData;
                    compileCall(f, wordName, tokens, &it, &state, dictionary);
                    free(wordName);
                } else {
                    char* wordName = it->stringData;
                    if (variableLabels.find(wordName) != variableLabels.end()) {
                        stack.push_back(variableLabels[wordName]);
                        free(it->stringData);
                    } else {
                        fprintf(stderr, "Variable '%s' not defined\n", wordName);
                        exit(1);
                    }
                }
                break;
            case Number:
                // puts("Number");
                if (state) {
                    dictionary->markAsUsed("lit");
                    fprintf(f, "\tjsr lit\n\t!word %i\n", it->intData);
                } else {
                    stack.push_back(it->intData);
                }
                break;
            case Code:
                // puts("Code");
                {
                    char* p = it->stringData;
                    std::string wordName;
                    while (!isspace(*p)) {
                        wordName.push_back(*p);
                        ++p;
                    }
                    dictionary->addWord(wordName.c_str());
                    if (*p == '\n') {
                        ++p;
                    }
                    if (label(wordName.c_str()) != wordName) {
                        fprintf(f, "%s:\t; %s\n%s\n", label(wordName.c_str()).c_str(),
                                wordName.c_str(), p);
                    } else {
                        fprintf(f, "%s:\n%s\n", wordName.c_str(), p);
                    }
                }
                free(it->stringData);
                break;
            case Colon:
                ++it;
                if (it == tokens.end() || it->type != WordName) {
                    fprintf(stderr, ": must be followed by a word name! (is type %i)\n", it->type);
                    exit(1);
                }
                fprintf(f, "\n%s:", label(it->stringData).c_str());
                // printf("Colon %s\n", it->stringData);
                dictionary->addWord(it->stringData);
                if (it->stringData != label(it->stringData)) {
                    fprintf(f, "\t; %s", it->stringData);
                }
                fprintf(f, "\n");
                free(it->stringData);
                state = true;
                break;
            case Drop:
                fputs("\tinx\t; drop\n", f);
                break;
            case SemiColon:
                fputs("\trts\n", f);
                state = false;
                break;
            case If:
                fprintf(f, "\tjsr ifcmp\n\tbeq .l%i\n", localLabel);
                dictionary->markAsUsed("ifcmp");
                stack.push_back(localLabel++);
                break;
            case Else:
                fprintf(f, "\tjmp .l%i\n.l%i:\n", localLabel, stack.back());
                stack.pop_back();
                stack.push_back(localLabel++);
                break;
            case Then:
                fprintf(f, ".l%i:\n", stack.back());
                stack.pop_back();
                break;
            case Begin:
                stack.push_back(localLabel);
                fprintf(f, ".l%i:\n", localLabel++);
                break;
            case Again:
                fprintf(f, "\tjmp .l%i\n", stack.back());
                stack.pop_back();
                break;
            case Value:
                ++it;
                if (it == tokens.end() || it->type != WordName) {
                    fprintf(stderr, "value must be followed by a word name!");
                    exit(1);
                }
                fprintf(f, "\n%s:\n", label(it->stringData).c_str());
                dictionary->addWord(it->stringData);
                fprintf(f, "\tlda #%i\n", stack.back() & 0xff);
                fprintf(f, "\tldy #%i\n", stack.back() >> 8);
                fprintf(f, "\tjmp pushya\n");
                stack.pop_back();
                dictionary->markAsUsed("pushya");
                free(it->stringData);
                break;
        }
    }
}
<|endoftext|>


<commit_before>/*M///////////////////////////////////////////////////////////////////////////////////////
//
//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
//  By downloading, copying, installing or using the software you agree to this license.
//  If you do not agree to this license, do not download, install,
//  copy or use the software.
//
//
//                           License Agreement
//                For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistribution's of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//
//   * Redistribution's in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//
//   * The name of the copyright holders may not be used to endorse or promote products
//     derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/

#include "cxcoretest.h"
#include <string>
#include <iostream>
#include <fstream>
#include <iterator>
#include <limits>
#include <numeric>

using namespace cv;
using namespace std;

class CV_MatrOpTest : public CvTest
{
public:
    CV_MatrOpTest();
    ~CV_MatrOpTest();
protected:
    void run(int);

    bool TestMat();
    bool TestMatND();
    bool TestSparseMat();

    bool checkMatSetError(const Mat& m1, const Mat& m2);
    bool checkMatSetError(const MatND& m1, const MatND& m2);
};

CV_MatrOpTest::CV_MatrOpTest(): CvTest( "matrix-operations", "?" )
{
    support_testing_modes = CvTS::CORRECTNESS_CHECK_MODE;
}
CV_MatrOpTest::~CV_MatrOpTest() {}

bool CV_MatrOpTest::checkMatSetError(const Mat& m1, const Mat& m2)
{
    if (norm(m1, m2, NORM_INF) == 0)
        return true;

    ts->set_failed_test_info(CvTS::FAIL_MISMATCH);
    return false;
}

bool CV_MatrOpTest::checkMatSetError(const MatND& m1, const MatND& m2)
{
    if (norm(m1, m2, NORM_INF) == 0)
        return true;

    ts->set_failed_test_info(CvTS::FAIL_MISMATCH);
    return false;
}

bool CV_MatrOpTest::TestMat()
{
    Mat one_3x1(3, 1, CV_32F, Scalar(1.0));
    Mat shi_3x1(3, 1, CV_32F, Scalar(1.2));
    Mat shi_2x1(2, 1, CV_32F, Scalar(-1));
    Scalar shift = Scalar::all(15);

    float data[] = { sqrt(2.f)/2, -sqrt(2.f)/2, 1.f, sqrt(2.f)/2, sqrt(2.f)/2, 10.f };
    Mat rot_2x3(2, 3, CV_32F, data);

    Mat res = rot_2x3 * (one_3x1 + shi_3x1 + shi_3x1 + shi_3x1) - shi_2x1 + shift;

    Mat tmp, res2;
    add(one_3x1, shi_3x1, tmp);
    add(tmp, shi_3x1, tmp);
    add(tmp, shi_3x1, tmp);
    gemm(rot_2x3, tmp, 1, shi_2x1, -1, res2, 0);
    add(res2, Mat(2, 1, CV_32F, shift), res2);

    if (!checkMatSetError(res, res2))
        return false;

    Mat mat4x4(4, 4, CV_32F);
    randu(mat4x4, Scalar(0), Scalar(10));

    Mat roi1 = mat4x4(Rect(Point(1, 1), Size(2, 2)));
    Mat roi2 = mat4x4(Range(1, 3), Range(1, 3));

    if (!checkMatSetError(roi1, roi2))
        return false;

    if (!checkMatSetError(mat4x4, mat4x4(Rect(Point(0,0), mat4x4.size()))))
        return false;

    return true;
}

bool CV_MatrOpTest::TestMatND()
{
    int sizes[] = { 3, 3, 3};
    cv::MatND nd(3, sizes, CV_32F);

   /* MatND res = nd * nd + nd;
    MatND res2;
    cv::gemm(nd, nd, 1, nd, 1, res2);

    if (!checkMatSetError(res1, res2))
        return false;*/

    return true;
}

bool CV_MatrOpTest::TestSparseMat()
{
    int sizes[] = { 10, 10, 10};
    SparseMat mat(sizeof(sizes)/sizeof(sizes[0]), sizes, CV_32F);

    return true;
}

void CV_MatrOpTest::run( int /* start_from */)
{
    if (!TestMat())
        return;

    if (!TestMatND())
        return;

    if (!TestSparseMat())
        return;

    ts->set_failed_test_info(CvTS::OK);
}

CV_MatrOpTest cv_MatrOp_test;

<commit_msg>united cv::Mat and cv::MatND<commit_after>/*M///////////////////////////////////////////////////////////////////////////////////////
//
//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
//  By downloading, copying, installing or using the software you agree to this license.
//  If you do not agree to this license, do not download, install,
//  copy or use the software.
//
//
//                           License Agreement
//                For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistribution's of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//
//   * Redistribution's in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//
//   * The name of the copyright holders may not be used to endorse or promote products
//     derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/

#include "cxcoretest.h"
#include <string>
#include <iostream>
#include <fstream>
#include <iterator>
#include <limits>
#include <numeric>

using namespace cv;
using namespace std;

class CV_MatrOpTest : public CvTest
{
public:
    CV_MatrOpTest();
    ~CV_MatrOpTest();
protected:
    void run(int);

    bool TestMat();
    bool TestMatND();
    bool TestSparseMat();

    bool checkMatSetError(const Mat& m1, const Mat& m2);
};

CV_MatrOpTest::CV_MatrOpTest(): CvTest( "matrix-operations", "?" )
{
    support_testing_modes = CvTS::CORRECTNESS_CHECK_MODE;
}
CV_MatrOpTest::~CV_MatrOpTest() {}

bool CV_MatrOpTest::checkMatSetError(const Mat& m1, const Mat& m2)
{
    if (norm(m1, m2, NORM_INF) == 0)
        return true;

    ts->set_failed_test_info(CvTS::FAIL_MISMATCH);
    return false;
}

bool CV_MatrOpTest::TestMat()
{
    Mat one_3x1(3, 1, CV_32F, Scalar(1.0));
    Mat shi_3x1(3, 1, CV_32F, Scalar(1.2));
    Mat shi_2x1(2, 1, CV_32F, Scalar(-1));
    Scalar shift = Scalar::all(15);

    float data[] = { sqrt(2.f)/2, -sqrt(2.f)/2, 1.f, sqrt(2.f)/2, sqrt(2.f)/2, 10.f };
    Mat rot_2x3(2, 3, CV_32F, data);

    Mat res = rot_2x3 * (one_3x1 + shi_3x1 + shi_3x1 + shi_3x1) - shi_2x1 + shift;

    Mat tmp, res2;
    add(one_3x1, shi_3x1, tmp);
    add(tmp, shi_3x1, tmp);
    add(tmp, shi_3x1, tmp);
    gemm(rot_2x3, tmp, 1, shi_2x1, -1, res2, 0);
    add(res2, Mat(2, 1, CV_32F, shift), res2);

    if (!checkMatSetError(res, res2))
        return false;

    Mat mat4x4(4, 4, CV_32F);
    randu(mat4x4, Scalar(0), Scalar(10));

    Mat roi1 = mat4x4(Rect(Point(1, 1), Size(2, 2)));
    Mat roi2 = mat4x4(Range(1, 3), Range(1, 3));

    if (!checkMatSetError(roi1, roi2))
        return false;

    if (!checkMatSetError(mat4x4, mat4x4(Rect(Point(0,0), mat4x4.size()))))
        return false;

    return true;
}

bool CV_MatrOpTest::TestMatND()
{
    int sizes[] = { 3, 3, 3};
    cv::MatND nd(3, sizes, CV_32F);

   /* MatND res = nd * nd + nd;
    MatND res2;
    cv::gemm(nd, nd, 1, nd, 1, res2);

    if (!checkMatSetError(res1, res2))
        return false;*/

    return true;
}

bool CV_MatrOpTest::TestSparseMat()
{
    int sizes[] = { 10, 10, 10};
    SparseMat mat(sizeof(sizes)/sizeof(sizes[0]), sizes, CV_32F);

    return true;
}

void CV_MatrOpTest::run( int /* start_from */)
{
    if (!TestMat())
        return;

    if (!TestMatND())
        return;

    if (!TestSparseMat())
        return;

    ts->set_failed_test_info(CvTS::OK);
}

CV_MatrOpTest cv_MatrOp_test;

<|endoftext|>