<commit_before>#include "sutil_linux.h"

using namespace std;

#if SUTIL_HAVE_PRLIMIT
    #define _FILE_OFFSET_BITS 64
    #include <time.h>
    #include <sys/resource.h>
#endif

#if SUTIL_HAVE_IOPRIO
enum {
    IOPRIO_WHO_PROCESS = 1,
};

static inline int
ioprio_get(int which, int who)
{
    return syscall(__NR_ioprio_get, which, who);
}

static inline int
ioprio_set(int which, int who, int ioprio)
{
    return syscall(__NR_ioprio_set, which, who, ioprio);
}

#define IOPRIO_CLASS_SHIFT 13
#define IOPRIO_PRIO_MASK ((1UL << IOPRIO_CLASS_SHIFT) - 1)

#define IOPRIO_PRIO_CLASS(mask) ((mask) >> IOPRIO_CLASS_SHIFT)
#define IOPRIO_PRIO_DATA(mask) ((mask) & IOPRIO_PRIO_MASK)
#define IOPRIO_PRIO_VALUE(class, data) (((class) << IOPRIO_CLASS_SHIFT) | data)

/*
 * Return a (ioclass, iodata) Python tuple representing process I/O priority.
 */
int
sutil_proc_ioprio_get(const int32_t &pid, int* &proc_ioprio)
{
    int ioprio, ioclass, iodata;
    ioprio = ioprio_get(IOPRIO_WHO_PROCESS, pid);
    if (ioprio == -1) {
        //PyErr_SetFromErrno(PyExc_OSError);
        return -1;
    }
    ioclass = IOPRIO_PRIO_CLASS(ioprio);
    iodata = IOPRIO_PRIO_DATA(ioprio);
    proc_ioprio[0] = ioclass;
    proc_ioprio[1] = iodata;
    return 0;
}

/*
 * A wrapper around ioprio_set(); sets process I/O priority.
 * ioclass can be either IOPRIO_CLASS_RT, IOPRIO_CLASS_BE, IOPRIO_CLASS_IDLE
 * or 0. iodata goes from 0 to 7 depending on ioclass specified.
 */
int
sutil_proc_ioprio_set(const int32_t &pid, const int &ioclass, const int &iodata)
{
    int ioprio = IOPRIO_PRIO_VALUE(ioclass, iodata);
    int retval = ioprio_set(IOPRIO_WHO_PROCESS, pid, ioprio);
    if (retval == -1) {
        //return PyErr_SetFromErrno(PyExc_OSError);
        return -1;
    }
    return 0;
}

#endif

#if SUTIL_HAVE_PRLIMIT
/*
 * A wrapper around prlimit(2); sets process resource limits.
 * This can be used for both get and set, in which case extra
 * 'soft' and 'hard' args must be provided.
 */
int
sutil_linux_prlimit(const pid_t &pid,
                    enum __rlimit_resource resource,
                    int64_t *&result,
                    int64_t *soft = nullptr,
                    int64_t *hard = nullptr)
{
    int ret;
    struct rlimit old, anew;
    struct rlimit *newp = NULL;

    // get
    if (soft == nullptr && hard == nullptr) {
        ret = prlimit(pid, resource, NULL, &old);
        if (ret == -1)
            return -1;
            //return PyErr_SetFromErrno(PyExc_OSError);
#if defined(SUTIL_HAVE_LONG_LONG)
        if (sizeof(old.rlim_cur) > sizeof(long)) {
            result[0] = old.rlim_cur;
            result[1] = old.rlim_max;
            return 0;
        }
#endif
        result[0] = old.rlim_cur;
        result[1] = old.rlim_max;
        return 0;
        //return Py_BuildValue("ll", (long)old.rlim_cur, (long)old.rlim_max);
    }

    // set
    else {
#if defined(SUTIL_HAVE_LARGEFILE_SUPPORT)
        anew.rlim_cur = *soft;
        if (anew.rlim_cur == (rlim_t) - 1)
            return 0;
        anew.rlim_max = *hard; //PyLong_AsLongLong(hard);
        if (anew.rlim_max == (rlim_t) - 1)
            return 0;
#else
        anew.rlim_cur = *soft; //PyLong_AsLong(soft);
        if (anew.rlim_cur == (rlim_t) - 1)
            return 0;
        anew.rlim_max = *hard;//PyLong_AsLong(hard);
        if (anew.rlim_max == (rlim_t) - 1)
            return 0;
#endif
        newp = &anew;
        ret = prlimit(pid, resource, newp, &old);
        if (ret == -1)
            //return PyErr_SetFromErrno(PyExc_OSError);
            return -1;
        return 0;
    }
}
#endif

bool
sutil_pid_exists(const int32_t &pid)
{

    int kill_ret;

    // save some time if it's an invalid PID
    if (pid < 0) {
        return false;
    }

    // if kill returns success of permission denied we know it's a valid PID
    kill_ret = kill(pid , 0);
    if ( (0 == kill_ret) || (EPERM == errno) ) {
        return true;
    }

    // otherwise return 0 for PID not found
    return false;
}

/*
 * return disk mounted partitions as a list of tuples including device,
 * mount point and filesystem type
 */
int
sutil_disk_partitions(vector<vector<string>> &devlist)
{
    FILE *file = NULL;
    struct mntent *entry;
    vector<string> tuple(4);

    // mounted constant comes from mntent.h and it's == '/etc/mtab'
    file = setmntent(MOUNTED, "r");
    if ((file == 0) || (file == NULL)) {
        //pyerr_setfromerrnowithfilename(pyexc_oserror, mounted);
        goto error;
    }

    while ((entry = getmntent(file))) {
        if (entry == NULL) {
            //pyerr_format(pyexc_runtimeerror, "getmntent() failed");
            goto error;
        }
        tuple.clear();
        tuple.push_back(entry->mnt_fsname);  // device
        tuple.push_back(entry->mnt_dir);     // mount point
        tuple.push_back(entry->mnt_type);    // fs type
        tuple.push_back(entry->mnt_opts);   // options
        devlist.push_back(tuple);
    }
    endmntent(file);
    return 0;

error:
    if (file != NULL)
        endmntent(file);
    return -1;
}

/*
 * A wrapper around sysinfo(), return system memory usage statistics.
 */
int
sutil_linux_sysinfo(uint64_t* &info)
{
    struct sysinfo ifo;
    if (sysinfo(&ifo) != 0) {
        //return PyErr_SetFromErrno(PyExc_OSError);
        return -1;
    }
    // note: boot time might also be determined from here
    //return Py_BuildValue(
    //    "(KKKKKK)",
    //
    info[0] = (uint64_t)ifo.totalram  * ifo.mem_unit;   // total
    info[1] = (uint64_t)ifo.freeram   * ifo.mem_unit;   // free
    info[2] = (uint64_t)ifo.bufferram * ifo.mem_unit;   // buffer
    info[3] = (uint64_t)ifo.sharedram * ifo.mem_unit;   // shared
    info[4] = (uint64_t)ifo.totalswap * ifo.mem_unit;   // swap tot
    info[5] = (uint64_t)ifo.freeswap  * ifo.mem_unit;  // swap free
    return 0;
}

/*
 * Return process CPU affinity as a Python long (the bitmask)
 */
int
sutil_proc_cpu_affinity_get(const int32_t pid, uint32_t &mask)
{
    unsigned int len = sizeof(mask);

    if (sched_getaffinity(pid, len, (cpu_set_t *)&mask) < 0) {
        //return PyErr_SetFromErrno(PyExc_OSError);
        return -1;
    }
    //return Py_BuildValue("l", mask);
    return 0;
}

/*
 * Set process CPU affinity; expects a bitmask
 */
int
sutil_proc_cpu_affinity_set(const int32_t &pid, vector<int32_t> &cpu_set_list)
{
    cpu_set_t cpu_set;
    size_t len;
    int i;//, seq_len;

    //if (!PySequence_Check(py_cpu_set)) {
        // does not work on Python 2.4
        // PyErr_Format(PyExc_TypeError, "sequence argument expected, got %s",
        //              Py_TYPE(py_cpu_set)->tp_name);
        //PyErr_Format(PyExc_TypeError, "sequence argument expected");
        //goto error;
    //}

    //py_cpu_seq = PySequence_Fast(py_cpu_set, "expected a sequence or integer");
    //if (!py_cpu_seq) {
    //    goto error;
    //}
    //seq_len = PySequence_Fast_GET_SIZE(py_cpu_seq);
    CPU_ZERO(&cpu_set);
    for (i = 0; i < cpu_set_list.size(); i++) {
        //PyObject *item = PySequence_Fast_GET_ITEM(py_cpu_seq, i);
        int32_t value = cpu_set_list[i];
        if (value == -1) {
            goto error;
        }
        CPU_SET(value, &cpu_set);
    }

    len = sizeof(cpu_set);
    if (sched_setaffinity(pid, len, &cpu_set)) {
        //PyErr_SetFromErrno(PyExc_OSError);
        goto error;
    }

    return 0;

error:
    return -1;
}

/*
 * Return currently connected users as a list of tuples.
 */
int
sutil_users(vector<sutil_user_info> &user_list)
{
    //PyObject *ret_list = PyList_New(0);
    //PyObject *tuple = NULL;
    //PyObject *user_proc = NULL;
    bool user_proc;
    sutil_user_info a_user;
    struct utmp *ut;

    //if (ret_list == NULL)
    //    return NULL;
    setutent();
    while (NULL != (ut = getutent())) {
        if (ut->ut_type == USER_PROCESS)
            user_proc = true;
        else
            user_proc = false;

        //tuple = Py_BuildValue(
        //    "(sssfO)",
        a_user.username = ut->ut_user;              // username
        a_user.tty = ut->ut_line;              // tty
        a_user.host = ut->ut_host;              // hostname
        a_user.start_time = (float)ut->ut_tv.tv_sec;  // tstamp
        a_user.user_proc = user_proc;                 // (bool) user process
        //);
        user_list.push_back(a_user);
    }
    endutent();
    return 0;

error:
    endutent();
    return -1;
}

int sutil_sysconf(std::string &which)
{
    if (which == "SC_CLK_TCK") {
        return sysconf(_SC_CLK_TCK);
    }
    if (which == "SC_PAGE_SIZE") {
        return sysconf(_SC_PAGE_SIZE);
    }
}

<commit_msg>update sutil_linux<commit_after>#include "sutil_linux.h"

using namespace std;

#if SUTIL_HAVE_PRLIMIT
    #define _FILE_OFFSET_BITS 64
    #include <time.h>
    #include <sys/resource.h>
#endif

#if SUTIL_HAVE_IOPRIO
enum {
    IOPRIO_WHO_PROCESS = 1,
};

static inline int
ioprio_get(int which, int who)
{
    return syscall(__NR_ioprio_get, which, who);
}

static inline int
ioprio_set(int which, int who, int ioprio)
{
    return syscall(__NR_ioprio_set, which, who, ioprio);
}

#define IOPRIO_CLASS_SHIFT 13
#define IOPRIO_PRIO_MASK ((1UL << IOPRIO_CLASS_SHIFT) - 1)

#define IOPRIO_PRIO_CLASS(mask) ((mask) >> IOPRIO_CLASS_SHIFT)
#define IOPRIO_PRIO_DATA(mask) ((mask) & IOPRIO_PRIO_MASK)
#define IOPRIO_PRIO_VALUE(class, data) (((class) << IOPRIO_CLASS_SHIFT) | data)

/*
 * Return {ioclass, iodata} representing process I/O priority.
 */
int
sutil_proc_ioprio_get(const int32_t &pid, int* &proc_ioprio)
{
    int ioprio, ioclass, iodata;
    ioprio = ioprio_get(IOPRIO_WHO_PROCESS, pid);
    if (ioprio == -1) {
        return -1;
    }
    ioclass = IOPRIO_PRIO_CLASS(ioprio);
    iodata = IOPRIO_PRIO_DATA(ioprio);
    proc_ioprio[0] = ioclass;
    proc_ioprio[1] = iodata;
    return 0;
}

/*
 * A wrapper around ioprio_set(); sets process I/O priority.
 * ioclass can be either IOPRIO_CLASS_RT, IOPRIO_CLASS_BE, IOPRIO_CLASS_IDLE
 * or 0. iodata goes from 0 to 7 depending on ioclass specified.
 */
int
sutil_proc_ioprio_set(const int32_t &pid, const int &ioclass, const int &iodata)
{
    int ioprio = IOPRIO_PRIO_VALUE(ioclass, iodata);
    int retval = ioprio_set(IOPRIO_WHO_PROCESS, pid, ioprio);
    if (retval == -1) {
        return -1;
    }
    return 0;
}

#endif

#if SUTIL_HAVE_PRLIMIT
/*
 * A wrapper around prlimit(2); sets process resource limits.
 * This can be used for both get and set, in which case extra
 * 'soft' and 'hard' args must be provided.
 */
int
sutil_linux_prlimit(const pid_t &pid,
                    enum __rlimit_resource resource,
                    int64_t *&result,
                    int64_t *soft = nullptr,
                    int64_t *hard = nullptr)
{
    int ret;
    struct rlimit old, anew;
    struct rlimit *newp = NULL;

    // get
    if (soft == nullptr && hard == nullptr) {
        ret = prlimit(pid, resource, NULL, &old);
        if (ret == -1)
            return -1;
#if defined(SUTIL_HAVE_LONG_LONG)
        if (sizeof(old.rlim_cur) > sizeof(long)) {
            result[0] = old.rlim_cur;
            result[1] = old.rlim_max;
            return 0;
        }
#endif
        result[0] = old.rlim_cur;
        result[1] = old.rlim_max;
        return 0;
    }

    // set
    else {
#if defined(SUTIL_HAVE_LARGEFILE_SUPPORT)
        anew.rlim_cur = *soft;
        if (anew.rlim_cur == (rlim_t) - 1)
            return 0;
        anew.rlim_max = *hard;
        if (anew.rlim_max == (rlim_t) - 1)
            return 0;
#else
        anew.rlim_cur = *soft;
        if (anew.rlim_cur == (rlim_t) - 1)
            return 0;
        anew.rlim_max = *hard;
        if (anew.rlim_max == (rlim_t) - 1)
            return 0;
#endif
        newp = &anew;
        ret = prlimit(pid, resource, newp, &old);
        if (ret == -1)
            return -1;
        return 0;
    }
}
#endif

bool
sutil_pid_exists(const int32_t &pid)
{

    int kill_ret;

    // save some time if it's an invalid PID
    if (pid < 0) {
        return false;
    }

    // if kill returns success of permission denied we know it's a valid PID
    kill_ret = kill(pid , 0);
    if ( (0 == kill_ret) || (EPERM == errno) ) {
        return true;
    }

    return false;
}

int
sutil_disk_partitions(vector<vector<string>> &devlist)
{
    FILE *file = NULL;
    struct mntent *entry;
    vector<string> tuple(4);

    // mounted constant comes from mntent.h and it's == '/etc/mtab'
    file = setmntent(MOUNTED, "r");
    if ((file == 0) || (file == NULL)) {
        goto error;
    }

    while ((entry = getmntent(file))) {
        if (entry == NULL) {
            goto error;
        }
        tuple.clear();
        tuple.push_back(entry->mnt_fsname);  // device
        tuple.push_back(entry->mnt_dir);     // mount point
        tuple.push_back(entry->mnt_type);    // fs type
        tuple.push_back(entry->mnt_opts);   // options
        devlist.push_back(tuple);
    }
    endmntent(file);
    return 0;

error:
    if (file != NULL)
        endmntent(file);
    return -1;
}

/*
 * A wrapper around sysinfo(), return system memory usage statistics.
 */
int
sutil_linux_sysinfo(uint64_t* &info)
{
    struct sysinfo ifo;
    if (sysinfo(&ifo) != 0) {
        return -1;
    }
    // note: boot time might also be determined from here
    info[0] = (uint64_t)ifo.totalram  * ifo.mem_unit;   // total
    info[1] = (uint64_t)ifo.freeram   * ifo.mem_unit;   // free
    info[2] = (uint64_t)ifo.bufferram * ifo.mem_unit;   // buffer
    info[3] = (uint64_t)ifo.sharedram * ifo.mem_unit;   // shared
    info[4] = (uint64_t)ifo.totalswap * ifo.mem_unit;   // swap tot
    info[5] = (uint64_t)ifo.freeswap  * ifo.mem_unit;  // swap free
    return 0;
}

/*
 * Return process CPU affinity as a long (the bitmask)
 */
int
sutil_proc_cpu_affinity_get(const int32_t pid, uint32_t &mask)
{
    unsigned int len = sizeof(mask);

    if (sched_getaffinity(pid, len, (cpu_set_t *)&mask) < 0) {
        return -1;
    }
    return 0;
}

/*
 * Set process CPU affinity; expects a bitmask
 */
int
sutil_proc_cpu_affinity_set(const int32_t &pid, vector<int32_t> &cpu_set_list)
{
    cpu_set_t cpu_set;
    size_t len;
    int i;//, seq_len;

    CPU_ZERO(&cpu_set);
    for (i = 0; i < cpu_set_list.size(); i++) {
        int32_t value = cpu_set_list[i];
        if (value == -1) {
            goto error;
        }
        CPU_SET(value, &cpu_set);
    }

    len = sizeof(cpu_set);
    if (sched_setaffinity(pid, len, &cpu_set)) {
        goto error;
    }

    return 0;

error:
    return -1;
}

/*
 * Return currently connected users.
 */
int
sutil_users(vector<sutil_user_info> &user_list)
{
    bool user_proc;
    sutil_user_info a_user;
    struct utmp *ut;

    setutent();
    while (NULL != (ut = getutent())) {
        if (ut->ut_type == USER_PROCESS)
            user_proc = true;
        else
            user_proc = false;

        a_user.username = ut->ut_user;              // username
        a_user.tty = ut->ut_line;              // tty
        a_user.host = ut->ut_host;              // hostname
        a_user.start_time = (float)ut->ut_tv.tv_sec;  // tstamp
        a_user.user_proc = user_proc;                 // (bool) user process
        //);
        user_list.push_back(a_user);
    }
    endutent();
    return 0;

error:
    endutent();
    return -1;
}

int sutil_sysconf(std::string &which)
{
    if (which == "SC_CLK_TCK") {
        return sysconf(_SC_CLK_TCK);
    }
    if (which == "SC_PAGE_SIZE") {
        return sysconf(_SC_PAGE_SIZE);
    }
}

<|endoftext|>


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

#include <px4_config.h>
#include <px4_posix.h>
#include <px4_tasks.h>

extern "C" __EXPORT int micrortps_client_main(int argc, char *argv[]);

static void usage(const char *name)
{
    PX4_INFO("usage: %s start|stop\n\n", name);
}

int micrortps_client_main(int argc, char *argv[])
{
    if (argc < 2)
    {
        usage(argv[0]);
        return -1;
    }

    if (!strcmp(argv[1], "start"))
    {
        PX4_WARN("PX4 built without RTPS bridge support, EXITING...\n");
        return -1;
    }

    if (!strcmp(argv[1], "stop"))
    {
        PX4_INFO("Not running");
        return -1;
    }

    usage(argv[0]);

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

#include <px4_config.h>
#include <px4_posix.h>
#include <px4_tasks.h>

extern "C" __EXPORT int micrortps_client_main(int argc, char *argv[]);

static void usage(const char *name)
{
    PX4_INFO("usage: %s start|stop\n\n", name);
}

int micrortps_client_main(int argc, char *argv[])
{
    if (argc < 2)
    {
        usage(argv[0]);
        return -1;
    }

    if (!strcmp(argv[1], "start"))
    {
        PX4_WARN("PX4 built without RTPS bridge support, EXITING...\n");
        return -1;
    }

    if (!strcmp(argv[1], "stop"))
    {
        PX4_INFO("Not running");
        return -1;
    }

    usage(argv[0]);

    return -1;
}
<|endoftext|>


<commit_before>#include <appbase/application.hpp>

#include <eosio/wallet_plugin/yubihsm_wallet.hpp>
#include <eosio/chain/exceptions.hpp>
#include <yubihsm.h>

#include <fc/crypto/openssl.hpp>

#include <boost/range/adaptor/map.hpp>
#include <boost/range/algorithm/copy.hpp>
#include <boost/asio/posix/stream_descriptor.hpp>
#include <boost/dll/runtime_symbol_info.hpp>

namespace eosio { namespace wallet {

using namespace fc::crypto::r1;

namespace detail {

struct yubihsm_wallet_impl {
   using key_map_type = map<public_key_type,uint16_t>;

   yubihsm_wallet_impl(const string& ep, const uint16_t ak) : endpoint(ep), authkey(ak) {
      yh_rc rc;
      if((rc = yh_init()))
         FC_THROW("yubihsm init failure: ${c}", ("c", yh_strerror(rc)));
   }

   ~yubihsm_wallet_impl() {
      lock();
      yh_exit();
      //bizarre, is there no way to destroy a yh_connector??

      ///XXX Probably a race condition on timer shutdown and appbase destruction
   }

   bool is_locked() const {
      return !connector;
   }

   key_map_type::iterator populate_key_map_with_keyid(const uint16_t key_id) {
      yh_rc rc;
      size_t blob_sz = 128;
      uint8_t blob[blob_sz];
      if((rc = yh_util_get_public_key(session, key_id, blob, &blob_sz, nullptr)))
         FC_THROW_EXCEPTION(chain::wallet_exception, "yh_util_get_public_key failed: ${m}", ("m", yh_strerror(rc)));
      if(blob_sz != 64)
         FC_THROW_EXCEPTION(chain::wallet_exception, "unexpected pubkey size from yh_util_get_public_key");

      ///XXX This is junky and common with SE wallet; commonize it
      char serialized_pub_key[sizeof(public_key_data) + 1];
      serialized_pub_key[0] = 0x01; //means R1 key
      serialized_pub_key[1] = 0x02 + (blob[63]&1); //R1 header; even or odd Y
      memcpy(serialized_pub_key+2, blob, 32); //copy in the 32 bytes of X

      public_key_type pub_key;
      fc::datastream<const char *> ds(serialized_pub_key, sizeof(serialized_pub_key));
      fc::raw::unpack(ds, pub_key);

      return _keys.emplace(pub_key, key_id).first;
   }

   void unlock(const string& password) {
      yh_rc rc;

      try {
         if((rc = yh_init_connector(endpoint.c_str(), &connector)))
            FC_THROW_EXCEPTION(chain::wallet_exception, "Failled to initialize yubihsm connector URL: ${c}", ("c", yh_strerror(rc)));
         if((rc = yh_connect(connector, 0)))
            FC_THROW_EXCEPTION(chain::wallet_exception, "Failed to connect to YubiHSM connector: ${m}", ("m", yh_strerror(rc)));
         if((rc = yh_create_session_derived(connector, authkey, (const uint8_t *)password.data(), password.size(), false, &session)))
            FC_THROW_EXCEPTION(chain::wallet_exception, "Failed to create YubiHSM session: ${m}", ("m", yh_strerror(rc)));
         if((rc = yh_authenticate_session(session)))
            FC_THROW_EXCEPTION(chain::wallet_exception, "Failed to authenticate YubiHSM session: ${m}", ("m", yh_strerror(rc)));

         yh_object_descriptor authkey_desc;
         if((rc = yh_util_get_object_info(session, authkey, YH_AUTHENTICATION_KEY, &authkey_desc)))
            FC_THROW_EXCEPTION(chain::wallet_exception, "Failed to get authkey info: ${m}", ("m", yh_strerror(rc)));

         authkey_caps = authkey_desc.capabilities;
         authkey_domains = authkey_desc.domains;

         if(!yh_check_capability(&authkey_caps, "sign-ecdsa"))
            FC_THROW_EXCEPTION(chain::wallet_exception, "Given authkey cannot perform signing");

         size_t found_objects_n = 64*1024;
         yh_object_descriptor found_objs[found_objects_n];
         yh_capabilities find_caps;
         yh_string_to_capabilities("sign-ecdsa", &find_caps);
         if((rc = yh_util_list_objects(session, 0, YH_ASYMMETRIC_KEY, 0, &find_caps, YH_ALGO_EC_P256, nullptr, found_objs, &found_objects_n)))
            FC_THROW_EXCEPTION(chain::wallet_exception, "yh_util_list_objects failed: ${m}", ("m", yh_strerror(rc)));

         for(size_t i = 0; i < found_objects_n; ++i)
            populate_key_map_with_keyid(found_objs[i].id);
      }
      catch(chain::wallet_exception& e) {
         lock();
         throw;
      }

      prime_keepalive_timer();
   }

   void lock() {
      if(session) {
         yh_util_close_session(session);
         yh_destroy_session(&session);
      }
      session = nullptr;
      if(connector)
         yh_disconnect(connector);
      //it would seem like this would leak-- there is no destroy() call for it. But I clearly can't reuse connectors
      // as that fails with a "Unable to find a suitable connector"
      connector = nullptr;

      _keys.clear();
      keepalive_timer.cancel();
   }

   void prime_keepalive_timer() {
      keepalive_timer.expires_at(std::chrono::steady_clock::now() + std::chrono::seconds(20));
      keepalive_timer.async_wait([this](const boost::system::error_code& ec){
         if(ec || !session)
            return;

         uint8_t data, resp;
         yh_cmd resp_cmd;
         size_t resp_sz = 1;
         if(yh_send_secure_msg(session, YHC_ECHO, &data, 1, &resp_cmd, &resp, &resp_sz))
            lock();
         else
            prime_keepalive_timer();
      });
   }

   fc::optional<signature_type> try_sign_digest(const digest_type d, const public_key_type public_key) {
      auto it = _keys.find(public_key);
      if(it == _keys.end())
         return fc::optional<signature_type>{};

      size_t der_sig_sz = 128;
      uint8_t der_sig[der_sig_sz];
      yh_rc rc;
      if((rc = yh_util_sign_ecdsa(session, it->second, (uint8_t*)d.data(), d.data_size(), der_sig, &der_sig_sz))) {
         lock();
         FC_THROW_EXCEPTION(chain::wallet_exception, "yh_util_sign_ecdsa failed: ${m}", ("m", yh_strerror(rc)));
      }

      ///XXX a lot of this below is similar to SE wallet; commonize it in non-junky way
      fc::ecdsa_sig sig = ECDSA_SIG_new();
      BIGNUM *r = BN_new(), *s = BN_new();
      BN_bin2bn(der_sig+4, der_sig[3], r);
      BN_bin2bn(der_sig+6+der_sig[3], der_sig[4+der_sig[3]+1], s);
      ECDSA_SIG_set0(sig, r, s);

      char pub_key_shim_data[64];
      fc::datastream<char *> eds(pub_key_shim_data, sizeof(pub_key_shim_data));
      fc::raw::pack(eds, it->first);
      public_key_data* kd = (public_key_data*)(pub_key_shim_data+1);

      compact_signature compact_sig;
      compact_sig = signature_from_ecdsa(key, *kd, sig, d);

      char serialized_signature[sizeof(compact_sig) + 1];
      serialized_signature[0] = 0x01;
      memcpy(serialized_signature+1, compact_sig.data, sizeof(compact_sig));

      signature_type final_signature;
      fc::datastream<const char *> ds(serialized_signature, sizeof(serialized_signature));
      fc::raw::unpack(ds, final_signature);
      return final_signature;
   }

   public_key_type create() {
      if(!yh_check_capability(&authkey_caps, "generate-asymmetric-key"))
         FC_THROW_EXCEPTION(chain::wallet_exception, "Given authkey cannot create keys");

      yh_rc rc;
      uint16_t new_key_id = 0;
      yh_capabilities creation_caps = {};
      if(yh_string_to_capabilities("sign-ecdsa:export-wrapped", &creation_caps))
         FC_THROW_EXCEPTION(chain::wallet_exception, "Cannot create caps mask");

      try {
         if((rc = yh_util_generate_ec_key(session, &new_key_id, "keosd created key", authkey_domains, &creation_caps, YH_ALGO_EC_P256)))
            FC_THROW_EXCEPTION(chain::wallet_exception, "yh_util_generate_ec_key failed: ${m}", ("m", yh_strerror(rc)));
         return populate_key_map_with_keyid(new_key_id)->first;
      }
      catch(chain::wallet_exception& e) {
         lock();
         throw;
      }
   }

   yh_connector* connector = nullptr;
   yh_session* session = nullptr;
   string endpoint;
   uint16_t authkey;

   map<public_key_type,uint16_t> _keys;

   yh_capabilities authkey_caps;
   uint16_t authkey_domains;

   boost::asio::steady_timer keepalive_timer{appbase::app().get_io_service()};
   fc::ec_key key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
};

}

yubihsm_wallet::yubihsm_wallet(const string& connector, const uint16_t authkey) : my(new detail::yubihsm_wallet_impl(connector, authkey)) {
}

yubihsm_wallet::~yubihsm_wallet() {
}

private_key_type yubihsm_wallet::get_private_key(public_key_type pubkey) const {
   FC_THROW_EXCEPTION(chain::wallet_exception, "Obtaining private key for a key stored in YubiHSM is impossible");
}

bool yubihsm_wallet::is_locked() const {
   return my->is_locked();
}
void yubihsm_wallet::lock() {
   FC_ASSERT(!is_locked());
   my->lock();
}

void yubihsm_wallet::unlock(string password) {
   my->unlock(password);
}
void yubihsm_wallet::check_password(string password) {
   //just leave this as a noop for now; remove_key from wallet_mgr calls through here
}
void yubihsm_wallet::set_password(string password) {
   FC_THROW_EXCEPTION(chain::wallet_exception, "YubiHSM wallet cannot have a password set");
}

map<public_key_type, private_key_type> yubihsm_wallet::list_keys() {
   FC_THROW_EXCEPTION(chain::wallet_exception, "Getting the private keys from the YubiHSM wallet is impossible");
}
flat_set<public_key_type> yubihsm_wallet::list_public_keys() {
   flat_set<public_key_type> keys;
   boost::copy(my->_keys | boost::adaptors::map_keys, std::inserter(keys, keys.end()));
   return keys;
}

bool yubihsm_wallet::import_key(string wif_key) {
   FC_THROW_EXCEPTION(chain::wallet_exception, "It is not possible to import a key in to the YubiHSM wallet");
}

string yubihsm_wallet::create_key(string key_type) {
   EOS_ASSERT(key_type.empty() || key_type == "R1", chain::unsupported_key_type_exception, "YubiHSM wallet only supports R1 keys");
   return (string)my->create();
}

bool yubihsm_wallet::remove_key(string key) {
   FC_ASSERT(!is_locked());
   return true;
}

fc::optional<signature_type> yubihsm_wallet::try_sign_digest(const digest_type digest, const public_key_type public_key) {
   return my->try_sign_digest(digest, public_key);
}

}}
<commit_msg>Merging in CICD even more changes so PR build can work.<commit_after>#include <appbase/application.hpp>

#include <eosio/wallet_plugin/yubihsm_wallet.hpp>
#include <eosio/chain/exceptions.hpp>
#include <yubihsm.h>

#include <fc/crypto/openssl.hpp>

#include <boost/range/adaptor/map.hpp>
#include <boost/range/algorithm/copy.hpp>
#include <boost/asio/posix/stream_descriptor.hpp>
#include <boost/dll/runtime_symbol_info.hpp>

namespace eosio { namespace wallet {

using namespace fc::crypto::r1;

namespace detail {

struct yubihsm_wallet_impl {
   using key_map_type = map<public_key_type,uint16_t>;

   yubihsm_wallet_impl(const string& ep, const uint16_t ak) : endpoint(ep), authkey(ak) {
      yh_rc rc;
      if((rc = yh_init()))
         FC_THROW("yubihsm init failure: ${c}", ("c", yh_strerror(rc)));
   }

   ~yubihsm_wallet_impl() {
      lock();
      yh_exit();
      //bizarre, is there no way to destroy a yh_connector??

      ///XXX Probably a race condition on timer shutdown and appbase destruction
   }

   bool is_locked() const {
      return !connector;
   }

   key_map_type::iterator populate_key_map_with_keyid(const uint16_t key_id) {
      yh_rc rc;
      size_t blob_sz = 128;
      uint8_t blob[blob_sz];
      if((rc = yh_util_get_public_key(session, key_id, blob, &blob_sz, nullptr)))
         FC_THROW_EXCEPTION(chain::wallet_exception, "yh_util_get_public_key failed: ${m}", ("m", yh_strerror(rc)));
      if(blob_sz != 64)
         FC_THROW_EXCEPTION(chain::wallet_exception, "unexpected pubkey size from yh_util_get_public_key");

      ///XXX This is junky and common with SE wallet; commonize it
      char serialized_pub_key[sizeof(public_key_data) + 1];
      serialized_pub_key[0] = 0x01; //means R1 key
      serialized_pub_key[1] = 0x02 + (blob[63]&1); //R1 header; even or odd Y
      memcpy(serialized_pub_key+2, blob, 32); //copy in the 32 bytes of X

      public_key_type pub_key;
      fc::datastream<const char *> ds(serialized_pub_key, sizeof(serialized_pub_key));
      fc::raw::unpack(ds, pub_key);

      return _keys.emplace(pub_key, key_id).first;
   }

   void unlock(const string& password) {
      yh_rc rc;

      try {
         if((rc = yh_init_connector(endpoint.c_str(), &connector)))
            FC_THROW_EXCEPTION(chain::wallet_exception, "Failled to initialize yubihsm connector URL: ${c}", ("c", yh_strerror(rc)));
         if((rc = yh_connect(connector, 0)))
            FC_THROW_EXCEPTION(chain::wallet_exception, "Failed to connect to YubiHSM connector: ${m}", ("m", yh_strerror(rc)));
         if((rc = yh_create_session_derived(connector, authkey, (const uint8_t *)password.data(), password.size(), false, &session)))
            FC_THROW_EXCEPTION(chain::wallet_exception, "Failed to create YubiHSM session: ${m}", ("m", yh_strerror(rc)));
         if((rc = yh_authenticate_session(session)))
            FC_THROW_EXCEPTION(chain::wallet_exception, "Failed to authenticate YubiHSM session: ${m}", ("m", yh_strerror(rc)));

         yh_object_descriptor authkey_desc;
         if((rc = yh_util_get_object_info(session, authkey, YH_AUTHENTICATION_KEY, &authkey_desc)))
            FC_THROW_EXCEPTION(chain::wallet_exception, "Failed to get authkey info: ${m}", ("m", yh_strerror(rc)));

         authkey_caps = authkey_desc.capabilities;
         authkey_domains = authkey_desc.domains;

         if(!yh_check_capability(&authkey_caps, "sign-ecdsa"))
            FC_THROW_EXCEPTION(chain::wallet_exception, "Given authkey cannot perform signing");

         size_t found_objects_n = 64*1024;
         yh_object_descriptor found_objs[found_objects_n];
         yh_capabilities find_caps;
         yh_string_to_capabilities("sign-ecdsa", &find_caps);
         if((rc = yh_util_list_objects(session, 0, YH_ASYMMETRIC_KEY, 0, &find_caps, YH_ALGO_EC_P256, nullptr, found_objs, &found_objects_n)))
            FC_THROW_EXCEPTION(chain::wallet_exception, "yh_util_list_objects failed: ${m}", ("m", yh_strerror(rc)));

         for(size_t i = 0; i < found_objects_n; ++i)
            populate_key_map_with_keyid(found_objs[i].id);
      }
      catch(chain::wallet_exception& e) {
         lock();
         throw;
      }

      prime_keepalive_timer();
   }

   void lock() {
      if(session) {
         yh_util_close_session(session);
         yh_destroy_session(&session);
      }
      session = nullptr;
      if(connector)
         yh_disconnect(connector);
      //it would seem like this would leak-- there is no destroy() call for it. But I clearly can't reuse connectors
      // as that fails with a "Unable to find a suitable connector"
      connector = nullptr;

      _keys.clear();
      keepalive_timer.cancel();
   }

   void prime_keepalive_timer() {
      keepalive_timer.expires_at(std::chrono::steady_clock::now() + std::chrono::seconds(20));
      keepalive_timer.async_wait([this](const boost::system::error_code& ec){
         if(ec || !session)
            return;

         uint8_t data, resp;
         yh_cmd resp_cmd;
         size_t resp_sz = 1;
         if(yh_send_secure_msg(session, YHC_ECHO, &data, 1, &resp_cmd, &resp, &resp_sz))
            lock();
         else
            prime_keepalive_timer();
      });
   }

   fc::optional<signature_type> try_sign_digest(const digest_type d, const public_key_type public_key) {
      auto it = _keys.find(public_key);
      if(it == _keys.end())
         return fc::optional<signature_type>{};

      size_t der_sig_sz = 128;
      uint8_t der_sig[der_sig_sz];
      yh_rc rc;
      if((rc = yh_util_sign_ecdsa(session, it->second, (uint8_t*)d.data(), d.data_size(), der_sig, &der_sig_sz))) {
         lock();
         FC_THROW_EXCEPTION(chain::wallet_exception, "yh_util_sign_ecdsa failed: ${m}", ("m", yh_strerror(rc)));
      }

      ///XXX a lot of this below is similar to SE wallet; commonize it in non-junky way
      fc::ecdsa_sig sig = ECDSA_SIG_new();
      BIGNUM *r = BN_new(), *s = BN_new();
      BN_bin2bn(der_sig+4, der_sig[3], r);
      BN_bin2bn(der_sig+6+der_sig[3], der_sig[4+der_sig[3]+1], s);
      ECDSA_SIG_set0(sig, r, s);

      char pub_key_shim_data[64];
      fc::datastream<char *> eds(pub_key_shim_data, sizeof(pub_key_shim_data));
      fc::raw::pack(eds, it->first);
      public_key_data* kd = (public_key_data*)(pub_key_shim_data+1);

      compact_signature compact_sig;
      compact_sig = signature_from_ecdsa(key, *kd, sig, d);

      char serialized_signature[sizeof(compact_sig) + 1];
      serialized_signature[0] = 0x01;
      memcpy(serialized_signature+1, compact_sig.data, sizeof(compact_sig));

      signature_type final_signature;
      fc::datastream<const char *> ds(serialized_signature, sizeof(serialized_signature));
      fc::raw::unpack(ds, final_signature);
      return final_signature;
   }

   public_key_type create() {
      if(!yh_check_capability(&authkey_caps, "generate-asymmetric-key"))
         FC_THROW_EXCEPTION(chain::wallet_exception, "Given authkey cannot create keys");

      yh_rc rc;
      uint16_t new_key_id = 0;
      yh_capabilities creation_caps = {};
      if(yh_string_to_capabilities("sign-ecdsa:export-wrapped", &creation_caps))
         FC_THROW_EXCEPTION(chain::wallet_exception, "Cannot create caps mask");

      try {
         if((rc = yh_util_generate_ec_key(session, &new_key_id, "keosd created key", authkey_domains, &creation_caps, YH_ALGO_EC_P256)))
            FC_THROW_EXCEPTION(chain::wallet_exception, "yh_util_generate_ec_key failed: ${m}", ("m", yh_strerror(rc)));
         return populate_key_map_with_keyid(new_key_id)->first;
      }
      catch(chain::wallet_exception& e) {
         lock();
         throw;
      }
   }

   yh_connector* connector = nullptr;
   yh_session* session = nullptr;
   string endpoint;
   uint16_t authkey;

   map<public_key_type,uint16_t> _keys;

   yh_capabilities authkey_caps;
   uint16_t authkey_domains;

   boost::asio::steady_timer keepalive_timer{appbase::app().get_io_service()};
   fc::ec_key key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
};

}

yubihsm_wallet::yubihsm_wallet(const string& connector, const uint16_t authkey) : my(new detail::yubihsm_wallet_impl(connector, authkey)) {
}

yubihsm_wallet::~yubihsm_wallet() {
}

private_key_type yubihsm_wallet::get_private_key(public_key_type pubkey) const {
   FC_THROW_EXCEPTION(chain::wallet_exception, "Obtaining private key for a key stored in YubiHSM is impossible");
}

bool yubihsm_wallet::is_locked() const {
   return my->is_locked();
}
void yubihsm_wallet::lock() {
   FC_ASSERT(!is_locked());
   my->lock();
}

void yubihsm_wallet::unlock(string password) {
   my->unlock(password);
}
void yubihsm_wallet::check_password(string password) {
   //just leave this as a noop for now; remove_key from wallet_mgr calls through here
}
void yubihsm_wallet::set_password(string password) {
   FC_THROW_EXCEPTION(chain::wallet_exception, "YubiHSM wallet cannot have a password set");
}

map<public_key_type, private_key_type> yubihsm_wallet::list_keys() {
   FC_THROW_EXCEPTION(chain::wallet_exception, "Getting the private keys from the YubiHSM wallet is impossible");
}
flat_set<public_key_type> yubihsm_wallet::list_public_keys() {
   flat_set<public_key_type> keys;
   boost::copy(my->_keys | boost::adaptors::map_keys, std::inserter(keys, keys.end()));
   return keys;
}

bool yubihsm_wallet::import_key(string wif_key) {
   FC_THROW_EXCEPTION(chain::wallet_exception, "It is not possible to import a key in to the YubiHSM wallet");
}

string yubihsm_wallet::create_key(string key_type) {
   EOS_ASSERT(key_type.empty() || key_type == "R1", chain::unsupported_key_type_exception, "YubiHSM wallet only supports R1 keys");
   return (string)my->create();
}

bool yubihsm_wallet::remove_key(string key) {
   FC_ASSERT(!is_locked());
   FC_THROW_EXCEPTION(chain::wallet_exception, "YubiHSM wallet does not currently support removal of keys");
   return true;
}

fc::optional<signature_type> yubihsm_wallet::try_sign_digest(const digest_type digest, const public_key_type public_key) {
   return my->try_sign_digest(digest, public_key);
}

}}
<|endoftext|>


<commit_before>#pragma once

#include <memory>
#include <vector>

#include <boost/thread/tss.hpp>

#include "blackhole/attribute.hpp"
#include "blackhole/detail/config/atomic.hpp"
#include "blackhole/detail/config/noncopyable.hpp"
#include "blackhole/detail/config/nullptr.hpp"
#include "blackhole/detail/util/unique.hpp"
#include "error/handler.hpp"
#include "filter.hpp"
#include "frontend.hpp"
#include "keyword.hpp"
#include "keyword/message.hpp"
#include "keyword/severity.hpp"
#include "keyword/thread.hpp"
#include "keyword/timestamp.hpp"
#include "keyword/tracebit.hpp"

#include "blackhole/config.hpp"

namespace blackhole {

class scoped_attributes_concept_t;

class logger_base_t {
    friend class scoped_attributes_concept_t;
    friend void swap(logger_base_t& lhs, logger_base_t& rhs) BLACKHOLE_NOEXCEPT;

protected:
    typedef boost::shared_mutex rw_mutex_type;
    typedef boost::shared_lock<rw_mutex_type> reader_lock_type;
    typedef boost::unique_lock<rw_mutex_type> writer_lock_type;

    struct state_t {
        std::atomic<bool> enabled;
        std::atomic<bool> tracked;

        filter_t filter;
        struct attrbutes_t {
            boost::thread_specific_ptr<scoped_attributes_concept_t> scoped;

            attrbutes_t(void(*deleter)(scoped_attributes_concept_t*)) :
                scoped(deleter)
            {}
        } attributes;

        std::vector<std::unique_ptr<base_frontend_t>> frontends;
        log::exception_handler_t exception;

        struct {
            mutable rw_mutex_type open;
            mutable rw_mutex_type push;
        } lock;

        state_t();
    };

    state_t state;

public:
    logger_base_t();

    //! @compat GCC4.4
    //! Blaming GCC4.4 - it needs explicit move constructor definition,
    //! because it cannot define default move constructor for derived class.
    logger_base_t(logger_base_t&& other) BLACKHOLE_NOEXCEPT;
    logger_base_t& operator=(logger_base_t&& other) BLACKHOLE_NOEXCEPT;

    bool enabled() const;
    void enabled(bool enable);

    bool tracked() const;
    void tracked(bool enable);

    void set_filter(filter_t&& filter);
    void add_frontend(std::unique_ptr<base_frontend_t> frontend);
    void set_exception_handler(log::exception_handler_t&& handler);

    record_t open_record() const;
    record_t open_record(attribute::pair_t attribute) const;
    record_t open_record(attribute::set_t attributes) const;

    void push(record_t&& record) const;

protected:
    record_t open_record(attribute::set_t internal, attribute::set_t external) const;
};

/// Concept form scoped attributes holder.
/*!
 * @note: It's not movable to avoid moving to another thread.
 */
class scoped_attributes_concept_t {
    BLACKHOLE_DECLARE_NONCOPYABLE(scoped_attributes_concept_t);

    logger_base_t *m_logger;
    scoped_attributes_concept_t *m_previous;

    friend void swap(logger_base_t&, logger_base_t&) BLACKHOLE_NOEXCEPT;

public:
    scoped_attributes_concept_t(logger_base_t& log);
    virtual ~scoped_attributes_concept_t();

    virtual const attribute::set_t& attributes() const = 0;

protected:
    bool has_parent() const;
    const scoped_attributes_concept_t& parent() const;
};

template<typename Level>
class verbose_logger_t : public logger_base_t {
public:
    typedef Level level_type;

    typedef std::function<
        bool(level_type, const attribute::combined_view_t&)
    > filter_type;

private:
    level_type level;
    filter_type filter;

    // TODO: Thread-safety.

public:
    explicit verbose_logger_t(level_type level) :
        logger_base_t(),
        level(level),
        filter(default_filter { level })
    {}

    //! @compat: GCC4.4
    //! GCC 4.4 doesn't create default copy/move constructor for derived
    //! classes. It's a bug.
    verbose_logger_t(verbose_logger_t&& other) BLACKHOLE_NOEXCEPT :
        logger_base_t(std::move(other))
    {
        level = other.level;
        filter = other.filter;
    }

    verbose_logger_t& operator=(verbose_logger_t&& other) BLACKHOLE_NOEXCEPT {
        logger_base_t::operator=(std::move(other));

        level = other.level;
        filter = other.filter;
        return *this;
    }

    /*!
     * Gets the current upper verbosity bound.
     */
    level_type verbosity() const {
        return level;
    }

    /*!
     * Sets the upper verbosity bound.
     * Every log event with a verbosity less than `level` will be dropped.
     * @param[in] level - Upper verbosity value.
     */
    void verbosity(level_type level) {
        this->level = level;
        this->filter = default_filter { level };
    }

    // TODO: Level is necessary!
    void verbosity(filter_type filter) {
        this->filter = filter;
    }

    /*!
     * Tries to open log record with specific verbosity level.
     *
     * Internally this method compares desired verbosity level with the upper
     * one and checks for tracebit attribute (temporary until filter redesign).
     * Can return invalid log record if some conditions are not met.
     * @param[in] level - Desired verbosity level.
     * @return valid or invalid `record_t` object.
     * @todo: Decompose.
     */
    record_t
    open_record(level_type level, attribute::set_t local = attribute::set_t()) const {
        bool passed = false;
        reader_lock_type lock(state.lock.open);
        if (auto scoped = state.attributes.scoped.get()) {
            const attribute::combined_view_t view(local, scoped->attributes());
            passed = filter(level, view);
        } else {
            const attribute::combined_view_t view(local);
            passed = filter(level, view);
        }

        if (passed) {
            attribute::set_t internal;
            internal.emplace_back(keyword::severity<Level>() = level);
            return logger_base_t::open_record(std::move(internal), std::move(local));
        }

        return record_t();
    }

private:
    struct default_filter {
        level_type threshold;

        inline
        bool
        operator()(level_type level, const attribute::combined_view_t&) const {
            return level >= threshold;
        }
    };
};

} // namespace blackhole

#if defined(BLACKHOLE_HEADER_ONLY)
#include "blackhole/logger.ipp"
#endif
<commit_msg>[GCC 4.6] Compare strong enums properly.<commit_after>#pragma once

#include <memory>
#include <vector>

#include <boost/thread/tss.hpp>

#include "blackhole/attribute.hpp"
#include "blackhole/detail/config/atomic.hpp"
#include "blackhole/detail/config/noncopyable.hpp"
#include "blackhole/detail/config/nullptr.hpp"
#include "blackhole/detail/util/unique.hpp"
#include "error/handler.hpp"
#include "filter.hpp"
#include "frontend.hpp"
#include "keyword.hpp"
#include "keyword/message.hpp"
#include "keyword/severity.hpp"
#include "keyword/thread.hpp"
#include "keyword/timestamp.hpp"
#include "keyword/tracebit.hpp"

#include "blackhole/config.hpp"

namespace blackhole {

class scoped_attributes_concept_t;

class logger_base_t {
    friend class scoped_attributes_concept_t;
    friend void swap(logger_base_t& lhs, logger_base_t& rhs) BLACKHOLE_NOEXCEPT;

protected:
    typedef boost::shared_mutex rw_mutex_type;
    typedef boost::shared_lock<rw_mutex_type> reader_lock_type;
    typedef boost::unique_lock<rw_mutex_type> writer_lock_type;

    struct state_t {
        std::atomic<bool> enabled;
        std::atomic<bool> tracked;

        filter_t filter;
        struct attrbutes_t {
            boost::thread_specific_ptr<scoped_attributes_concept_t> scoped;

            attrbutes_t(void(*deleter)(scoped_attributes_concept_t*)) :
                scoped(deleter)
            {}
        } attributes;

        std::vector<std::unique_ptr<base_frontend_t>> frontends;
        log::exception_handler_t exception;

        struct {
            mutable rw_mutex_type open;
            mutable rw_mutex_type push;
        } lock;

        state_t();
    };

    state_t state;

public:
    logger_base_t();

    //! @compat GCC4.4
    //! Blaming GCC4.4 - it needs explicit move constructor definition,
    //! because it cannot define default move constructor for derived class.
    logger_base_t(logger_base_t&& other) BLACKHOLE_NOEXCEPT;
    logger_base_t& operator=(logger_base_t&& other) BLACKHOLE_NOEXCEPT;

    bool enabled() const;
    void enabled(bool enable);

    bool tracked() const;
    void tracked(bool enable);

    void set_filter(filter_t&& filter);
    void add_frontend(std::unique_ptr<base_frontend_t> frontend);
    void set_exception_handler(log::exception_handler_t&& handler);

    record_t open_record() const;
    record_t open_record(attribute::pair_t attribute) const;
    record_t open_record(attribute::set_t attributes) const;

    void push(record_t&& record) const;

protected:
    record_t open_record(attribute::set_t internal, attribute::set_t external) const;
};

/// Concept form scoped attributes holder.
/*!
 * @note: It's not movable to avoid moving to another thread.
 */
class scoped_attributes_concept_t {
    BLACKHOLE_DECLARE_NONCOPYABLE(scoped_attributes_concept_t);

    logger_base_t *m_logger;
    scoped_attributes_concept_t *m_previous;

    friend void swap(logger_base_t&, logger_base_t&) BLACKHOLE_NOEXCEPT;

public:
    scoped_attributes_concept_t(logger_base_t& log);
    virtual ~scoped_attributes_concept_t();

    virtual const attribute::set_t& attributes() const = 0;

protected:
    bool has_parent() const;
    const scoped_attributes_concept_t& parent() const;
};

template<typename Level>
class verbose_logger_t : public logger_base_t {
public:
    typedef Level level_type;

    typedef std::function<
        bool(level_type, const attribute::combined_view_t&)
    > filter_type;

private:
    level_type level;
    filter_type filter;

    // TODO: Thread-safety.

public:
    explicit verbose_logger_t(level_type level) :
        logger_base_t(),
        level(level),
        filter(default_filter { level })
    {}

    //! @compat: GCC4.4
    //! GCC 4.4 doesn't create default copy/move constructor for derived
    //! classes. It's a bug.
    verbose_logger_t(verbose_logger_t&& other) BLACKHOLE_NOEXCEPT :
        logger_base_t(std::move(other))
    {
        level = other.level;
        filter = other.filter;
    }

    verbose_logger_t& operator=(verbose_logger_t&& other) BLACKHOLE_NOEXCEPT {
        logger_base_t::operator=(std::move(other));

        level = other.level;
        filter = other.filter;
        return *this;
    }

    /*!
     * Gets the current upper verbosity bound.
     */
    level_type verbosity() const {
        return level;
    }

    /*!
     * Sets the upper verbosity bound.
     * Every log event with a verbosity less than `level` will be dropped.
     * @param[in] level - Upper verbosity value.
     */
    void verbosity(level_type level) {
        this->level = level;
        this->filter = default_filter { level };
    }

    // TODO: Level is necessary!
    void verbosity(filter_type filter) {
        this->filter = filter;
    }

    /*!
     * Tries to open log record with specific verbosity level.
     *
     * Internally this method compares desired verbosity level with the upper
     * one and checks for tracebit attribute (temporary until filter redesign).
     * Can return invalid log record if some conditions are not met.
     * @param[in] level - Desired verbosity level.
     * @return valid or invalid `record_t` object.
     * @todo: Decompose.
     */
    record_t
    open_record(level_type level, attribute::set_t local = attribute::set_t()) const {
        bool passed = false;
        reader_lock_type lock(state.lock.open);
        if (auto scoped = state.attributes.scoped.get()) {
            const attribute::combined_view_t view(local, scoped->attributes());
            passed = filter(level, view);
        } else {
            const attribute::combined_view_t view(local);
            passed = filter(level, view);
        }

        if (passed) {
            attribute::set_t internal;
            internal.emplace_back(keyword::severity<Level>() = level);
            return logger_base_t::open_record(std::move(internal), std::move(local));
        }

        return record_t();
    }

private:
    struct default_filter {
        level_type threshold;

        inline
        bool
        operator()(level_type level, const attribute::combined_view_t&) const {
            typedef typename aux::underlying_type<Level>::type underlying_type;

            return static_cast<underlying_type>(level) >= static_cast<underlying_type>(threshold);
        }
    };
};

} // namespace blackhole

#if defined(BLACKHOLE_HEADER_ONLY)
#include "blackhole/logger.ipp"
#endif
<|endoftext|>


<commit_before>
#include "uri.h"
#include "string_util.h"
#include "contract.h"
#include <algorithm>
#include "file_system.h"
#include "user_info.h"

namespace base
{

////////////////////////////////////////

uri::uri( char *str )
{
	parse( str );
	while ( *str != '\0' )
	{
		*str = '*';
		++str;
	}
}

////////////////////////////////////////

std::string
uri::full_path( void ) const
{
	if ( _path.empty() )
		return std::string( '/', 1 );

	std::string ret;
	size_t n = 0;
	for ( auto &p: _path )
		n += p.size() + 1;
	ret.reserve( n );
	for ( auto &p: _path )
	{
		ret.push_back( '/' );
		ret.append( p );
	}
	return ret;
}

////////////////////////////////////////

std::vector<std::pair<std::string, std::string>>
uri::parse_query( char kv_sep, char arg_sep ) const
{
	std::vector<std::pair<std::string, std::string>> ret;
	if ( _raw_query.empty() )
		return ret;

	std::vector<std::string> args;
	base::split( _raw_query, arg_sep, std::back_inserter( args ), false );
	for ( auto &a: args )
	{
		std::string::size_type kvPos = a.find_first_of( kv_sep );
		if ( kvPos == std::string::npos )
			throw_runtime( "invalid key/value argument '{0}' - no separator '{2}'", a, kv_sep );

		std::string k = a.substr( 0, kvPos );
		std::string v = a.substr( kvPos + 1 );
		// NOW we unescape
		ret.emplace_back( std::make_pair( unescape( k ), unescape( v ) ) );
	}

	return ret;
}

////////////////////////////////////////

std::string uri::escape( cstring str )
{
	const cstring reserved = ":/?#[]@!$&'()*+,;=";
	std::string result;
	size_t i = 0;
	size_t n = str.find_first_of( reserved, i );
   	while ( n != cstring::npos )
	{
		result.append( str.data() + i, n - i );
		i = n;
		if ( i < str.size() )
		{
			result.append( base::format( "%{0,B16,w2}", int(str[i]) ) );
			++i;
		}
		n = str.find_first_of( reserved, i );
	}
	result.append( str.data() + i, std::min( str.size() - i, n ) );

	return result;
}

////////////////////////////////////////

std::string uri::unescape( cstring str )
{
	std::string result;
	result.reserve( str.size() );
	size_t i = 0;
	size_t n = str.find( '%', i );
   	while ( n != cstring::npos )
	{
		result.append( str.data() + i, n - i );
		i = n;
		if ( i < str.size() )
		{
			++i;
			if ( i+1 < str.size() )
			{
				if ( std::isxdigit( str[i] ) && std::isxdigit( str[i+1] ) )
					result.push_back( from_hex( str[i], str[i+1] ) );
				else
					throw_runtime( "invalid percent encoding at end: '{0}'", str );
			}
			else
				throw_runtime( "invalid percent encoding at end: '{0}'", str );
			i += 2;
		}
		n = str.find( '%', i );
	}
	result.append( str.data() + i, std::min( str.size() - i, n ) );

	return result;
}

////////////////////////////////////////

void uri::add_path( cstring path )
{
	split( path, '/', std::back_inserter( _path ), true );
}

////////////////////////////////////////

uri uri::root( void ) const
{
	uri result;
	result._scheme = _scheme;
	result._user = _user;
	result._host = _host;
	result._port = _port;
	return result;
}

////////////////////////////////////////

void uri::split_query( std::vector<std::pair<std::string,std::string>> &parsed )
{
	std::vector<std::string> list;
	split( list, _query, '&', true );
	for ( auto &q: list )
	{
		std::vector<std::string> fv;
		split( fv, q, '=' );
		if ( fv.size() != 2 )
			throw_runtime( "invalid field/value query '{0}'", q );
		parsed.emplace_back( std::move( fv[0] ), std::move( fv[1] ) );
	}
}

////////////////////////////////////////

std::string uri::pretty( void ) const
{
	std::stringstream out;
	out << scheme() << "://";
	if ( !host().empty() )
	{
		if ( !user().empty() )
			out << user() << '@';
		out << host();
		if ( port() != 0 )
			out << ':' << to_string( port() );
	}
	for ( auto &p: path() )
		out << '/' << p;
	if ( !query().empty() )
		out << '?' << query();
	if ( !fragment().empty() )
		out << '#' << fragment();
	return out.str();
}

////////////////////////////////////////

void uri::parse( cstring str )
{
	if ( str.empty() )
		return;

	cstring path;

	size_t colon = str.find( ':' );
	if ( colon == cstring::npos || str[0] == '/' || str[0] == '~' )
	{
		_scheme = "file";
		// assume it's a file path
		if ( str[0] == '~' )
		{
			size_t slpos = str.find( '/' );
			cstring user = str.substr( 1, slpos );
			user_info uinf( user );
			add_path( uinf.home_dir() );
			if ( slpos != cstring::npos )
				path = str.substr( slpos + 1 );
		}
		else
		{
			if ( str[0] != '/' )
			{
				// get the current directory from the default filesystem
				uri tmp = file_system::get( _scheme )->current_path();
				_path = tmp._path;
			}

			path = str;
		}
	}
	else if ( str.size() > 2 && str[0] == '\\' && str[1] == '\\' )
	{
		// unc-like path
		throw_not_yet();
	}
	else
	{
		size_t question = str.find( '?', colon );
		size_t hash = str.find( '#', colon );

		if ( hash < question )
			question = cstring::npos;

		_scheme = unescape( str.substr( 0, colon ) );
		if ( colon < question )
			path = str.substr( colon + 1, std::min( hash, question ) - colon - 1 );
		if ( question < hash )
		{
			// stash the raw / unescaped to allow splitting
			_raw_query = str.substr( question + 1, hash - question - 1 );
			_query = unescape( _raw_query );
		}
		if ( hash != cstring::npos )
			_fragment = unescape( str.substr( hash + 1 ) );

		if ( path.empty() )
			throw_runtime( "invalid uri with no path: '{0}'", str );

		if ( begins_with( path, "//" ) )
		{
			size_t slash = path.find( '/', 2 );
			auto auth = path.substr( 2, slash - 2 );
			path.remove_prefix( slash );
			parse_authority( auth );
		}
		else if ( path[0] != '/' )
			throw_runtime( "expected uri path to start with slash: '{0}'", str );
	}

	add_path( path );
	for ( auto &p: _path )
		p = unescape( p );
}

////////////////////////////////////////

void uri::parse_authority( cstring auth )
{
	if ( auth.empty() )
		return;

	size_t at = auth.find( '@' );
	if ( at == cstring::npos )
		at = 0;
	else
		at = at + 1;
	size_t pcolon = auth.find( ':', at );

	if ( at > 0 && at < auth.size() )
		_user = unescape( auth.substr( 0, at - 1 ) );
	_host = unescape( auth.substr( at, pcolon - at ) );
	if ( pcolon < auth.size() )
		_port = static_cast<uint16_t>( stoul( auth.substr( pcolon + 1 ) ) );
	else
		_port = 0;
}

////////////////////////////////////////

std::ostream &operator<<( std::ostream &out, const uri &u )
{
	out << uri::escape( u.scheme() ) << ':';
	if ( !u.host().empty() )
	{
		out << "//";
		if ( !u.user().empty() )
			out << uri::escape( u.user() ) << '@';
		out << uri::escape( u.host() );
		if ( u.port() != 0 )
			out << ':' << to_string( u.port() );
	}
	for ( auto &p: u.path() )
		out << '/' << uri::escape( p );
	if ( !u.query().empty() )
		out << '?' << uri::escape( u.query() );
	if ( !u.fragment().empty() )
		out << '#' << uri::escape( u.fragment() );
	return out;
}

////////////////////////////////////////

}

<commit_msg>handle empty user tilde-slash<commit_after>
#include "uri.h"
#include "string_util.h"
#include "contract.h"
#include <algorithm>
#include "file_system.h"
#include "user_info.h"

namespace base
{

////////////////////////////////////////

uri::uri( char *str )
{
	parse( str );
	while ( *str != '\0' )
	{
		*str = '*';
		++str;
	}
}

////////////////////////////////////////

std::string
uri::full_path( void ) const
{
	if ( _path.empty() )
		return std::string( '/', 1 );

	std::string ret;
	size_t n = 0;
	for ( auto &p: _path )
		n += p.size() + 1;
	ret.reserve( n );
	for ( auto &p: _path )
	{
		ret.push_back( '/' );
		ret.append( p );
	}
	return ret;
}

////////////////////////////////////////

std::vector<std::pair<std::string, std::string>>
uri::parse_query( char kv_sep, char arg_sep ) const
{
	std::vector<std::pair<std::string, std::string>> ret;
	if ( _raw_query.empty() )
		return ret;

	std::vector<std::string> args;
	base::split( _raw_query, arg_sep, std::back_inserter( args ), false );
	for ( auto &a: args )
	{
		std::string::size_type kvPos = a.find_first_of( kv_sep );
		if ( kvPos == std::string::npos )
			throw_runtime( "invalid key/value argument '{0}' - no separator '{2}'", a, kv_sep );

		std::string k = a.substr( 0, kvPos );
		std::string v = a.substr( kvPos + 1 );
		// NOW we unescape
		ret.emplace_back( std::make_pair( unescape( k ), unescape( v ) ) );
	}

	return ret;
}

////////////////////////////////////////

std::string uri::escape( cstring str )
{
	const cstring reserved = ":/?#[]@!$&'()*+,;=";
	std::string result;
	size_t i = 0;
	size_t n = str.find_first_of( reserved, i );
   	while ( n != cstring::npos )
	{
		result.append( str.data() + i, n - i );
		i = n;
		if ( i < str.size() )
		{
			result.append( base::format( "%{0,B16,w2}", int(str[i]) ) );
			++i;
		}
		n = str.find_first_of( reserved, i );
	}
	result.append( str.data() + i, std::min( str.size() - i, n ) );

	return result;
}

////////////////////////////////////////

std::string uri::unescape( cstring str )
{
	std::string result;
	result.reserve( str.size() );
	size_t i = 0;
	size_t n = str.find( '%', i );
   	while ( n != cstring::npos )
	{
		result.append( str.data() + i, n - i );
		i = n;
		if ( i < str.size() )
		{
			++i;
			if ( i+1 < str.size() )
			{
				if ( std::isxdigit( str[i] ) && std::isxdigit( str[i+1] ) )
					result.push_back( from_hex( str[i], str[i+1] ) );
				else
					throw_runtime( "invalid percent encoding at end: '{0}'", str );
			}
			else
				throw_runtime( "invalid percent encoding at end: '{0}'", str );
			i += 2;
		}
		n = str.find( '%', i );
	}
	result.append( str.data() + i, std::min( str.size() - i, n ) );

	return result;
}

////////////////////////////////////////

void uri::add_path( cstring path )
{
	split( path, '/', std::back_inserter( _path ), true );
}

////////////////////////////////////////

uri uri::root( void ) const
{
	uri result;
	result._scheme = _scheme;
	result._user = _user;
	result._host = _host;
	result._port = _port;
	return result;
}

////////////////////////////////////////

void uri::split_query( std::vector<std::pair<std::string,std::string>> &parsed )
{
	std::vector<std::string> list;
	split( list, _query, '&', true );
	for ( auto &q: list )
	{
		std::vector<std::string> fv;
		split( fv, q, '=' );
		if ( fv.size() != 2 )
			throw_runtime( "invalid field/value query '{0}'", q );
		parsed.emplace_back( std::move( fv[0] ), std::move( fv[1] ) );
	}
}

////////////////////////////////////////

std::string uri::pretty( void ) const
{
	std::stringstream out;
	out << scheme() << "://";
	if ( !host().empty() )
	{
		if ( !user().empty() )
			out << user() << '@';
		out << host();
		if ( port() != 0 )
			out << ':' << to_string( port() );
	}
	for ( auto &p: path() )
		out << '/' << p;
	if ( !query().empty() )
		out << '?' << query();
	if ( !fragment().empty() )
		out << '#' << fragment();
	return out.str();
}

////////////////////////////////////////

void uri::parse( cstring str )
{
	if ( str.empty() )
		return;

	cstring path;

	size_t colon = str.find( ':' );
	if ( colon == cstring::npos || str[0] == '/' || str[0] == '~' )
	{
		_scheme = "file";
		// assume it's a file path
		if ( str[0] == '~' )
		{
			size_t slpos = str.find( '/' );
			cstring user;
			if ( slpos != 1 )
				user = str.substr( 1, slpos );
			user_info uinf( user );
			add_path( uinf.home_dir() );
			if ( slpos != cstring::npos )
				path = str.substr( slpos + 1 );
		}
		else
		{
			if ( str[0] != '/' )
			{
				// get the current directory from the default filesystem
				uri tmp = file_system::get( _scheme )->current_path();
				_path = tmp._path;
			}

			path = str;
		}
	}
	else if ( str.size() > 2 && str[0] == '\\' && str[1] == '\\' )
	{
		// unc-like path
		throw_not_yet();
	}
	else
	{
		size_t question = str.find( '?', colon );
		size_t hash = str.find( '#', colon );

		if ( hash < question )
			question = cstring::npos;

		_scheme = unescape( str.substr( 0, colon ) );
		if ( colon < question )
			path = str.substr( colon + 1, std::min( hash, question ) - colon - 1 );
		if ( question < hash )
		{
			// stash the raw / unescaped to allow splitting
			_raw_query = str.substr( question + 1, hash - question - 1 );
			_query = unescape( _raw_query );
		}
		if ( hash != cstring::npos )
			_fragment = unescape( str.substr( hash + 1 ) );

		if ( path.empty() )
			throw_runtime( "invalid uri with no path: '{0}'", str );

		if ( begins_with( path, "//" ) )
		{
			size_t slash = path.find( '/', 2 );
			auto auth = path.substr( 2, slash - 2 );
			path.remove_prefix( slash );
			parse_authority( auth );
		}
		else if ( path[0] != '/' )
			throw_runtime( "expected uri path to start with slash: '{0}'", str );
	}

	add_path( path );
	for ( auto &p: _path )
		p = unescape( p );
}

////////////////////////////////////////

void uri::parse_authority( cstring auth )
{
	if ( auth.empty() )
		return;

	size_t at = auth.find( '@' );
	if ( at == cstring::npos )
		at = 0;
	else
		at = at + 1;
	size_t pcolon = auth.find( ':', at );

	if ( at > 0 && at < auth.size() )
		_user = unescape( auth.substr( 0, at - 1 ) );
	_host = unescape( auth.substr( at, pcolon - at ) );
	if ( pcolon < auth.size() )
		_port = static_cast<uint16_t>( stoul( auth.substr( pcolon + 1 ) ) );
	else
		_port = 0;
}

////////////////////////////////////////

std::ostream &operator<<( std::ostream &out, const uri &u )
{
	out << uri::escape( u.scheme() ) << ':';
	if ( !u.host().empty() )
	{
		out << "//";
		if ( !u.user().empty() )
			out << uri::escape( u.user() ) << '@';
		out << uri::escape( u.host() );
		if ( u.port() != 0 )
			out << ':' << to_string( u.port() );
	}
	for ( auto &p: u.path() )
		out << '/' << uri::escape( p );
	if ( !u.query().empty() )
		out << '?' << uri::escape( u.query() );
	if ( !u.fragment().empty() )
		out << '#' << uri::escape( u.fragment() );
	return out;
}

////////////////////////////////////////

}

<|endoftext|>


<commit_before>/*
	This file is part of cpp-ethereum.

	cpp-ethereum is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	cpp-ethereum 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 cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/**
 * @author Christian <c@ethdev.com>
 * @date 2014
 * Utilities for the solidity compiler.
 */

#include <utility>
#include <numeric>
#include <libsolidity/AST.h>
#include <libsolidity/Compiler.h>

using namespace std;

namespace dev
{
namespace solidity
{

void CompilerContext::addMagicGlobal(MagicVariableDeclaration const& _declaration)
{
	m_magicGlobals.insert(&_declaration);
}

void CompilerContext::addStateVariable(VariableDeclaration const& _declaration)
{
	m_stateVariables[&_declaration] = m_stateVariablesSize;
	m_stateVariablesSize += _declaration.getType()->getStorageSize();
}

void CompilerContext::startFunction(Declaration const& _function)
{
	m_functionsWithCode.insert(&_function);
	m_localVariables.clear();
	m_asm.setDeposit(0);
	*this << getFunctionEntryLabel(_function);
}

void CompilerContext::addVariable(VariableDeclaration const& _declaration,
								  unsigned _offsetToCurrent)
{
	solAssert(m_asm.deposit() >= 0 && unsigned(m_asm.deposit()) >= _offsetToCurrent, "");
	m_localVariables[&_declaration] = unsigned(m_asm.deposit()) - _offsetToCurrent;
}

void CompilerContext::addAndInitializeVariable(VariableDeclaration const& _declaration)
{
	addVariable(_declaration);

	int const size = _declaration.getType()->getSizeOnStack();
	for (int i = 0; i < size; ++i)
		*this << u256(0);
}

bytes const& CompilerContext::getCompiledContract(const ContractDefinition& _contract) const
{
	auto ret = m_compiledContracts.find(&_contract);
	solAssert(ret != m_compiledContracts.end(), "Compiled contract not found.");
	return *ret->second;
}

bool CompilerContext::isLocalVariable(Declaration const* _declaration) const
{
	return m_localVariables.count(_declaration);
}

eth::AssemblyItem CompilerContext::getFunctionEntryLabel(Declaration const& _declaration)
{
	auto res = m_functionEntryLabels.find(&_declaration);
	if (res == m_functionEntryLabels.end())
	{
		eth::AssemblyItem tag(m_asm.newTag());
		m_functionEntryLabels.insert(make_pair(&_declaration, tag));
		return tag.tag();
	}
	else
		return res->second.tag();
}

eth::AssemblyItem CompilerContext::getVirtualFunctionEntryLabel(FunctionDefinition const& _function)
{
	solAssert(!m_inheritanceHierarchy.empty(), "No inheritance hierarchy set.");
	for (ContractDefinition const* contract: m_inheritanceHierarchy)
		for (ASTPointer<FunctionDefinition> const& function: contract->getDefinedFunctions())
			if (!function->isConstructor() && function->getName() == _function.getName())
				return getFunctionEntryLabel(*function);
	solAssert(false, "Virtual function " + _function.getName() + " not found.");
	return m_asm.newTag(); // not reached
}

eth::AssemblyItem CompilerContext::getSuperFunctionEntryLabel(string const& _name, ContractDefinition const& _base)
{
	// search for first contract after _base
	solAssert(!m_inheritanceHierarchy.empty(), "No inheritance hierarchy set.");
	auto it = find(m_inheritanceHierarchy.begin(), m_inheritanceHierarchy.end(), &_base);
	solAssert(it != m_inheritanceHierarchy.end(), "Base not found in inheritance hierarchy.");
	for (++it; it != m_inheritanceHierarchy.end(); ++it)
		for (ASTPointer<FunctionDefinition> const& function: (*it)->getDefinedFunctions())
			if (!function->isConstructor() && function->getName() == _name)
				return getFunctionEntryLabel(*function);
	solAssert(false, "Super function " + _name + " not found.");
	return m_asm.newTag(); // not reached
}

set<Declaration const*> CompilerContext::getFunctionsWithoutCode()
{
	set<Declaration const*> functions;
	for (auto const& it: m_functionEntryLabels)
		if (m_functionsWithCode.count(it.first) == 0)
			functions.insert(it.first);
	return move(functions);
}

ModifierDefinition const& CompilerContext::getFunctionModifier(string const& _name) const
{
	solAssert(!m_inheritanceHierarchy.empty(), "No inheritance hierarchy set.");
	for (ContractDefinition const* contract: m_inheritanceHierarchy)
		for (ASTPointer<ModifierDefinition> const& modifier: contract->getFunctionModifiers())
			if (modifier->getName() == _name)
				return *modifier.get();
	BOOST_THROW_EXCEPTION(InternalCompilerError()
						  << errinfo_comment("Function modifier " + _name + " not found."));
}

unsigned CompilerContext::getBaseStackOffsetOfVariable(Declaration const& _declaration) const
{
	auto res = m_localVariables.find(&_declaration);
	solAssert(res != m_localVariables.end(), "Variable not found on stack.");
	return res->second;
}

unsigned CompilerContext::baseToCurrentStackOffset(unsigned _baseOffset) const
{
	return m_asm.deposit() - _baseOffset - 1;
}

unsigned CompilerContext::currentToBaseStackOffset(unsigned _offset) const
{
	return m_asm.deposit() - _offset - 1;
}

u256 CompilerContext::getStorageLocationOfVariable(const Declaration& _declaration) const
{
	auto it = m_stateVariables.find(&_declaration);
	solAssert(it != m_stateVariables.end(), "Variable not found in storage.");
	return it->second;
}

}
}
<commit_msg>Some windows fixes.<commit_after>/*
	This file is part of cpp-ethereum.

	cpp-ethereum is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	cpp-ethereum 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 cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/**
 * @author Christian <c@ethdev.com>
 * @date 2014
 * Utilities for the solidity compiler.
 */

#include <utility>
#include <numeric>
#include <libsolidity/AST.h>
#include <libsolidity/Compiler.h>

using namespace std;

namespace dev
{
namespace solidity
{

void CompilerContext::addMagicGlobal(MagicVariableDeclaration const& _declaration)
{
	m_magicGlobals.insert(&_declaration);
}

void CompilerContext::addStateVariable(VariableDeclaration const& _declaration)
{
	m_stateVariables[&_declaration] = m_stateVariablesSize;
	m_stateVariablesSize += _declaration.getType()->getStorageSize();
}

void CompilerContext::startFunction(Declaration const& _function)
{
	m_functionsWithCode.insert(&_function);
	m_localVariables.clear();
	m_asm.setDeposit(0);
	*this << getFunctionEntryLabel(_function);
}

void CompilerContext::addVariable(VariableDeclaration const& _declaration,
								  unsigned _offsetToCurrent)
{
	solAssert(m_asm.deposit() >= 0 && unsigned(m_asm.deposit()) >= _offsetToCurrent, "");
	m_localVariables[&_declaration] = unsigned(m_asm.deposit()) - _offsetToCurrent;
}

void CompilerContext::addAndInitializeVariable(VariableDeclaration const& _declaration)
{
	addVariable(_declaration);

	int const size = _declaration.getType()->getSizeOnStack();
	for (int i = 0; i < size; ++i)
		*this << u256(0);
}

bytes const& CompilerContext::getCompiledContract(const ContractDefinition& _contract) const
{
	auto ret = m_compiledContracts.find(&_contract);
	solAssert(ret != m_compiledContracts.end(), "Compiled contract not found.");
	return *ret->second;
}

bool CompilerContext::isLocalVariable(Declaration const* _declaration) const
{
	return !!m_localVariables.count(_declaration);
}

eth::AssemblyItem CompilerContext::getFunctionEntryLabel(Declaration const& _declaration)
{
	auto res = m_functionEntryLabels.find(&_declaration);
	if (res == m_functionEntryLabels.end())
	{
		eth::AssemblyItem tag(m_asm.newTag());
		m_functionEntryLabels.insert(make_pair(&_declaration, tag));
		return tag.tag();
	}
	else
		return res->second.tag();
}

eth::AssemblyItem CompilerContext::getVirtualFunctionEntryLabel(FunctionDefinition const& _function)
{
	solAssert(!m_inheritanceHierarchy.empty(), "No inheritance hierarchy set.");
	for (ContractDefinition const* contract: m_inheritanceHierarchy)
		for (ASTPointer<FunctionDefinition> const& function: contract->getDefinedFunctions())
			if (!function->isConstructor() && function->getName() == _function.getName())
				return getFunctionEntryLabel(*function);
	solAssert(false, "Virtual function " + _function.getName() + " not found.");
	return m_asm.newTag(); // not reached
}

eth::AssemblyItem CompilerContext::getSuperFunctionEntryLabel(string const& _name, ContractDefinition const& _base)
{
	// search for first contract after _base
	solAssert(!m_inheritanceHierarchy.empty(), "No inheritance hierarchy set.");
	auto it = find(m_inheritanceHierarchy.begin(), m_inheritanceHierarchy.end(), &_base);
	solAssert(it != m_inheritanceHierarchy.end(), "Base not found in inheritance hierarchy.");
	for (++it; it != m_inheritanceHierarchy.end(); ++it)
		for (ASTPointer<FunctionDefinition> const& function: (*it)->getDefinedFunctions())
			if (!function->isConstructor() && function->getName() == _name)
				return getFunctionEntryLabel(*function);
	solAssert(false, "Super function " + _name + " not found.");
	return m_asm.newTag(); // not reached
}

set<Declaration const*> CompilerContext::getFunctionsWithoutCode()
{
	set<Declaration const*> functions;
	for (auto const& it: m_functionEntryLabels)
		if (m_functionsWithCode.count(it.first) == 0)
			functions.insert(it.first);
	return move(functions);
}

ModifierDefinition const& CompilerContext::getFunctionModifier(string const& _name) const
{
	solAssert(!m_inheritanceHierarchy.empty(), "No inheritance hierarchy set.");
	for (ContractDefinition const* contract: m_inheritanceHierarchy)
		for (ASTPointer<ModifierDefinition> const& modifier: contract->getFunctionModifiers())
			if (modifier->getName() == _name)
				return *modifier.get();
	BOOST_THROW_EXCEPTION(InternalCompilerError()
						  << errinfo_comment("Function modifier " + _name + " not found."));
}

unsigned CompilerContext::getBaseStackOffsetOfVariable(Declaration const& _declaration) const
{
	auto res = m_localVariables.find(&_declaration);
	solAssert(res != m_localVariables.end(), "Variable not found on stack.");
	return res->second;
}

unsigned CompilerContext::baseToCurrentStackOffset(unsigned _baseOffset) const
{
	return m_asm.deposit() - _baseOffset - 1;
}

unsigned CompilerContext::currentToBaseStackOffset(unsigned _offset) const
{
	return m_asm.deposit() - _offset - 1;
}

u256 CompilerContext::getStorageLocationOfVariable(const Declaration& _declaration) const
{
	auto it = m_stateVariables.find(&_declaration);
	solAssert(it != m_stateVariables.end(), "Variable not found in storage.");
	return it->second;
}

}
}
<|endoftext|>


<commit_before>#include "builtin_procedure.hh"
#include "lisp_ptr.hh"
#include "vm.hh"
#include "builtin_util.hh"
#include "procedure.hh"
#include "eval.hh"
#include "util.hh"
#include "delay.hh"

using namespace std;

Lisp_ptr type_check_procedure(){
  ZsArgs args;
  return Lisp_ptr{is_procedure(args[0])};
}

Lisp_ptr apply_func(){
  std::vector<Lisp_ptr> args;
  stack_to_vector(vm.stack, args);

  if(!is_procedure(args[0])){
    throw zs_error("apply error: first arg is not procedure (%s)\n",
                        stringify(args[0].tag()));
  }

  // simulating function_call()
  int argc = 0;
  for(auto i = std::next(args.begin()), e = args.end(); i != e; ++i){
    if(i->tag() == Ptr_tag::cons){
      for(auto p : *i){
        vm.stack.push_back(p);
        ++argc;
      }
    }else{
      vm.stack.push_back(*i);
      ++argc;
    }
  }
  vm.stack.push_back({Ptr_tag::vm_argcount, argc});

  proc_enter_entrypoint(args[0]); // direct jump to proc_enter()
  return {};
}

Lisp_ptr func_force(){
  ZsArgs args;

  auto d = args[0].get<Delay*>();
  if(!d){
    return args[0];
  }

  if(d->forced()){
    return d->get();
  }

  // evaluates Delay's contents
  args.~ZsArgs();

  auto oldenv = vm.frame();
  vm.set_frame(d->env());
  vm.stack.push_back(d);
  vm.code.insert(vm.code.end(),
                 {vm_op_force, oldenv, vm_op_leave_frame, d->get()});
  return {};
}

Lisp_ptr proc_values(){
  vm.return_value.clear();
  stack_to_vector(vm.stack, vm.return_value);
  return {};
}

Lisp_ptr call_with_values(){
  Lisp_ptr procs[2];
  {
    ZsArgs args;

    if(!is_procedure(args[0])){
      throw zs_error("call-with-values error: first arg is not procedure (%s)\n",
                          stringify(args[0].tag()));
    }

    auto info = get_procinfo(args[0]);
    if(info->required_args != 0){
      throw zs_error("call-with-values error: first arg takes 1 or more args (%d)\n",
                          info->required_args);
    }

    if(!is_procedure(args[1])){
      throw zs_error("call-with-values error: second arg is not procedure (%s)\n",
                          stringify(args[1].tag()));
    }

    std::copy(args.begin(), args.end(), procs);
  }

  // second proc call
  vm.code.insert(vm.code.end(), {procs[1], vm_op_proc_enter, vm_op_move_values});

  // first proc, calling with zero args.
  vm.stack.push_back({Ptr_tag::vm_argcount, 0});
  proc_enter_entrypoint(procs[0]); // direct jump to proc_enter()
  return {};
}

Lisp_ptr call_cc(){
  Lisp_ptr proc;
  {
    ZsArgs args;

    if(!is_procedure(args[0])){
      throw zs_error("call/cc error: first arg is not procedure (%s)\n",
                          stringify(args[0].tag()));
    }

    auto info = get_procinfo(args[0]);
    if(info->required_args != 1){
      throw zs_error("call/cc error: first arg mush take 1 arg (%d)\n",
                          info->required_args);
    }
    proc = args[0];
  }

  auto cont = new Continuation(vm);
  vm.stack.insert(vm.stack.end(), {cont, {Ptr_tag::vm_argcount, 1}});
  proc_enter_entrypoint(proc); // direct jump to proc_enter()
  return {};
}

Lisp_ptr dynamic_wind(){
  Lisp_ptr procs[3];
  {
    ZsArgs args;
    auto procs_i = begin(procs);

    for(auto p : args){
      if(!is_procedure(p)){
        throw zs_error("error: dynamic-wind: arg is not procedure (%s)\n",
                            stringify(p.tag()));
      }

      auto info = get_procinfo(p);
      if(info->required_args != 0){
        throw zs_error("error: dynamic-wind: first arg mush take 0 arg (%d)\n",
                            info->required_args);
      }

      *procs_i = p;
      ++procs_i;
    }
  }

  vm.extent.push_back({procs[0], procs[1], procs[2]});
  vm.code.push_back(vm_op_leave_winding);

  // third proc call
  vm.stack.push_back({Ptr_tag::vm_argcount, 0});
  vm.code.push_back(procs[2]);
  vm.code.push_back(vm_op_save_values_and_enter);

  // second proc call
  vm.stack.push_back({Ptr_tag::vm_argcount, 0});
  vm.code.push_back(procs[1]);
  vm.code.push_back(vm_op_proc_enter);

  // first proc, calling with zero args.
  vm.stack.push_back({Ptr_tag::vm_argcount, 0});
  proc_enter_entrypoint(procs[0]); // direct jump to proc_enter()
  return {};
}
<commit_msg>removed stack_to_vector() usage (partial)<commit_after>#include "builtin_procedure.hh"
#include "lisp_ptr.hh"
#include "vm.hh"
#include "builtin_util.hh"
#include "procedure.hh"
#include "eval.hh"
#include "util.hh"
#include "delay.hh"

using namespace std;

Lisp_ptr type_check_procedure(){
  ZsArgs args;
  return Lisp_ptr{is_procedure(args[0])};
}

Lisp_ptr apply_func(){
  ZsArgs args;

  auto proc = args[0];
  if(!is_procedure(proc)){
    throw zs_error("apply error: first arg is not procedure (%s)\n",
                   stringify(proc.tag()));
  }

  std::vector<Lisp_ptr> a_args(next(begin(args)), end(args));

  args.~ZsArgs();

  // simulating function_call()
  int argc = 0;
  for(auto i : a_args){
    if(i.tag() == Ptr_tag::cons){
      for(auto p : i){
        vm.stack.push_back(p);
        ++argc;
      }
    }else{
      vm.stack.push_back(i);
      ++argc;
    }
  }
  vm.stack.push_back({Ptr_tag::vm_argcount, argc});

  proc_enter_entrypoint(proc); // direct jump to proc_enter()
  return {};
}

Lisp_ptr func_force(){
  ZsArgs args;

  auto d = args[0].get<Delay*>();
  if(!d){
    return args[0];
  }

  if(d->forced()){
    return d->get();
  }

  // evaluates Delay's contents
  args.~ZsArgs();

  auto oldenv = vm.frame();
  vm.set_frame(d->env());
  vm.stack.push_back(d);
  vm.code.insert(vm.code.end(),
                 {vm_op_force, oldenv, vm_op_leave_frame, d->get()});
  return {};
}

Lisp_ptr proc_values(){
  ZsArgs args;
  vm.return_value.assign(begin(args), end(args));
  return {};
}

Lisp_ptr call_with_values(){
  Lisp_ptr procs[2];
  {
    ZsArgs args;

    if(!is_procedure(args[0])){
      throw zs_error("call-with-values error: first arg is not procedure (%s)\n",
                          stringify(args[0].tag()));
    }

    auto info = get_procinfo(args[0]);
    if(info->required_args != 0){
      throw zs_error("call-with-values error: first arg takes 1 or more args (%d)\n",
                          info->required_args);
    }

    if(!is_procedure(args[1])){
      throw zs_error("call-with-values error: second arg is not procedure (%s)\n",
                          stringify(args[1].tag()));
    }

    std::copy(args.begin(), args.end(), procs);
  }

  // second proc call
  vm.code.insert(vm.code.end(), {procs[1], vm_op_proc_enter, vm_op_move_values});

  // first proc, calling with zero args.
  vm.stack.push_back({Ptr_tag::vm_argcount, 0});
  proc_enter_entrypoint(procs[0]); // direct jump to proc_enter()
  return {};
}

Lisp_ptr call_cc(){
  Lisp_ptr proc;
  {
    ZsArgs args;

    if(!is_procedure(args[0])){
      throw zs_error("call/cc error: first arg is not procedure (%s)\n",
                          stringify(args[0].tag()));
    }

    auto info = get_procinfo(args[0]);
    if(info->required_args != 1){
      throw zs_error("call/cc error: first arg mush take 1 arg (%d)\n",
                          info->required_args);
    }
    proc = args[0];
  }

  auto cont = new Continuation(vm);
  vm.stack.insert(vm.stack.end(), {cont, {Ptr_tag::vm_argcount, 1}});
  proc_enter_entrypoint(proc); // direct jump to proc_enter()
  return {};
}

Lisp_ptr dynamic_wind(){
  Lisp_ptr procs[3];
  {
    ZsArgs args;
    auto procs_i = begin(procs);

    for(auto p : args){
      if(!is_procedure(p)){
        throw zs_error("error: dynamic-wind: arg is not procedure (%s)\n",
                            stringify(p.tag()));
      }

      auto info = get_procinfo(p);
      if(info->required_args != 0){
        throw zs_error("error: dynamic-wind: first arg mush take 0 arg (%d)\n",
                            info->required_args);
      }

      *procs_i = p;
      ++procs_i;
    }
  }

  vm.extent.push_back({procs[0], procs[1], procs[2]});
  vm.code.push_back(vm_op_leave_winding);

  // third proc call
  vm.stack.push_back({Ptr_tag::vm_argcount, 0});
  vm.code.push_back(procs[2]);
  vm.code.push_back(vm_op_save_values_and_enter);

  // second proc call
  vm.stack.push_back({Ptr_tag::vm_argcount, 0});
  vm.code.push_back(procs[1]);
  vm.code.push_back(vm_op_proc_enter);

  // first proc, calling with zero args.
  vm.stack.push_back({Ptr_tag::vm_argcount, 0});
  proc_enter_entrypoint(procs[0]); // direct jump to proc_enter()
  return {};
}
<|endoftext|>


<commit_before>//
//  main.cpp
//  Unit Tests
//
//  Created by Evan McCartney-Melstad on 12/31/14.
//  Copyright (c) 2014 Evan McCartney-Melstad. All rights reserved.
//

#define CATCH_CONFIG_MAIN  // This tells Catch to provide a main() - only do this in one cpp file
#include "../cPWP/generateSimulatedData.h"
#include "../cPWP/bamsToPWP.h"
#include "catch.hpp"
#include <string>

/*
TEST_CASE( "Simulated reads are generated", "[generateReads]" ) {
    // Make sure that the read simulation finishes
    REQUIRE( generateReadsAndMap(1, 0.01, "0.0", "300", "50", "1000000", "100", "1234", "scaffold_0.fasta") == 0);
}
 */

TEST_CASE( "Generate reference genome for simulation tests", "[generateReference]") {
    REQUIRE( createReferenceGenome(10000, 0.42668722, "simulatedReferenceGenome.fasta") == 0 );
}

TEST_CASE ( "Mutate a reference genome", "[mutateRefGenome]") {
    REQUIRE( createMutatedGenome("simulatedReferenceGenome.fasta", "simulatedReferenceGenomeMutated.fasta", 0.01) == 0);
}

TEST_CASE( "Generate sequence reads", "[perfectReads]") {
    REQUIRE( generatePerfectReads ("simulatedReferenceGenome.fasta", 1, 100, 300, "normalRef") == 0);
}

TEST_CASE( " Mapping first set of reads", "[mapReads]") {
    REQUIRE( mapReads("simulatedReferenceGenome.fasta", "normalRef_R1.fastq", "normalRef_R2.fastq", "normal.bam", "10") == 0);
}

TEST_CASE( "Generate sequence reads 2", "[perfectReads2]") {
    REQUIRE( generatePerfectReads ("simulatedReferenceGenomeMutated.fasta", 1, 100, 300, "mutatedRef") == 0);
}

TEST_CASE( " Mapping second set of reads", "[mapReads2]") {
    REQUIRE( mapReads("simulatedReferenceGenome.fasta", "mutatedRef_R1.fastq", "mutatedRef_R2.fastq", "mutated.bam", "10") == 0);
}

TEST_CASE( "Run ANGSD on simulated reads", "[runANGSD]" ) {
    REQUIRE( runANGSDforReadCounts("bamlist.txt", "angsdOut", "25", "angsdOutLog.txt") == 0);
}

/*

TEST_CASE( "Generate mutated reference genomes and simulate reads", "[genomeAndReadSim]") {
    REQUIRE( generateReadsAndMap(3, 0.01, "300", "25", "10000", "100", "1234", "simulatedReferenceGenome.fasta", "25") == 0);
}

TEST_CASE( "Run ANGSD on simulated reads", "[runANGSD]" ) {
    REQUIRE( runANGSDforReadCounts("bamlist.txt", "angsdOut", "25", "angsdOutLog.txt") == 0);
}

 */

TEST_CASE( "Convert ANGSD read counts to unsigned chars for major and minor counts", "[convertCountsToBinary]") {
    REQUIRE( convertANGSDcountsToBinary("angsdOut", "angsdOut.readCounts.binary", 2, 5000) == 0); // 3 individuals, not 2, because generateReadsAndMap actually generates n+1 individuals, since one individual is identical to the reference genome. And 5000 as a max because we don't want to exclude any loci for this test
}

TEST_CASE( "Calculate PWP from the binary representations of the ANGSD readcounts", "[calcPWP]") {
    REQUIRE( calcPWPfromBinaryFile ("angsdOut.readCounts.binary", 9998, 2) == 0);
}<commit_msg>Troubleshooting<commit_after>//
//  main.cpp
//  Unit Tests
//
//  Created by Evan McCartney-Melstad on 12/31/14.
//  Copyright (c) 2014 Evan McCartney-Melstad. All rights reserved.
//

#define CATCH_CONFIG_MAIN  // This tells Catch to provide a main() - only do this in one cpp file
#include "../cPWP/generateSimulatedData.h"
#include "../cPWP/bamsToPWP.h"
#include "catch.hpp"
#include <string>

/*
TEST_CASE( "Simulated reads are generated", "[generateReads]" ) {
    // Make sure that the read simulation finishes
    REQUIRE( generateReadsAndMap(1, 0.01, "0.0", "300", "50", "1000000", "100", "1234", "scaffold_0.fasta") == 0);
}
 */

TEST_CASE( "Generate reference genome for simulation tests", "[generateReference]") {
    REQUIRE( createReferenceGenome(100000, 0.42668722, "simulatedReferenceGenome.fasta") == 0 );
}

TEST_CASE ( "Mutate a reference genome", "[mutateRefGenome]") {
    REQUIRE( createMutatedGenome("simulatedReferenceGenome.fasta", "simulatedReferenceGenomeMutated.fasta", 0.01) == 0);
}

TEST_CASE( "Generate sequence reads", "[perfectReads]") {
    REQUIRE( generatePerfectReads ("simulatedReferenceGenome.fasta", 1, 100, 300, "normalRef") == 0);
    //generatePerfectReads (std::string reference, unsigned int stagger, unsigned int readLengths, unsigned int fragmentLengths, std::string readPrefix);
}

TEST_CASE( " Mapping first set of reads", "[mapReads]") {
    REQUIRE( mapReads("simulatedReferenceGenome.fasta", "normalRef_R1.fastq", "normalRef_R2.fastq", "normal.bam", "10") == 0);
}

TEST_CASE( "Generate sequence reads 2", "[perfectReads2]") {
    REQUIRE( generatePerfectReads ("simulatedReferenceGenomeMutated.fasta", 1, 100, 300, "mutatedRef") == 0);
}

TEST_CASE( " Mapping second set of reads", "[mapReads2]") {
    REQUIRE( mapReads("simulatedReferenceGenome.fasta", "mutatedRef_R1.fastq", "mutatedRef_R2.fastq", "mutated.bam", "10") == 0);
}

TEST_CASE( "Run ANGSD on simulated reads", "[runANGSD]" ) {
    REQUIRE( runANGSDforReadCounts("bamlist.txt", "angsdOut", "25", "angsdOutLog.txt") == 0);
}

/*

TEST_CASE( "Generate mutated reference genomes and simulate reads", "[genomeAndReadSim]") {
    REQUIRE( generateReadsAndMap(3, 0.01, "300", "25", "10000", "100", "1234", "simulatedReferenceGenome.fasta", "25") == 0);
}

TEST_CASE( "Run ANGSD on simulated reads", "[runANGSD]" ) {
    REQUIRE( runANGSDforReadCounts("bamlist.txt", "angsdOut", "25", "angsdOutLog.txt") == 0);
}

 */

TEST_CASE( "Convert ANGSD read counts to unsigned chars for major and minor counts", "[convertCountsToBinary]") {
    REQUIRE( convertANGSDcountsToBinary("angsdOut", "angsdOut.readCounts.binary", 2, 5000) == 0); // 3 individuals, not 2, because generateReadsAndMap actually generates n+1 individuals, since one individual is identical to the reference genome. And 5000 as a max because we don't want to exclude any loci for this test
}

TEST_CASE( "Calculate PWP from the binary representations of the ANGSD readcounts", "[calcPWP]") {
    REQUIRE( calcPWPfromBinaryFile ("angsdOut.readCounts.binary", 100000, 2) == 0);
}<|endoftext|>