<commit_before>/*
 * unap.cpp
 *
 *  Created on: Apr 2, 2013
 *      Author: nikita.karnauhov@gmail.com
 */

#include "unap.h"
#include "formats.h"
#include "exception.h"

#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <netdb.h>
#include <poll.h>

#include <iostream>
#include <sstream>
#include <fstream>
#include <iomanip>
#include <random>

unsigned int UNAP::s_cSeed = 0;
std::default_random_engine UNAP::s_randomEngine = std::default_random_engine();

UNAP::UNAP() :
    strHost("127.0.0.1"), nPort(26751), nMTU(1500), m_nSockWorker(0), m_status(usStopped),
    m_nSocket(-1)
{
    if (s_cSeed == 0) {
        try {
            std::random_device rd;
            s_cSeed = rd();
        } catch (...) {
            s_cSeed = Clock::now().time_since_epoch().count();
        }

        s_randomEngine.seed(s_cSeed);
    }

    _reset(true);
    _init_descriptors();
}

UNAP::~UNAP() {
    if (m_nSocket >= -1)
        close(m_nSocket);
}

UNAP::Status UNAP::get_status() const {
    return m_status;
}

void UNAP::start() {
    _reset(false);
    m_status = usRunning;
    m_startTime = Clock::now();
    m_worker = std::thread(_make_worker());
}

void UNAP::stop() {
    if (m_status & usRunning)
        _send_stop();

    m_status = usStopped;

    if (m_worker.joinable())
        m_worker.join();
}

snd_pcm_sframes_t UNAP::get_buffer_pointer() const {
    if (!m_bPrepared)
        return 0;

    const snd_pcm_sframes_t frames = _estimate_frames();
    snd_pcm_sframes_t nPointer = std::min(frames, m_nPointer)%get_buffer_size();
    std::lock_guard<std::mutex> lock(m_mutex);

    if (nPointer == 0 && m_queue.empty() && m_nPointer > 0 && frames > 0)
        nPointer = get_buffer_size(); // Nothing more to play, buffer must have ran out.

    return nPointer;
}

snd_pcm_sframes_t UNAP::transfer(const char *_pData, size_t _cOffset, size_t _cSize) {
    assert(m_bPrepared);

    std::lock_guard<std::mutex> lock(m_mutex);

    size_t cSizeBytes = std::min<size_t>(_cSize, get_buffer_size() - m_nAvail);

    _cSize = cSizeBytes;
    cSizeBytes *= get_bytes_per_frame();

    if (cSizeBytes == 0)
        return 0;

    char *pStart = m_pBuffer.get();
    char *pDest = m_queue.empty() ? m_pBuffer.get() : m_queue.back().second;
    const char *pSrc = _pData + _cOffset*get_bytes_per_frame();
    const size_t cBufferBytes = get_buffer_size()*get_bytes_per_frame();

    if (pDest < pStart + cBufferBytes) {
        const size_t cPart = std::min(cSizeBytes, cBufferBytes - (pDest - pStart));
        memcpy(pDest, pSrc, cPart);
        m_queue.emplace_back(pDest, pDest + cPart);
        cSizeBytes -= cPart;
        pSrc += cPart;
        assert(m_queue.back().second > m_queue.back().first);
    }

    if (cSizeBytes > 0) {
        assert(cSizeBytes < cBufferBytes);
        memcpy(pStart, pSrc, cSizeBytes);
        m_queue.emplace_back(pStart, pStart + cSizeBytes);
        assert(m_queue.back().second > m_queue.back().first);
    }

    m_nAvail += _cSize;

    return _cSize;
}

void UNAP::prepare() {
    _reset(true);
    m_nAvail = 0;
    m_strFormat = get_format_name(get_format());
    m_cBitsPerSample = snd_pcm_format_physical_width(get_format());
    assert(get_bytes_per_frame() > 0);
    assert(get_buffer_size() > 0);
    std::unique_ptr<char[]> pBuffer(new char[get_buffer_size()*get_bytes_per_frame()]);
    m_pBuffer = std::move(pBuffer);
    m_bPrepared = true;
}

void UNAP::drain() {
    assert(m_bPrepared);
    m_status = usStopping;
    if (m_worker.joinable())
        m_worker.join();
}

void UNAP::pause() {
    assert(m_bPrepared && m_status == usRunning);
    m_nLastFrames = _estimate_frames();
    m_status = usPaused;
    m_startTime = TimePoint();
}

void UNAP::unpause() {
    m_status = usRunning;
    m_startTime = Clock::now();
}

snd_pcm_sframes_t UNAP::get_unplayed_frames() const {
    return m_nAvail; // TODO m_nPosition - estimateFrames
}

void UNAP::_reset(bool _bResetStreamParams) {
    m_nPointer = 0;
    m_nLastFrames = 0;
    m_startTime = TimePoint();
    m_cStreamId = s_randomEngine();

    if (_bResetStreamParams) {
        m_nAvail = 0;
        m_strFormat = "";
        m_cBitsPerSample = 0;
        m_queue.clear();
        m_bPrepared = false;
    }
}

void UNAP::_init_descriptors() {
    int fds[2];

    if (socketpair(AF_LOCAL, SOCK_STREAM, 0, fds) != 0)
        perror(__FUNCTION__);

    for (int fd : fds) {
        int fl;

        if ((fl = fcntl(fd, F_GETFL)) < 0) {
            perror(__FUNCTION__);
            break;
        }

        if (fl & O_NONBLOCK)
            break;

        if (fcntl(fd, F_SETFL, fl | O_NONBLOCK) < 0) {
            perror(__FUNCTION__);
            break;
        }
    }

    poll_fd = fds[0];
    m_nSockWorker = fds[1];
    poll_events = POLLIN;
}

snd_pcm_sframes_t UNAP::_estimate_frames() const {
    if (m_status == usPaused)
        return m_nLastFrames;
    DurationMS ms(std::chrono::duration_cast<DurationMS>(Clock::now() - m_startTime));
    return m_nLastFrames + ms.count()*(get_rate()/1000.0);
}

std::function<void(void)> UNAP::_make_worker() {
    return [&]() {
        if (!m_nSockWorker)
            return;

        Status prev = usRunning;

        while (m_status & usRunning) {
            if (prev == usRunning && m_status == usPaused)
                _send_pause();
            else if (prev == usPaused && m_status == usRunning)
                _send_unpause();

            if (!m_queue.empty()) {
                std::lock_guard<std::mutex> lock(m_mutex);

                while (!m_queue.empty())
                    _send_data();
            } else if (m_bPrepared && m_status == UNAP::usStopping && _estimate_frames() >= m_nPointer) {
                _send_stop();
                m_status = UNAP::usStopped;
            }

            char buf[1] = {0};
            write(m_nSockWorker, buf, 1);
            prev = m_status;
            std::this_thread::sleep_for(std::chrono::milliseconds(100));
        }
    };
}

void UNAP::_prepare_packet(unap::Packet &_packet, unap::Packet_Kind _kind,
        uint64_t _nTimestamp)
{
    _packet.set_version(1);
    _packet.set_stream(m_cStreamId);
    _packet.set_kind(_kind);
    _packet.set_channels(get_channel_count());
    _packet.set_rate(get_rate());
    _packet.set_format(m_strFormat);
    _packet.set_timestamp(_nTimestamp);

    if (_kind != unap::Packet_Kind_DATA)
        _packet.set_samples("");
}

void UNAP::_send_buffer(const void *_pBuf, size_t _cSize) {
    for (size_t cRetry = 0; cRetry < 5; ++cRetry) {
        if (send(m_nSocket, _pBuf, _cSize, 0) >= 0)
            break;

        if (errno != ECONNREFUSED)
            throw SystemError("send()");

        std::this_thread::sleep_for(std::chrono::milliseconds(1));
    }
}

void UNAP::_send_packet(const unap::Packet &_packet) {
    auto pBuf = std::unique_ptr<char[]>(new char[this->nMTU]);
    assert(_packet.ByteSize() <= this->nMTU);
    _packet.SerializeToArray((void *)pBuf.get(), this->nMTU);
    _send_buffer((const void *)pBuf.get(), _packet.ByteSize());
}

void UNAP::_send_stop() {
    unap::Packet packet;
    _prepare_packet(packet, unap::Packet_Kind_STOP, _estimate_frames());
    _send_packet(packet);
}

void UNAP::_send_pause() {
    unap::Packet packet;
    _prepare_packet(packet, unap::Packet_Kind_PAUSE, _estimate_frames());
    _send_packet(packet);
}

void UNAP::_send_unpause() {
    unap::Packet packet;
    _prepare_packet(packet, unap::Packet_Kind_UNPAUSE, m_nLastFrames);
    _send_packet(packet);
}

void UNAP::_send_data() {
    unap::Packet packet;

    assert(m_queue.front().second > m_queue.front().first);
    assert(m_bPrepared);
    _prepare_packet(packet, unap::Packet_Kind_DATA, m_nPointer);

    const size_t cHeaderSize = packet.ByteSize() + 4; // Account for data length field.
    const size_t cFrameSize = get_bytes_per_frame();
    const size_t cTotal = ((this->nMTU - cHeaderSize)/cFrameSize)*cFrameSize;
    size_t cBytes = cTotal;
    auto pBuf = std::unique_ptr<char[]>(new char[this->nMTU]); // Reuse as serialization buffer.
    char *pPos = pBuf.get();

    while (!m_queue.empty() && cBytes > 0) {
        char *pSource = m_queue.front().first;
        char *pEnd = m_queue.front().second;
        const size_t cAvailable = pEnd - pSource;

        if (cAvailable > 0) {
            const size_t c = std::min(cAvailable, (cBytes/cFrameSize)*cFrameSize);

            // FIXME c may equal zero.
            memcpy(pPos, pSource, c);

            pSource += c;
            pPos += c;
            cBytes -= c;
        }

        m_queue.front().first = pSource;

        assert(m_queue.front().second >= m_queue.front().first);

        if (pSource == pEnd)
            m_queue.pop_front();
    }

    packet.set_samples((const void *)pBuf.get(), cTotal - cBytes);
    m_nPointer += (cTotal - cBytes)/get_bytes_per_frame();
    m_nAvail -= (cTotal - cBytes)/get_bytes_per_frame();

    // Send.
    assert(packet.ByteSize() <= this->nMTU);
    packet.SerializeToArray((void *)pBuf.get(), this->nMTU);
    _send_buffer((const void *)pBuf.get(), packet.ByteSize());
}

void UNAP::connect() {
    struct sockaddr_in name;

    if (m_nSocket >= 0)
        close(m_nSocket);

    m_nSocket = socket(PF_INET, SOCK_DGRAM, 0);

    if (m_nSocket < 0)
        throw SystemError("socket()");

    name.sin_family = AF_INET;
    name.sin_port = htons(this->nPort);

    struct hostent *pHost = gethostbyname(this->strHost.c_str());

    if (!pHost)
        throw SystemError("gethostbyname()");

    name.sin_addr = *(struct in_addr *)pHost->h_addr;

    if (::connect(m_nSocket, (struct sockaddr *)&name, sizeof(name)) < 0)
        throw SystemError("connect()");
}

const std::vector<unsigned int> &UNAP::get_format_values() {
    m_formatValues.clear();

    for (const std::string &strFormat : formats) {
        auto iFormat = g_formats.find(strFormat);

        if (iFormat != g_formats.end())
            m_formatValues.push_back(iFormat->second);
    }

    return m_formatValues;
}

unsigned int UNAP::get_channel_count() const {
    return this->channels;
}

snd_pcm_uframes_t UNAP::get_buffer_size() const {
    return this->buffer_size;
}

snd_pcm_uframes_t UNAP::get_period_size() const {
    return this->buffer_size;
}

size_t UNAP::get_bytes_per_frame() const {
    return get_channel_count()*m_cBitsPerSample/8;
}

snd_pcm_format_t UNAP::get_format() const {
    return this->format;
}

unsigned int UNAP::get_rate() const {
    return this->rate;
}
<commit_msg>Use exceptions instead of perror().<commit_after>/*
 * unap.cpp
 *
 *  Created on: Apr 2, 2013
 *      Author: nikita.karnauhov@gmail.com
 */

#include "unap.h"
#include "formats.h"
#include "exception.h"

#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <netdb.h>
#include <poll.h>

#include <iostream>
#include <sstream>
#include <fstream>
#include <iomanip>
#include <random>

unsigned int UNAP::s_cSeed = 0;
std::default_random_engine UNAP::s_randomEngine = std::default_random_engine();

UNAP::UNAP() :
    strHost("127.0.0.1"), nPort(26751), nMTU(1500), m_nSockWorker(0), m_status(usStopped),
    m_nSocket(-1)
{
    if (s_cSeed == 0) {
        try {
            std::random_device rd;
            s_cSeed = rd();
        } catch (...) {
            s_cSeed = Clock::now().time_since_epoch().count();
        }

        s_randomEngine.seed(s_cSeed);
    }

    _reset(true);
    _init_descriptors();
}

UNAP::~UNAP() {
    if (m_nSocket >= -1)
        close(m_nSocket);
}

UNAP::Status UNAP::get_status() const {
    return m_status;
}

void UNAP::start() {
    _reset(false);
    m_status = usRunning;
    m_startTime = Clock::now();
    m_worker = std::thread(_make_worker());
}

void UNAP::stop() {
    if (m_status & usRunning)
        _send_stop();

    m_status = usStopped;

    if (m_worker.joinable())
        m_worker.join();
}

snd_pcm_sframes_t UNAP::get_buffer_pointer() const {
    if (!m_bPrepared)
        return 0;

    const snd_pcm_sframes_t frames = _estimate_frames();
    snd_pcm_sframes_t nPointer = std::min(frames, m_nPointer)%get_buffer_size();
    std::lock_guard<std::mutex> lock(m_mutex);

    if (nPointer == 0 && m_queue.empty() && m_nPointer > 0 && frames > 0)
        nPointer = get_buffer_size(); // Nothing more to play, buffer must have ran out.

    return nPointer;
}

snd_pcm_sframes_t UNAP::transfer(const char *_pData, size_t _cOffset, size_t _cSize) {
    assert(m_bPrepared);

    std::lock_guard<std::mutex> lock(m_mutex);

    size_t cSizeBytes = std::min<size_t>(_cSize, get_buffer_size() - m_nAvail);

    _cSize = cSizeBytes;
    cSizeBytes *= get_bytes_per_frame();

    if (cSizeBytes == 0)
        return 0;

    char *pStart = m_pBuffer.get();
    char *pDest = m_queue.empty() ? m_pBuffer.get() : m_queue.back().second;
    const char *pSrc = _pData + _cOffset*get_bytes_per_frame();
    const size_t cBufferBytes = get_buffer_size()*get_bytes_per_frame();

    if (pDest < pStart + cBufferBytes) {
        const size_t cPart = std::min(cSizeBytes, cBufferBytes - (pDest - pStart));
        memcpy(pDest, pSrc, cPart);
        m_queue.emplace_back(pDest, pDest + cPart);
        cSizeBytes -= cPart;
        pSrc += cPart;
        assert(m_queue.back().second > m_queue.back().first);
    }

    if (cSizeBytes > 0) {
        assert(cSizeBytes < cBufferBytes);
        memcpy(pStart, pSrc, cSizeBytes);
        m_queue.emplace_back(pStart, pStart + cSizeBytes);
        assert(m_queue.back().second > m_queue.back().first);
    }

    m_nAvail += _cSize;

    return _cSize;
}

void UNAP::prepare() {
    _reset(true);
    m_nAvail = 0;
    m_strFormat = get_format_name(get_format());
    m_cBitsPerSample = snd_pcm_format_physical_width(get_format());
    assert(get_bytes_per_frame() > 0);
    assert(get_buffer_size() > 0);
    std::unique_ptr<char[]> pBuffer(new char[get_buffer_size()*get_bytes_per_frame()]);
    m_pBuffer = std::move(pBuffer);
    m_bPrepared = true;
}

void UNAP::drain() {
    assert(m_bPrepared);
    m_status = usStopping;
    if (m_worker.joinable())
        m_worker.join();
}

void UNAP::pause() {
    assert(m_bPrepared && m_status == usRunning);
    m_nLastFrames = _estimate_frames();
    m_status = usPaused;
    m_startTime = TimePoint();
}

void UNAP::unpause() {
    m_status = usRunning;
    m_startTime = Clock::now();
}

snd_pcm_sframes_t UNAP::get_unplayed_frames() const {
    return m_nAvail; // TODO m_nPosition - estimateFrames
}

void UNAP::_reset(bool _bResetStreamParams) {
    m_nPointer = 0;
    m_nLastFrames = 0;
    m_startTime = TimePoint();
    m_cStreamId = s_randomEngine();

    if (_bResetStreamParams) {
        m_nAvail = 0;
        m_strFormat = "";
        m_cBitsPerSample = 0;
        m_queue.clear();
        m_bPrepared = false;
    }
}

void UNAP::_init_descriptors() {
    int fds[2];

    if (socketpair(AF_LOCAL, SOCK_STREAM, 0, fds) != 0)
        throw SystemError("socketpair()");

    for (int fd : fds) {
        int fl;

        if ((fl = fcntl(fd, F_GETFL)) < 0)
            throw SystemError("fcntl()");

        if (fl & O_NONBLOCK)
            break;

        if (fcntl(fd, F_SETFL, fl | O_NONBLOCK) < 0)
            throw SystemError("fcntl()");
    }

    poll_fd = fds[0];
    m_nSockWorker = fds[1];
    poll_events = POLLIN;
}

snd_pcm_sframes_t UNAP::_estimate_frames() const {
    if (m_status == usPaused)
        return m_nLastFrames;
    DurationMS ms(std::chrono::duration_cast<DurationMS>(Clock::now() - m_startTime));
    return m_nLastFrames + ms.count()*(get_rate()/1000.0);
}

std::function<void(void)> UNAP::_make_worker() {
    return [&]() {
        if (!m_nSockWorker)
            return;

        Status prev = usRunning;

        while (m_status & usRunning) {
            if (prev == usRunning && m_status == usPaused)
                _send_pause();
            else if (prev == usPaused && m_status == usRunning)
                _send_unpause();

            if (!m_queue.empty()) {
                std::lock_guard<std::mutex> lock(m_mutex);

                while (!m_queue.empty())
                    _send_data();
            } else if (m_bPrepared && m_status == UNAP::usStopping && _estimate_frames() >= m_nPointer) {
                _send_stop();
                m_status = UNAP::usStopped;
            }

            char buf[1] = {0};
            write(m_nSockWorker, buf, 1);
            prev = m_status;
            std::this_thread::sleep_for(std::chrono::milliseconds(100));
        }
    };
}

void UNAP::_prepare_packet(unap::Packet &_packet, unap::Packet_Kind _kind,
        uint64_t _nTimestamp)
{
    _packet.set_version(1);
    _packet.set_stream(m_cStreamId);
    _packet.set_kind(_kind);
    _packet.set_channels(get_channel_count());
    _packet.set_rate(get_rate());
    _packet.set_format(m_strFormat);
    _packet.set_timestamp(_nTimestamp);

    if (_kind != unap::Packet_Kind_DATA)
        _packet.set_samples("");
}

void UNAP::_send_buffer(const void *_pBuf, size_t _cSize) {
    for (size_t cRetry = 0; cRetry < 5; ++cRetry) {
        if (send(m_nSocket, _pBuf, _cSize, 0) >= 0)
            break;

        if (errno != ECONNREFUSED)
            throw SystemError("send()");

        std::this_thread::sleep_for(std::chrono::milliseconds(1));
    }
}

void UNAP::_send_packet(const unap::Packet &_packet) {
    auto pBuf = std::unique_ptr<char[]>(new char[this->nMTU]);
    assert(_packet.ByteSize() <= this->nMTU);
    _packet.SerializeToArray((void *)pBuf.get(), this->nMTU);
    _send_buffer((const void *)pBuf.get(), _packet.ByteSize());
}

void UNAP::_send_stop() {
    unap::Packet packet;
    _prepare_packet(packet, unap::Packet_Kind_STOP, _estimate_frames());
    _send_packet(packet);
}

void UNAP::_send_pause() {
    unap::Packet packet;
    _prepare_packet(packet, unap::Packet_Kind_PAUSE, _estimate_frames());
    _send_packet(packet);
}

void UNAP::_send_unpause() {
    unap::Packet packet;
    _prepare_packet(packet, unap::Packet_Kind_UNPAUSE, m_nLastFrames);
    _send_packet(packet);
}

void UNAP::_send_data() {
    unap::Packet packet;

    assert(m_queue.front().second > m_queue.front().first);
    assert(m_bPrepared);
    _prepare_packet(packet, unap::Packet_Kind_DATA, m_nPointer);

    const size_t cHeaderSize = packet.ByteSize() + 4; // Account for data length field.
    const size_t cFrameSize = get_bytes_per_frame();
    const size_t cTotal = ((this->nMTU - cHeaderSize)/cFrameSize)*cFrameSize;
    size_t cBytes = cTotal;
    auto pBuf = std::unique_ptr<char[]>(new char[this->nMTU]); // Reuse as serialization buffer.
    char *pPos = pBuf.get();

    while (!m_queue.empty() && cBytes > 0) {
        char *pSource = m_queue.front().first;
        char *pEnd = m_queue.front().second;
        const size_t cAvailable = pEnd - pSource;

        if (cAvailable > 0) {
            const size_t c = std::min(cAvailable, (cBytes/cFrameSize)*cFrameSize);

            // FIXME c may equal zero.
            memcpy(pPos, pSource, c);

            pSource += c;
            pPos += c;
            cBytes -= c;
        }

        m_queue.front().first = pSource;

        assert(m_queue.front().second >= m_queue.front().first);

        if (pSource == pEnd)
            m_queue.pop_front();
    }

    packet.set_samples((const void *)pBuf.get(), cTotal - cBytes);
    m_nPointer += (cTotal - cBytes)/get_bytes_per_frame();
    m_nAvail -= (cTotal - cBytes)/get_bytes_per_frame();

    // Send.
    assert(packet.ByteSize() <= this->nMTU);
    packet.SerializeToArray((void *)pBuf.get(), this->nMTU);
    _send_buffer((const void *)pBuf.get(), packet.ByteSize());
}

void UNAP::connect() {
    struct sockaddr_in name;

    if (m_nSocket >= 0)
        close(m_nSocket);

    m_nSocket = socket(PF_INET, SOCK_DGRAM, 0);

    if (m_nSocket < 0)
        throw SystemError("socket()");

    name.sin_family = AF_INET;
    name.sin_port = htons(this->nPort);

    struct hostent *pHost = gethostbyname(this->strHost.c_str());

    if (!pHost)
        throw SystemError("gethostbyname()");

    name.sin_addr = *(struct in_addr *)pHost->h_addr;

    if (::connect(m_nSocket, (struct sockaddr *)&name, sizeof(name)) < 0)
        throw SystemError("connect()");
}

const std::vector<unsigned int> &UNAP::get_format_values() {
    m_formatValues.clear();

    for (const std::string &strFormat : formats) {
        auto iFormat = g_formats.find(strFormat);

        if (iFormat != g_formats.end())
            m_formatValues.push_back(iFormat->second);
    }

    return m_formatValues;
}

unsigned int UNAP::get_channel_count() const {
    return this->channels;
}

snd_pcm_uframes_t UNAP::get_buffer_size() const {
    return this->buffer_size;
}

snd_pcm_uframes_t UNAP::get_period_size() const {
    return this->buffer_size;
}

size_t UNAP::get_bytes_per_frame() const {
    return get_channel_count()*m_cBitsPerSample/8;
}

snd_pcm_format_t UNAP::get_format() const {
    return this->format;
}

unsigned int UNAP::get_rate() const {
    return this->rate;
}
<|endoftext|>


<commit_before>//----------------------------------------------------------------------------
/// \file   variant.hpp
/// \author Serge Aleynikov
//----------------------------------------------------------------------------
/// \brief Variant class that represents a subtype of
/// boost::variant that can hold integer/bool/double/string values.
//----------------------------------------------------------------------------
// Created: 2010-07-10
//----------------------------------------------------------------------------
/*
***** BEGIN LICENSE BLOCK *****

This file is part of the utxx open-source project.

Copyright (C) 2010 Serge Aleynikov <saleyn@gmail.com>

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library 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
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

***** END LICENSE BLOCK *****
*/

#ifndef _UTXX_VARIANT_HPP_
#define _UTXX_VARIANT_HPP_

#include <boost/variant.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/find.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/joint_view.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/static_assert.hpp>
#include <boost/cstdint.hpp>
#include <boost/property_tree/detail/info_parser_utils.hpp>
#include <stdexcept>
#include <string.h>
#include <stdio.h>

namespace utxx {

struct null {};

class variant: public boost::variant<null, bool, long, double, std::string>
{
    typedef boost::variant    <null, bool, long, double, std::string> base;
    typedef boost::mpl::vector<null, bool, long, double, std::string> internal_types;

    struct string_visitor: public boost::static_visitor<std::string> {
        std::string operator () (null v) const { return "<NULL>";             }
        std::string operator () (bool v) const { return v ? "true" : "false"; }
        std::string operator () (long v) const { return std::to_string(v);    }
        std::string operator () (double v) const {
            char buf[128];
            snprintf(buf, sizeof(buf)-1, "%f", v);
            // Remove trailing zeros.
            for (char* p = buf+strlen(buf); p > buf && *(p-1) != '.'; p--)
                if (*p == '0')
                    *p = '\0';
            return buf;
        }
        std::string operator () (const std::string& v) const { return v; }
    };

    template <typename T>
    T              get(T*)       const { return boost::get<T>(*this); }
    const variant& get(variant*) const { return *this; }
    variant&       get(variant*)       { return *this; }
public:
    typedef boost::mpl::vector<
        int,int16_t,long,uint16_t,uint32_t,uint64_t> int_types;

    typedef boost::mpl::joint_view<
        int_types,
        boost::mpl::vector<null,bool,double,std::string>
    > valid_types;

    typedef boost::mpl::joint_view<
        int_types,
        boost::mpl::vector<null,bool,double,std::string,variant>
    > valid_get_types;

    // For integers - cast them all to long type
    template <typename T>
    class normal_type {
        typedef typename boost::mpl::find<int_types, T>::type int_iter;
    public:
        typedef
            typename boost::mpl::if_
                <boost::is_same<boost::mpl::end<int_types>::type, int_iter>,
                 T, long>::type
            type;
    };

    enum value_type {
          TYPE_NULL
        , TYPE_BOOL
        , TYPE_INT
        , TYPE_DOUBLE
        , TYPE_STRING
    };

    variant() : base(null()) {}
    explicit variant(bool       a) : base(a)        {}
    explicit variant(int16_t    a) : base((long)a)  {}
    explicit variant(int        a) : base((long)a)  {}
    explicit variant(long       a) : base(a)        {}
    explicit variant(uint16_t   a) : base((long)a)  {}
    explicit variant(uint32_t   a) : base((long)a)  {}
    explicit variant(uint64_t   a) : base((long)a)  {}
    explicit variant(double     a) : base(a)        {}

    template <class Ch>
    variant(const std::basic_string<Ch>& a) : base(to_std_string<Ch>(a)) {}
    variant(const char*                  a) : base(std::string(a)) {}
    variant(const std::string&           a) : base(a) {}

    variant(const variant& a) : base((const base&)a) {}

#if __cplusplus >= 201103L
    variant(variant&& a)            { swap(a); }
    variant& operator=(variant&& a) { clear(); swap(a); return *this; }
#endif

    variant(value_type v, const std::string& a) { from_string(v, a); }

    void operator= (const variant& a) { *(base*)this = (const base&)a; }
    //void operator= (null        a)  { *(base*)this = null(); }
    void operator= (int16_t     a)  { *(base*)this = (long)a; }
    void operator= (int         a)  { *(base*)this = (long)a; }
    void operator= (int64_t     a)  { *(base*)this = (long)a; }
    void operator= (uint16_t    a)  { *(base*)this = (long)a; }
    void operator= (uint32_t    a)  { *(base*)this = (long)a; }
    void operator= (uint64_t    a)  { *(base*)this = (long)a; }
    void operator= (const char* a)  { *(base*)this = std::string(a); }
    void operator= (const std::string& a) { *(base*)this = a; }
    void operator= (bool        a)  { variant b(a); *this = b; }

    template <typename T>
    void operator= (T a) {
        typedef typename boost::mpl::find<valid_types, T>::type type_iter;
        BOOST_STATIC_ASSERT(
            (!boost::is_same<
                boost::mpl::end<valid_types>::type,
                type_iter >::value)
        );
        *(base*)this = a;
    }

    void operator+= (int16_t     a)  { *(base*)this = is_null() ? a : to_int() + a; }
    void operator+= (int         a)  { *(base*)this = is_null() ? a : to_int() + a; }
    void operator+= (int64_t     a)  { *(base*)this = is_null() ? a : to_int() + a; }
    void operator+= (uint16_t    a)  { *(base*)this = is_null() ? a : to_int() + a; }
    void operator+= (uint32_t    a)  { *(base*)this = is_null() ? a : to_int() + a; }
    void operator+= (uint64_t    a)  { *(base*)this = is_null() ? (long)a : to_int()+(long)a; }
    void operator+= (double      a)  { *(base*)this = is_null() ? a : to_int() + a; }
    void operator+= (const char* a)  { *(base*)this = is_null() ? a : to_str() + a; }
    void operator+= (const std::string& a) { *(base*)this = is_null() ? a : to_str() + a; }

    template <typename T>
    void operator+= (T a) { throw std::runtime_error("Operation not supported!"); }

    value_type  type()     const { return static_cast<value_type>(which()); }
    const char* type_str() const {
        static const char* s_types[] = { "null", "bool", "int", "double", "string" };
        return s_types[type()];
    }

    /// Set value to null.
    void clear() { *(base*)this = null(); }

    /// Returns true if the value is null.
    bool is_null()      const { return type() == TYPE_NULL; }
    bool is_bool()      const { return type() == TYPE_BOOL; }
    bool is_int()       const { return type() == TYPE_INT;  }
    bool is_double()    const { return type() == TYPE_DOUBLE; }
    bool is_string()    const { return type() == TYPE_STRING; }

    template <typename T>
    bool is_type()      const {
        variant::type_visitor<T> v;
        return boost::apply_visitor(v, *this);
    }

    bool                to_bool()   const { return boost::get<bool>(*this); }
    long                to_int()    const { return boost::get<long>(*this); }
    long                to_float()  const { return boost::get<double>(*this); }
    const std::string&  to_str()    const { return boost::get<std::string>(*this); }
    const char*         c_str()     const { return boost::get<std::string>(
                                                    *this).c_str(); }

    /// Returns true if the variant doesn't contain a value or it's an empty string
    bool empty(bool a_check_empty_string = true) const {
        return is_null() || (a_check_empty_string && is_string() && to_str().empty());
    }

    /// Convert value to string.
    std::string to_string() const {
        variant::string_visitor v;
        return boost::apply_visitor(v, *this);
    }

    template <typename T>
    T get() const {
        // Make sure given type is a valid variant type.
        // Note to user: an error raised here indicates that
        // there's a compile-time attempt to convert a variant to
        // unsupported type.
        typedef typename boost::mpl::find<valid_get_types, T>::type valid_iter;
        BOOST_STATIC_ASSERT(
            (!boost::is_same<boost::mpl::end<valid_get_types>::type, valid_iter>::value));
        // For integers - cast them to long type when fetching from the variant.
        typename normal_type<T>::type* dummy(NULL);
        return get(dummy);
    }

    const variant& get() const { return *this; }

    void from_string(value_type v, const std::string& a) {
        switch (v) {
            case TYPE_NULL:     *this = null(); break;
            case TYPE_BOOL:     *this = a == "true" || a == "yes";      break;
            case TYPE_INT:      *this = boost::lexical_cast<long>(a);   break;
            case TYPE_DOUBLE:   *this = boost::lexical_cast<double>(a); break;
            case TYPE_STRING:   *this = a;
            default:            throw_type_error(type());
        }
    }

    bool operator== (const variant& rhs) const {
        if (type() != rhs.type()) return false;
        switch (type()) {
            case TYPE_NULL:     return true;
            case TYPE_BOOL:     return to_bool()  == rhs.to_bool();
            case TYPE_INT:      return to_int()   == rhs.to_int();
            case TYPE_DOUBLE:   return to_float() == rhs.to_float();
            case TYPE_STRING:   return to_str()   == rhs.to_str();
            default:            throw_type_error(type());
                                return false; // just to pease the compiler
        }
    }

    bool operator< (const variant& rhs) const {
        if (type() < rhs.type()) return true;
        if (type() > rhs.type()) return false;
        switch (type()) {
            case TYPE_NULL:     return false;
            case TYPE_BOOL:     return to_bool()  < rhs.to_bool();
            case TYPE_INT:      return to_int()   < rhs.to_int();
            case TYPE_DOUBLE:   return to_float() < rhs.to_float();
            case TYPE_STRING:   return to_str()   < rhs.to_str();
            default:            throw_type_error(type());
                                return false; // just to pease the compiler
        }
    }

    bool operator> (const variant& rhs) const {
        if (type() > rhs.type()) return true;
        if (type() < rhs.type()) return false;
        switch (type()) {
            case TYPE_NULL:     return false;
            case TYPE_BOOL:     return to_bool()  > rhs.to_bool();
            case TYPE_INT:      return to_int()   > rhs.to_int();
            case TYPE_DOUBLE:   return to_float() > rhs.to_float();
            case TYPE_STRING:   return to_str()   > rhs.to_str();
            default:            throw_type_error(type());
                                return false; // just to pease the compiler
        }
    }

private:
    static void throw_type_error(value_type v) {
        std::stringstream s;
        s << "Unknown type " << v;
        throw std::runtime_error(s.str());
    }

    static std::string to_std_string(const std::basic_string<char>& a) {
        return a;
    }

    template <class Ch>
    static std::string to_std_string(const std::basic_string<Ch>& a) {
        return boost::property_tree::info_parser::convert_chtype<char, Ch>(a);
    }

    template <typename U>
    struct type_visitor: public boost::static_visitor<bool> {
        typedef typename normal_type<U>::type Type;
        bool operator() (Type v) const { return true; }

        template <typename T>
        bool operator() (T v)    const { return false; }
    };
};

static inline std::ostream& operator<< (std::ostream& out, const variant& a) {
    return out << a.to_string();
}

} // namespace utxx

#endif // _UTXX_VARIANT_HPP_
<commit_msg>Bug fix variant::to_float()<commit_after>//----------------------------------------------------------------------------
/// \file   variant.hpp
/// \author Serge Aleynikov
//----------------------------------------------------------------------------
/// \brief Variant class that represents a subtype of
/// boost::variant that can hold integer/bool/double/string values.
//----------------------------------------------------------------------------
// Created: 2010-07-10
//----------------------------------------------------------------------------
/*
***** BEGIN LICENSE BLOCK *****

This file is part of the utxx open-source project.

Copyright (C) 2010 Serge Aleynikov <saleyn@gmail.com>

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library 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
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

***** END LICENSE BLOCK *****
*/

#ifndef _UTXX_VARIANT_HPP_
#define _UTXX_VARIANT_HPP_

#include <boost/variant.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/find.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/joint_view.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/static_assert.hpp>
#include <boost/cstdint.hpp>
#include <boost/property_tree/detail/info_parser_utils.hpp>
#include <stdexcept>
#include <string.h>
#include <stdio.h>

namespace utxx {

struct null {};

class variant: public boost::variant<null, bool, long, double, std::string>
{
    typedef boost::variant    <null, bool, long, double, std::string> base;
    typedef boost::mpl::vector<null, bool, long, double, std::string> internal_types;

    struct string_visitor: public boost::static_visitor<std::string> {
        std::string operator () (null v) const { return "<NULL>";             }
        std::string operator () (bool v) const { return v ? "true" : "false"; }
        std::string operator () (long v) const { return std::to_string(v);    }
        std::string operator () (double v) const {
            char buf[128];
            snprintf(buf, sizeof(buf)-1, "%f", v);
            // Remove trailing zeros.
            for (char* p = buf+strlen(buf); p > buf && *(p-1) != '.'; p--)
                if (*p == '0')
                    *p = '\0';
            return buf;
        }
        std::string operator () (const std::string& v) const { return v; }
    };

    template <typename T>
    T              get(T*)       const { return boost::get<T>(*this); }
    const variant& get(variant*) const { return *this; }
    variant&       get(variant*)       { return *this; }
public:
    typedef boost::mpl::vector<
        int,int16_t,long,uint16_t,uint32_t,uint64_t> int_types;

    typedef boost::mpl::joint_view<
        int_types,
        boost::mpl::vector<null,bool,double,std::string>
    > valid_types;

    typedef boost::mpl::joint_view<
        int_types,
        boost::mpl::vector<null,bool,double,std::string,variant>
    > valid_get_types;

    // For integers - cast them all to long type
    template <typename T>
    class normal_type {
        typedef typename boost::mpl::find<int_types, T>::type int_iter;
    public:
        typedef
            typename boost::mpl::if_
                <boost::is_same<boost::mpl::end<int_types>::type, int_iter>,
                 T, long>::type
            type;
    };

    enum value_type {
          TYPE_NULL
        , TYPE_BOOL
        , TYPE_INT
        , TYPE_DOUBLE
        , TYPE_STRING
    };

    variant() : base(null()) {}
    explicit variant(bool       a) : base(a)        {}
    explicit variant(int16_t    a) : base((long)a)  {}
    explicit variant(int        a) : base((long)a)  {}
    explicit variant(long       a) : base(a)        {}
    explicit variant(uint16_t   a) : base((long)a)  {}
    explicit variant(uint32_t   a) : base((long)a)  {}
    explicit variant(uint64_t   a) : base((long)a)  {}
    explicit variant(double     a) : base(a)        {}

    template <class Ch>
    variant(const std::basic_string<Ch>& a) : base(to_std_string<Ch>(a)) {}
    variant(const char*                  a) : base(std::string(a)) {}
    variant(const std::string&           a) : base(a) {}

    variant(const variant& a) : base((const base&)a) {}

#if __cplusplus >= 201103L
    variant(variant&& a)            { swap(a); }
    variant& operator=(variant&& a) { clear(); swap(a); return *this; }
#endif

    variant(value_type v, const std::string& a) { from_string(v, a); }

    void operator= (const variant& a) { *(base*)this = (const base&)a; }
    //void operator= (null        a)  { *(base*)this = null(); }
    void operator= (int16_t     a)  { *(base*)this = (long)a; }
    void operator= (int         a)  { *(base*)this = (long)a; }
    void operator= (int64_t     a)  { *(base*)this = (long)a; }
    void operator= (uint16_t    a)  { *(base*)this = (long)a; }
    void operator= (uint32_t    a)  { *(base*)this = (long)a; }
    void operator= (uint64_t    a)  { *(base*)this = (long)a; }
    void operator= (const char* a)  { *(base*)this = std::string(a); }
    void operator= (const std::string& a) { *(base*)this = a; }
    void operator= (bool        a)  { variant b(a); *this = b; }

    template <typename T>
    void operator= (T a) {
        typedef typename boost::mpl::find<valid_types, T>::type type_iter;
        BOOST_STATIC_ASSERT(
            (!boost::is_same<
                boost::mpl::end<valid_types>::type,
                type_iter >::value)
        );
        *(base*)this = a;
    }

    void operator+= (int16_t     a)  { *(base*)this = is_null() ? a : to_int() + a; }
    void operator+= (int         a)  { *(base*)this = is_null() ? a : to_int() + a; }
    void operator+= (int64_t     a)  { *(base*)this = is_null() ? a : to_int() + a; }
    void operator+= (uint16_t    a)  { *(base*)this = is_null() ? a : to_int() + a; }
    void operator+= (uint32_t    a)  { *(base*)this = is_null() ? a : to_int() + a; }
    void operator+= (uint64_t    a)  { *(base*)this = is_null() ? (long)a : to_int()+(long)a; }
    void operator+= (double      a)  { *(base*)this = is_null() ? a : to_int() + a; }
    void operator+= (const char* a)  { *(base*)this = is_null() ? a : to_str() + a; }
    void operator+= (const std::string& a) { *(base*)this = is_null() ? a : to_str() + a; }

    template <typename T>
    void operator+= (T a) { throw std::runtime_error("Operation not supported!"); }

    value_type  type()     const { return static_cast<value_type>(which()); }
    const char* type_str() const {
        static const char* s_types[] = { "null", "bool", "int", "double", "string" };
        return s_types[type()];
    }

    /// Set value to null.
    void clear() { *(base*)this = null(); }

    /// Returns true if the value is null.
    bool is_null()      const { return type() == TYPE_NULL; }
    bool is_bool()      const { return type() == TYPE_BOOL; }
    bool is_int()       const { return type() == TYPE_INT;  }
    bool is_double()    const { return type() == TYPE_DOUBLE; }
    bool is_string()    const { return type() == TYPE_STRING; }

    template <typename T>
    bool is_type()      const {
        variant::type_visitor<T> v;
        return boost::apply_visitor(v, *this);
    }

    bool                to_bool()   const { return boost::get<bool>(*this); }
    long                to_int()    const { return boost::get<long>(*this); }
    double              to_float()  const { return boost::get<double>(*this); }
    double              to_double() const { return boost::get<double>(*this); }
    const std::string&  to_str()    const { return boost::get<std::string>(*this); }
    const char*         c_str()     const { return boost::get<std::string>(
                                                    *this).c_str(); }

    /// Returns true if the variant doesn't contain a value or it's an empty string
    bool empty(bool a_check_empty_string = true) const {
        return is_null() || (a_check_empty_string && is_string() && to_str().empty());
    }

    /// Convert value to string.
    std::string to_string() const {
        variant::string_visitor v;
        return boost::apply_visitor(v, *this);
    }

    template <typename T>
    T get() const {
        // Make sure given type is a valid variant type.
        // Note to user: an error raised here indicates that
        // there's a compile-time attempt to convert a variant to
        // unsupported type.
        typedef typename boost::mpl::find<valid_get_types, T>::type valid_iter;
        BOOST_STATIC_ASSERT(
            (!boost::is_same<boost::mpl::end<valid_get_types>::type, valid_iter>::value));
        // For integers - cast them to long type when fetching from the variant.
        typename normal_type<T>::type* dummy(NULL);
        return get(dummy);
    }

    const variant& get() const { return *this; }

    void from_string(value_type v, const std::string& a) {
        switch (v) {
            case TYPE_NULL:     *this = null(); break;
            case TYPE_BOOL:     *this = a == "true" || a == "yes";      break;
            case TYPE_INT:      *this = boost::lexical_cast<long>(a);   break;
            case TYPE_DOUBLE:   *this = boost::lexical_cast<double>(a); break;
            case TYPE_STRING:   *this = a;
            default:            throw_type_error(type());
        }
    }

    bool operator== (const variant& rhs) const {
        if (type() != rhs.type()) return false;
        switch (type()) {
            case TYPE_NULL:     return true;
            case TYPE_BOOL:     return to_bool()  == rhs.to_bool();
            case TYPE_INT:      return to_int()   == rhs.to_int();
            case TYPE_DOUBLE:   return to_float() == rhs.to_float();
            case TYPE_STRING:   return to_str()   == rhs.to_str();
            default:            throw_type_error(type());
                                return false; // just to pease the compiler
        }
    }

    bool operator< (const variant& rhs) const {
        if (type() < rhs.type()) return true;
        if (type() > rhs.type()) return false;
        switch (type()) {
            case TYPE_NULL:     return false;
            case TYPE_BOOL:     return to_bool()  < rhs.to_bool();
            case TYPE_INT:      return to_int()   < rhs.to_int();
            case TYPE_DOUBLE:   return to_float() < rhs.to_float();
            case TYPE_STRING:   return to_str()   < rhs.to_str();
            default:            throw_type_error(type());
                                return false; // just to pease the compiler
        }
    }

    bool operator> (const variant& rhs) const {
        if (type() > rhs.type()) return true;
        if (type() < rhs.type()) return false;
        switch (type()) {
            case TYPE_NULL:     return false;
            case TYPE_BOOL:     return to_bool()  > rhs.to_bool();
            case TYPE_INT:      return to_int()   > rhs.to_int();
            case TYPE_DOUBLE:   return to_float() > rhs.to_float();
            case TYPE_STRING:   return to_str()   > rhs.to_str();
            default:            throw_type_error(type());
                                return false; // just to pease the compiler
        }
    }

private:
    static void throw_type_error(value_type v) {
        std::stringstream s;
        s << "Unknown type " << v;
        throw std::runtime_error(s.str());
    }

    static std::string to_std_string(const std::basic_string<char>& a) {
        return a;
    }

    template <class Ch>
    static std::string to_std_string(const std::basic_string<Ch>& a) {
        return boost::property_tree::info_parser::convert_chtype<char, Ch>(a);
    }

    template <typename U>
    struct type_visitor: public boost::static_visitor<bool> {
        typedef typename normal_type<U>::type Type;
        bool operator() (Type v) const { return true; }

        template <typename T>
        bool operator() (T v)    const { return false; }
    };
};

static inline std::ostream& operator<< (std::ostream& out, const variant& a) {
    return out << a.to_string();
}

} // namespace utxx

#endif // _UTXX_VARIANT_HPP_
<|endoftext|>


<commit_before>#include <iostream>
#include <sstream>
#include <fstream>
#include <algorithm>
#include <vector>
#include <iomanip>
#include <cassert>

#include "logger.hpp"
#include "lexer.hpp"
#include "parser.hpp"
#include "environment.hpp"
#include "interpreter.hpp"

// conver a double value to percent
std::string format_probability(double prob)
{
    if (prob < 0.0001 && prob != 0)
    {
        return "< 0.01 %";
    }
    return std::to_string(prob * 100) + " %";
}

// value formatting functions

void print(int value)
{
    std::cout << value << std::endl;
}

void print(double value)
{
    std::cout << value << std::endl;
}

template<typename ValueType, typename ProbabilityType>
void print(
    const dice::random_variable_decomposition<ValueType, ProbabilityType>& var)
{
    const int width_value = 10;
    const int width_prob = 15;
    const int width_cdf = 15;

    std::cout << std::endl
        << "\e[1m" << std::setw(width_value) << "Value"
        << "\e[1m" << std::setw(width_prob) << "PMF"
        << "\e[1m" << std::setw(width_cdf) << "CDF"
        << "\e[0m"
        << std::endl;

    ProbabilityType sum = 0;
    for (auto&& pair : var.probability())
    {
        std::cout
            << std::setw(width_value) << pair.first
            << std::setw(width_prob) << format_probability(pair.second)
            << std::setw(width_cdf) << format_probability(sum)
            << std::endl;
        sum += pair.second;
    }
}

/** Print computed value.
 * @param computed value
 */
void print_value(const dice::base_value* value)
{
    if (value == nullptr)
    {
        return;
    }

    // print value
    auto int_value = dynamic_cast<const dice::type_int*>(value);
    if (int_value != nullptr)
    {
        print(int_value->data());
        return;
    }

    auto double_value = dynamic_cast<const dice::type_double*>(value);
    if (double_value != nullptr)
    {
        print(double_value->data());
        return;
    }

    auto var_value = dynamic_cast<const dice::type_rand_var*>(value);
    if (var_value != nullptr)
    {
        print(var_value->data());
        return;
    }

    throw std::runtime_error("Unknown value.");
}

struct options
{
    // Command line arguments
    std::vector<std::string> args;
    // Input stream
    std::istream* input;
    // Should we print the executed script?
    bool verbose;

    options(int argc, char** argv) :
        args(argv, argv + argc),
        input(nullptr),
        verbose(false)
    {
        parse();
    }
private:
    std::ifstream input_file_;
    std::stringstream input_mem_;

    void parse()
    {
        auto it = args.begin() + 1; // first arg is the file path

        bool load_from_file = false;
        for (; it != args.end(); ++it)
        {
            if (*it == "-f") // input file
            {
                assert(it + 1 != args.end());
                ++it;
                input_file_.open(*it);
                input = &input_file_;
                load_from_file = true;
            }
            else if (*it == "-v")
            {
                verbose = true;
            }
            else
            {
                break;
            }
        }

        // load from arguments - concatenate the rest of the args
        if (!load_from_file && it != args.end())
        {
            std::string expr = *it++;
            for (; it != args.end(); ++it)
                expr += " " + *it;
            input_mem_ = std::stringstream{ expr };
            input = &input_mem_;
        }
    }
};

int main(int argc, char** argv)
{
    options opt{ argc, argv };

    if (opt.input != nullptr)
    {
        // parse and interpret the expression
        dice::logger log;
        dice::lexer lexer{ opt.input, &log };
        dice::environment env;
        dice::interpreter<dice::environment> interpret{ &env };
        auto parser = dice::make_parser(&lexer, &log, &interpret);
        auto result = parser.parse();

        for (auto&& value : result)
        {
            std::string expr;
            std::getline(interpret.code(), expr);
            if (value != nullptr || opt.verbose)
            {
                std::cout << expr;
                if (value != nullptr)
                    std::cout << ": ";
            }
            print_value(value.get());
            if (value != nullptr)
            {
                std::cout << std::endl;
            }
        }
    }
    else
    {
        std::cerr << "Dice expressions interpreter." << std::endl
            << std::endl
            << "Usage:" << std::endl
            << "   ./dice_cli [options] [expression]" << std::endl
            << std::endl
            << "   [options]:" << std::endl
            << "      -f <file> load expression from file" << std::endl
            << "      -v verbose output (show executed script)" << std::endl
            << std::endl
            << "   [expression]:" << std::endl
            << "      A dice expression. Can be in multiple arguments." << std::endl
            << "      The program will join them wih a space." << std::endl;
        return 1;
    }
    return 0;
}<commit_msg>Add newline after definition in verbose mode<commit_after>#include <iostream>
#include <sstream>
#include <fstream>
#include <algorithm>
#include <vector>
#include <iomanip>
#include <cassert>

#include "logger.hpp"
#include "lexer.hpp"
#include "parser.hpp"
#include "environment.hpp"
#include "interpreter.hpp"

// conver a double value to percent
std::string format_probability(double prob)
{
    if (prob < 0.0001 && prob != 0)
    {
        return "< 0.01 %";
    }
    return std::to_string(prob * 100) + " %";
}

// value formatting functions

void print(int value)
{
    std::cout << value << std::endl;
}

void print(double value)
{
    std::cout << value << std::endl;
}

template<typename ValueType, typename ProbabilityType>
void print(
    const dice::random_variable_decomposition<ValueType, ProbabilityType>& var)
{
    const int width_value = 10;
    const int width_prob = 15;
    const int width_cdf = 15;

    std::cout << std::endl
        << "\e[1m" << std::setw(width_value) << "Value"
        << "\e[1m" << std::setw(width_prob) << "PMF"
        << "\e[1m" << std::setw(width_cdf) << "CDF"
        << "\e[0m"
        << std::endl;

    ProbabilityType sum = 0;
    for (auto&& pair : var.probability())
    {
        std::cout
            << std::setw(width_value) << pair.first
            << std::setw(width_prob) << format_probability(pair.second)
            << std::setw(width_cdf) << format_probability(sum)
            << std::endl;
        sum += pair.second;
    }
}

/** Print computed value.
 * @param computed value
 */
void print_value(const dice::base_value* value)
{
    if (value == nullptr)
    {
        return;
    }

    // print value
    auto int_value = dynamic_cast<const dice::type_int*>(value);
    if (int_value != nullptr)
    {
        print(int_value->data());
        return;
    }

    auto double_value = dynamic_cast<const dice::type_double*>(value);
    if (double_value != nullptr)
    {
        print(double_value->data());
        return;
    }

    auto var_value = dynamic_cast<const dice::type_rand_var*>(value);
    if (var_value != nullptr)
    {
        print(var_value->data());
        return;
    }

    throw std::runtime_error("Unknown value.");
}

struct options
{
    // Command line arguments
    std::vector<std::string> args;
    // Input stream
    std::istream* input;
    // Should we print the executed script?
    bool verbose;

    options(int argc, char** argv) :
        args(argv, argv + argc),
        input(nullptr),
        verbose(false)
    {
        parse();
    }
private:
    std::ifstream input_file_;
    std::stringstream input_mem_;

    void parse()
    {
        auto it = args.begin() + 1; // first arg is the file path

        bool load_from_file = false;
        for (; it != args.end(); ++it)
        {
            if (*it == "-f") // input file
            {
                assert(it + 1 != args.end());
                ++it;
                input_file_.open(*it);
                input = &input_file_;
                load_from_file = true;
            }
            else if (*it == "-v")
            {
                verbose = true;
            }
            else
            {
                break;
            }
        }

        // load from arguments - concatenate the rest of the args
        if (!load_from_file && it != args.end())
        {
            std::string expr = *it++;
            for (; it != args.end(); ++it)
                expr += " " + *it;
            input_mem_ = std::stringstream{ expr };
            input = &input_mem_;
        }
    }
};

int main(int argc, char** argv)
{
    options opt{ argc, argv };

    if (opt.input != nullptr)
    {
        // parse and interpret the expression
        dice::logger log;
        dice::lexer lexer{ opt.input, &log };
        dice::environment env;
        dice::interpreter<dice::environment> interpret{ &env };
        auto parser = dice::make_parser(&lexer, &log, &interpret);
        auto result = parser.parse();

        for (auto&& value : result)
        {
            std::string expr;
            std::getline(interpret.code(), expr);
            if (value != nullptr || opt.verbose)
            {
                std::cout << expr;
                if (value != nullptr)
                    std::cout << ": ";
            }
            print_value(value.get());
            if (value != nullptr || opt.verbose)
            {
                std::cout << std::endl;
            }
        }
    }
    else
    {
        std::cerr << "Dice expressions interpreter." << std::endl
            << std::endl
            << "Usage:" << std::endl
            << "   ./dice_cli [options] [expression]" << std::endl
            << std::endl
            << "   [options]:" << std::endl
            << "      -f <file> load expression from file" << std::endl
            << "      -v verbose output (show executed script)" << std::endl
            << std::endl
            << "   [expression]:" << std::endl
            << "      A dice expression. Can be in multiple arguments." << std::endl
            << "      The program will join them wih a space." << std::endl;
        return 1;
    }
    return 0;
}<|endoftext|>


<commit_before>/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * Written (W) 1999-2009 Soeren Sonnenburg
 * Written (W) 1999-2008 Gunnar Raetsch
 * Copyright (C) 1999-2009 Fraunhofer Institute FIRST and Max-Planck-Society
 */

#include "features/Features.h"
#include "preproc/PreProc.h"
#include "lib/io.h"
#include "base/Parameter.h"

#include <string.h>

using namespace shogun;

CFeatures::CFeatures(int32_t size)
: CSGObject()
{
	init();
	cache_size = size;
}

CFeatures::CFeatures(const CFeatures& orig)
: CSGObject(orig)
{
	init();

	preproc = orig.preproc;
	num_preproc = orig.num_preproc;

	preprocessed=new bool[orig.num_preproc];
	memcpy(preprocessed, orig.preprocessed, sizeof(bool)*orig.num_preproc);
}

CFeatures::CFeatures(CFile* loader)
: CSGObject()
{
	init();

	load(loader);
	SG_INFO("Feature object loaded (%p)\n",this) ;
}

CFeatures::~CFeatures()
{
	if (m_subset_idx)
		delete[] m_subset_idx;

	clean_preprocs();
}

void
CFeatures::init(void)
{
	m_parameters->add(&properties, "properties",
					  "Feature properties.");
	m_parameters->add(&cache_size, "cache_size",
					  "Size of cache in MB.");

	m_parameters->add_vector((CSGObject***) &preproc,
							 &num_preproc, "preproc",
							 "List of preprocessors.");
	m_parameters->add_vector(&preprocessed,
							 &num_preproc, "preprocessed",
							 "Feature[i] is already preprocessed.");

	m_parameters->add_vector(&m_subset_idx, &m_subset_len, "subset_idx", "Subset indices.");

	properties = FP_NONE;
	cache_size = 0;
	preproc = NULL;
	num_preproc = 0;
	preprocessed = NULL;
	m_subset_idx = NULL;
	m_subset_len = 0;
}

/// set preprocessor
int32_t CFeatures::add_preproc(CPreProc* p)
{
	SG_INFO( "%d preprocs currently, new preproc list is\n", num_preproc);
	ASSERT(p);

	bool* preprocd=new bool[num_preproc+1];
	CPreProc** pps=new CPreProc*[num_preproc+1];
	for (int32_t i=0; i<num_preproc; i++)
	{
		pps[i]=preproc[i];
		preprocd[i]=preprocessed[i];
	}
	delete[] preproc;
	delete[] preprocessed;
	preproc=pps;
	preprocessed=preprocd;
	preproc[num_preproc]=p;
	preprocessed[num_preproc]=false;

	num_preproc++;

	for (int32_t i=0; i<num_preproc; i++)
		SG_INFO( "preproc[%d]=%s %ld\n",i, preproc[i]->get_name(), preproc[i]) ;

	SG_REF(p);

	return num_preproc;
}

/// get current preprocessor
CPreProc* CFeatures::get_preproc(int32_t num)
{
	if (num<num_preproc)
	{
		SG_REF(preproc[num]);
		return preproc[num];
	}
	else
		return NULL;
}

/// get whether specified preprocessor (or all if num=1) was/were already applied
int32_t CFeatures::get_num_preprocessed()
{
	int32_t num=0;

	for (int32_t i=0; i<num_preproc; i++)
	{
		if (preprocessed[i])
			num++;
	}

	return num;
}

/// clears all preprocs
void CFeatures::clean_preprocs()
{
	while (del_preproc(0));
}

/// del current preprocessor
CPreProc* CFeatures::del_preproc(int32_t num)
{
	CPreProc** pps=NULL;
	bool* preprocd=NULL;
	CPreProc* removed_preproc=NULL;

	if (num_preproc>0 && num<num_preproc)
	{
		removed_preproc=preproc[num];

		if (num_preproc>1)
		{
			pps= new CPreProc*[num_preproc-1];
			preprocd= new bool[num_preproc-1];

			if (pps && preprocd)
			{
				int32_t j=0;
				for (int32_t i=0; i<num_preproc; i++)
				{
					if (i!=num)
					{
						pps[j]=preproc[i];
						preprocd[j]=preprocessed[i];
						j++;
					}
				}
			}
		}

		delete[] preproc;
		preproc=pps;
		delete[] preprocessed;
		preprocessed=preprocd;

		num_preproc--;

		for (int32_t i=0; i<num_preproc; i++)
			SG_INFO( "preproc[%d]=%s\n",i, preproc[i]->get_name()) ;
	}

	SG_UNREF(removed_preproc);
	return removed_preproc;
}

void CFeatures::list_feature_obj()
{
	SG_INFO( "%p - ", this);
	switch (get_feature_class())
	{
		case C_UNKNOWN:
			SG_INFO( "C_UNKNOWN ");
			break;
		case C_SIMPLE:
			SG_INFO( "C_SIMPLE ");
			break;
		case C_SPARSE:
			SG_INFO( "C_SPARSE ");
			break;
		case C_STRING:
			SG_INFO( "C_STRING ");
			break;
		case C_COMBINED:
			SG_INFO( "C_COMBINED ");
			break;
		case C_COMBINED_DOT:
			SG_INFO( "C_COMBINED_DOT ");
			break;
		case C_WD:
			SG_INFO( "C_WD ");
			break;
		case C_SPEC:
			SG_INFO( "C_SPEC ");
			break;
		case C_WEIGHTEDSPEC:
			SG_INFO( "C_WEIGHTEDSPEC ");
			break;
		case C_ANY:
			SG_INFO( "C_ANY ");
			break;
		default:
         SG_ERROR( "ERROR UNKNOWN FEATURE CLASS");
	}

	switch (get_feature_type())
	{
		case F_UNKNOWN:
			SG_INFO( "F_UNKNOWN \n");
			break;
		case F_CHAR:
			SG_INFO( "F_CHAR \n");
			break;
		case F_BYTE:
			SG_INFO( "F_BYTE \n");
			break;
		case F_SHORT:
			SG_INFO( "F_SHORT \n");
			break;
		case F_WORD:
			SG_INFO( "F_WORD \n");
			break;
		case F_INT:
			SG_INFO( "F_INT \n");
			break;
		case F_UINT:
			SG_INFO( "F_UINT \n");
			break;
		case F_LONG:
			SG_INFO( "F_LONG \n");
			break;
		case F_ULONG:
			SG_INFO( "F_ULONG \n");
			break;
		case F_SHORTREAL:
			SG_INFO( "F_SHORTEAL \n");
			break;
		case F_DREAL:
			SG_INFO( "F_DREAL \n");
			break;
		case F_LONGREAL:
			SG_INFO( "F_LONGREAL \n");
			break;
		case F_ANY:
			SG_INFO( "F_ANY \n");
			break;
		default:
         SG_ERROR( "ERROR UNKNOWN FEATURE TYPE\n");
	}
}

bool CFeatures::check_feature_compatibility(CFeatures* f)
{
	bool result=false;

	if (f)
		result= ( (this->get_feature_class() == f->get_feature_class()) &&
				(this->get_feature_type() == f->get_feature_type()));
	return result;
}

void CFeatures::set_feature_subset(int32_t subset_len, int32_t* subset_idx)
{
	if (m_subset_idx)
		delete[] m_subset_idx;

	m_subset_idx=subset_idx;
	m_subset_len=subset_len;
}

void CFeatures::set_feature_subset(int32_t* subset_idx, int32_t subset_len)
{
	ASSERT(subset_idx);

	if (m_subset_idx)
	{
		delete[] m_subset_idx;
		m_subset_idx = NULL;
	}

	int64_t length=sizeof(int32_t)*subset_len;

	m_subset_idx=(int32_t*)malloc(length);
	if (!m_subset_idx)
		SG_ERROR("Allocating %ld bytes failes\n", length);

	memcpy(m_subset_idx, subset_idx, length);
}

void CFeatures::remove_feature_subset()
{
	if (!m_subset_idx)
	{
		delete[] m_subset_idx;
		m_subset_idx=NULL;
		m_subset_len=0;
	}
}

void CFeatures::get_feature_subset(int32_t** subset_idx, int32_t* subset_len)
{
	ASSERT(m_subset_idx);
	int64_t length = sizeof(int32_t)*m_subset_len;

	*subset_len=m_subset_len;
	*subset_idx=(int32_t*)malloc(length);
	if (!*subset_idx)
		SG_ERROR("Allocating %ld bytes failes\n", length);
	memcpy(*subset_idx, m_subset_idx, length);
}
<commit_msg>remove unnecessary NULL check<commit_after>/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * Written (W) 1999-2009 Soeren Sonnenburg
 * Written (W) 1999-2008 Gunnar Raetsch
 * Copyright (C) 1999-2009 Fraunhofer Institute FIRST and Max-Planck-Society
 */

#include "features/Features.h"
#include "preproc/PreProc.h"
#include "lib/io.h"
#include "base/Parameter.h"

#include <string.h>

using namespace shogun;

CFeatures::CFeatures(int32_t size)
: CSGObject()
{
	init();
	cache_size = size;
}

CFeatures::CFeatures(const CFeatures& orig)
: CSGObject(orig)
{
	init();

	preproc = orig.preproc;
	num_preproc = orig.num_preproc;

	preprocessed=new bool[orig.num_preproc];
	memcpy(preprocessed, orig.preprocessed, sizeof(bool)*orig.num_preproc);
}

CFeatures::CFeatures(CFile* loader)
: CSGObject()
{
	init();

	load(loader);
	SG_INFO("Feature object loaded (%p)\n",this) ;
}

CFeatures::~CFeatures()
{
	if (m_subset_idx)
		delete[] m_subset_idx;

	clean_preprocs();
}

void
CFeatures::init(void)
{
	m_parameters->add(&properties, "properties",
					  "Feature properties.");
	m_parameters->add(&cache_size, "cache_size",
					  "Size of cache in MB.");

	m_parameters->add_vector((CSGObject***) &preproc,
							 &num_preproc, "preproc",
							 "List of preprocessors.");
	m_parameters->add_vector(&preprocessed,
							 &num_preproc, "preprocessed",
							 "Feature[i] is already preprocessed.");

	m_parameters->add_vector(&m_subset_idx, &m_subset_len, "subset_idx", "Subset indices.");

	properties = FP_NONE;
	cache_size = 0;
	preproc = NULL;
	num_preproc = 0;
	preprocessed = NULL;
	m_subset_idx = NULL;
	m_subset_len = 0;
}

/// set preprocessor
int32_t CFeatures::add_preproc(CPreProc* p)
{
	SG_INFO( "%d preprocs currently, new preproc list is\n", num_preproc);
	ASSERT(p);

	bool* preprocd=new bool[num_preproc+1];
	CPreProc** pps=new CPreProc*[num_preproc+1];
	for (int32_t i=0; i<num_preproc; i++)
	{
		pps[i]=preproc[i];
		preprocd[i]=preprocessed[i];
	}
	delete[] preproc;
	delete[] preprocessed;
	preproc=pps;
	preprocessed=preprocd;
	preproc[num_preproc]=p;
	preprocessed[num_preproc]=false;

	num_preproc++;

	for (int32_t i=0; i<num_preproc; i++)
		SG_INFO( "preproc[%d]=%s %ld\n",i, preproc[i]->get_name(), preproc[i]) ;

	SG_REF(p);

	return num_preproc;
}

/// get current preprocessor
CPreProc* CFeatures::get_preproc(int32_t num)
{
	if (num<num_preproc)
	{
		SG_REF(preproc[num]);
		return preproc[num];
	}
	else
		return NULL;
}

/// get whether specified preprocessor (or all if num=1) was/were already applied
int32_t CFeatures::get_num_preprocessed()
{
	int32_t num=0;

	for (int32_t i=0; i<num_preproc; i++)
	{
		if (preprocessed[i])
			num++;
	}

	return num;
}

/// clears all preprocs
void CFeatures::clean_preprocs()
{
	while (del_preproc(0));
}

/// del current preprocessor
CPreProc* CFeatures::del_preproc(int32_t num)
{
	CPreProc** pps=NULL;
	bool* preprocd=NULL;
	CPreProc* removed_preproc=NULL;

	if (num_preproc>0 && num<num_preproc)
	{
		removed_preproc=preproc[num];

		if (num_preproc>1)
		{
			pps= new CPreProc*[num_preproc-1];
			preprocd= new bool[num_preproc-1];

			if (pps && preprocd)
			{
				int32_t j=0;
				for (int32_t i=0; i<num_preproc; i++)
				{
					if (i!=num)
					{
						pps[j]=preproc[i];
						preprocd[j]=preprocessed[i];
						j++;
					}
				}
			}
		}

		delete[] preproc;
		preproc=pps;
		delete[] preprocessed;
		preprocessed=preprocd;

		num_preproc--;

		for (int32_t i=0; i<num_preproc; i++)
			SG_INFO( "preproc[%d]=%s\n",i, preproc[i]->get_name()) ;
	}

	SG_UNREF(removed_preproc);
	return removed_preproc;
}

void CFeatures::list_feature_obj()
{
	SG_INFO( "%p - ", this);
	switch (get_feature_class())
	{
		case C_UNKNOWN:
			SG_INFO( "C_UNKNOWN ");
			break;
		case C_SIMPLE:
			SG_INFO( "C_SIMPLE ");
			break;
		case C_SPARSE:
			SG_INFO( "C_SPARSE ");
			break;
		case C_STRING:
			SG_INFO( "C_STRING ");
			break;
		case C_COMBINED:
			SG_INFO( "C_COMBINED ");
			break;
		case C_COMBINED_DOT:
			SG_INFO( "C_COMBINED_DOT ");
			break;
		case C_WD:
			SG_INFO( "C_WD ");
			break;
		case C_SPEC:
			SG_INFO( "C_SPEC ");
			break;
		case C_WEIGHTEDSPEC:
			SG_INFO( "C_WEIGHTEDSPEC ");
			break;
		case C_ANY:
			SG_INFO( "C_ANY ");
			break;
		default:
         SG_ERROR( "ERROR UNKNOWN FEATURE CLASS");
	}

	switch (get_feature_type())
	{
		case F_UNKNOWN:
			SG_INFO( "F_UNKNOWN \n");
			break;
		case F_CHAR:
			SG_INFO( "F_CHAR \n");
			break;
		case F_BYTE:
			SG_INFO( "F_BYTE \n");
			break;
		case F_SHORT:
			SG_INFO( "F_SHORT \n");
			break;
		case F_WORD:
			SG_INFO( "F_WORD \n");
			break;
		case F_INT:
			SG_INFO( "F_INT \n");
			break;
		case F_UINT:
			SG_INFO( "F_UINT \n");
			break;
		case F_LONG:
			SG_INFO( "F_LONG \n");
			break;
		case F_ULONG:
			SG_INFO( "F_ULONG \n");
			break;
		case F_SHORTREAL:
			SG_INFO( "F_SHORTEAL \n");
			break;
		case F_DREAL:
			SG_INFO( "F_DREAL \n");
			break;
		case F_LONGREAL:
			SG_INFO( "F_LONGREAL \n");
			break;
		case F_ANY:
			SG_INFO( "F_ANY \n");
			break;
		default:
         SG_ERROR( "ERROR UNKNOWN FEATURE TYPE\n");
	}
}

bool CFeatures::check_feature_compatibility(CFeatures* f)
{
	bool result=false;

	if (f)
		result= ( (this->get_feature_class() == f->get_feature_class()) &&
				(this->get_feature_type() == f->get_feature_type()));
	return result;
}

void CFeatures::set_feature_subset(int32_t subset_len, int32_t* subset_idx)
{
	if (m_subset_idx)
		delete[] m_subset_idx;

	m_subset_idx=subset_idx;
	m_subset_len=subset_len;
}

void CFeatures::set_feature_subset(int32_t* subset_idx, int32_t subset_len)
{
	ASSERT(subset_idx);

	delete[] m_subset_idx;
	m_subset_idx = NULL;

	int64_t length=sizeof(int32_t)*subset_len;

	m_subset_idx=(int32_t*)malloc(length);
	if (!m_subset_idx)
		SG_ERROR("Allocating %ld bytes failes\n", length);

	memcpy(m_subset_idx, subset_idx, length);
}

void CFeatures::remove_feature_subset()
{
	if (!m_subset_idx)
	{
		delete[] m_subset_idx;
		m_subset_idx=NULL;
		m_subset_len=0;
	}
}

void CFeatures::get_feature_subset(int32_t** subset_idx, int32_t* subset_len)
{
	ASSERT(m_subset_idx);
	int64_t length = sizeof(int32_t)*m_subset_len;

	*subset_len=m_subset_len;
	*subset_idx=(int32_t*)malloc(length);
	if (!*subset_idx)
		SG_ERROR("Allocating %ld bytes failes\n", length);
	memcpy(*subset_idx, m_subset_idx, length);
}
<|endoftext|>


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

#define L10N                                           // Localization complete.

#include <iostream>
#include <stdlib.h>

#ifdef CYGWIN
#include <time.h>
#else
#include <sys/time.h>
#endif

#include <i18n.h>
#include <Context.h>
#include <cmake.h>

Context context;

#ifdef HAVE_SRANDOM
#define srand(x) srandom(x)
#endif

int main (int argc, const char** argv)
{
  // Set up randomness.
#ifdef CYGWIN
  srand (time (NULL));
#else
  struct timeval tv;
  gettimeofday (&tv, NULL);
  srand (tv.tv_usec);
#endif

  int status = 0;

  try
  {
    status = context.initialize (argc, argv);
    if (status == 0)
      status = context.run ();
  }

  catch (std::string& error)
  {
    std::cout << error << "\n";
    status = -1;
  }

  catch (...)
  {
    std::cerr << STRING_UNKNOWN_ERROR << "\n";
    status = -2;
  }

  return status;
}

////////////////////////////////////////////////////////////////////////////////
<commit_msg>Bug #902 - 'task version' requires a .taskrc<commit_after>////////////////////////////////////////////////////////////////////////////////
// taskwarrior - a command line task list manager.
//
// Copyright 2006-2012, Paul Beckingham, Federico Hernandez.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// http://www.opensource.org/licenses/mit-license.php
//
////////////////////////////////////////////////////////////////////////////////

#define L10N                                           // Localization complete.

#include <iostream>
#include <stdlib.h>

#ifdef CYGWIN
#include <time.h>
#else
#include <sys/time.h>
#endif

#include <i18n.h>
#include <Context.h>
#include <cmake.h>

Context context;

#ifdef HAVE_SRANDOM
#define srand(x) srandom(x)
#endif

////////////////////////////////////////////////////////////////////////////////
int main (int argc, const char** argv)
{
  // Set up randomness.
#ifdef CYGWIN
  srand (time (NULL));
#else
  struct timeval tv;
  gettimeofday (&tv, NULL);
  srand (tv.tv_usec);
#endif

  int status = 0;

  if (argc == 2 && !strcmp (argv[1], "--version"))
  {
    std::cout << VERSION << "\n";
  }
  else
  {
    try
    {
      status = context.initialize (argc, argv);
      if (status == 0)
        status = context.run ();
    }

    catch (std::string& error)
    {
      std::cout << error << "\n";
      status = -1;
    }

    catch (...)
    {
      std::cerr << STRING_UNKNOWN_ERROR << "\n";
      status = -2;
    }
  }

  return status;
}

////////////////////////////////////////////////////////////////////////////////
<|endoftext|>


<commit_before>//----------------------------------------------------------------------------
// main.cpp
//
// main for pathed
//
// Copyright (C) 2011 Neil Butterworth
//----------------------------------------------------------------------------

#include <iostream>
#include <set>
#include "cmdline.h"
#include "error.h"
#include "registry.h"
#include "util.h"

using namespace std;

//----------------------------------------------------------------------------
// Flags controling behaviour in various ways.
//----------------------------------------------------------------------------

const char * const ADD_FLAG = "-a";			// add to path
const char * const REM_FLAG = "-r";			// remove from path
const char * const SYS_FLAG = "-s";			// use system instead of user path
const char * const EXIST_FLAG = "-f";		// check path exists on disk
const char * const LIST_FLAG = "-l";		// list current path
const char * const QUERY_FLAG = "-q";		// list current path
const char * const VERIFY_FLAG = "-v";		// verify path
const char * const EXPAND_FLAG = "-x";		// expand path
const char * const PRUNE_FLAG = "-p";		// prune path

static bool Remove = false,
			Add = false,
			UseSys = false,
			List = false,
			CheckExist = true,
			QueryPath = false,
			Verify = false,
			Expand = false,
			Prune = false;

//----------------------------------------------------------------------------
// Set flags from the command line, shifting them off as they are set.
//----------------------------------------------------------------------------

void SetFlags( CmdLine & cl ) {
	while( cl.Argc() > 1 ) {
		string s = cl.Argv(1);
		if ( s.size() && s[0] == '-' ) {
			if ( s == REM_FLAG ) {
				Remove = true;
			}
			else if ( s == PRUNE_FLAG ){
				Prune = true;
			}
			else if ( s == ADD_FLAG ) {
				Add = true;
			}
			else if ( s == SYS_FLAG ) {
				UseSys = true;
			}
			else if ( s == EXPAND_FLAG ) {
				Expand = true;
			}
			else if ( s == EXIST_FLAG ) {
				CheckExist = false;
			}
			else if ( s == LIST_FLAG ) {
				List = true;
			}
			else if ( s == QUERY_FLAG ) {
				QueryPath = true;
			}
			else if ( s == VERIFY_FLAG ) {
				Verify = true;
			}
			else {
				throw Error( "Invalid flag: " + s );
			}
			cl.Shift(1);
		}
		else {
			break;
		}
	}
}

//----------------------------------------------------------------------------
// List PATH to stdout, one directory per line
//----------------------------------------------------------------------------

void ListPath() {
	RegPath path( UseSys ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER );
	for ( unsigned int i = 0; i < path.Count(); i++ ) {
		cout << ( Expand ? ExpandPath( path.At(i) ) : path.At(i) ) << "\n";
	}
}

//----------------------------------------------------------------------------
// Add an entry to the path
//----------------------------------------------------------------------------

void AddPath( CmdLine & cl ) {
	if ( CheckExist ) {
		DWORD attr = GetFileAttributes( cl.Argv(1).c_str() );
		if ( attr == INVALID_FILE_ATTRIBUTES || ! (attr & FILE_ATTRIBUTE_DIRECTORY ) ) {
			throw Error( "No such directory: " + cl.Argv(1));
		}
	}

	RegPath path( UseSys ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER );
	if ( path.Find( cl.Argv(1), RegPath::NoExpand ) ) {
		throw Error( cl.Argv(1) + " is already on the path" );
	}
	path.Add( cl.Argv(1) );
}

//----------------------------------------------------------------------------
// Remove entry from the path
//----------------------------------------------------------------------------

void RemovePath( CmdLine & cl ) {
	RegPath path( UseSys ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER );
	if ( ! path.Find( cl.Argv(1) , RegPath::NoExpand ) ) {
		throw Error( cl.Argv(1) + " is not on the path" );
	}
	path.Remove( cl.Argv(1) );
}

//----------------------------------------------------------------------------
// Prune duplicates and non-existent dirs from path
//----------------------------------------------------------------------------

void PrunePath( CmdLine &  ) {
	RegPath path( UseSys ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER );

	typedef std::set <string> DirSet;
	DirSet uniq;
	std::vector <string> ordered;

	for ( unsigned int i = 0; i < path.Count(); i++ ) {
		string dir = path.At( i );
		std::pair<DirSet::iterator, bool> ok = uniq.insert( dir );
		if ( ok.second ) {
			ordered.push_back( dir );
		}
		else {
			cout << "Pruned: " << dir << endl;
		}
	}

	string entry;

	for ( unsigned int i = 0; i < ordered.size(); i++ ) {
		string dir = ExpandPath( ordered[i] );
		DWORD attr = GetFileAttributes( dir.c_str() );
		if ( attr == INVALID_FILE_ATTRIBUTES ||
						! (attr & FILE_ATTRIBUTE_DIRECTORY ) ) {
			cout << "Pruned: " << ordered[i] << endl;
		}
		else {
			if ( entry != "" ) {
				entry += ";";
			}
			entry += ordered[i];
		}

	}
	path.ReplaceAll( entry );
	std::cout << entry << std::endl;
}

//----------------------------------------------------------------------------
// See if directory is on the path, if so return success code (not boolean!)
//----------------------------------------------------------------------------

int FindPath( CmdLine & cl ) {
	RegPath path( UseSys ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER );
	return  path.Find( cl.Argv(1), Expand ? RegPath::Expand : RegPath::NoExpand ) ? 0 : 1;
}

//----------------------------------------------------------------------------
// Verify directories on path exist.
//----------------------------------------------------------------------------

int VerifyPath() {
	RegPath path( UseSys ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER );
	int bad = 0;
	for ( unsigned int i = 0; i < path.Count(); i++ ) {
		string epath = ExpandPath( path.At(i) );
		DWORD attr = GetFileAttributes( epath.c_str() );
		if ( attr == INVALID_FILE_ATTRIBUTES ) {
			cout << "No such directory: " << epath << "\n";
			bad++;
		}
		else if ( ! (attr & FILE_ATTRIBUTE_DIRECTORY ) ) {
			cout << "Not a directory: " << epath << "\n";
			bad++;
		}
	}
	return bad == 0 ? 0 : 1;
}

//----------------------------------------------------------------------------
// Display help
//----------------------------------------------------------------------------

void Help() {

	cout <<

	"pathed is a command-line tool for changing the Windows path in the registry\n"
	"Version 0.4\n"
	"Copyright (C) 2011 Neil Butterworth\n\n"
	"usage: pathed [-a | -r | -l  | -q | -v] [-s] [-f]  [-x] [dir]\n\n"
	"pathed -a dir    adds dir to the path in  the registry\n"
	"pathed -r dir    removes  dir from the path in the registry\n"
	"pathed -l        lists the entries on the current path\n"
	"pathed -q dir    queries registry, returns 0 if dir is on path, 1 otherwise\n"
	"pathed -v        verifies that all directories on the path exist\n"
	"pathed -p        prunes the path by removing duplicates and non-existent directories\n\n"
	"By default, pathed works on the path in HKEY_CURRENT_USER. You can make it use\n"
	"the system path in HKEY_LOCAL_MACHINE by using the -s flag.\n\n"
	"Normally, pathed will check a directory exists on disk before adding it to the\n"
	"path. To prevent this, use the -f flag.\n\n"
	"Paths containing environment variables such as %systemroot% will not normally have\n"
	"the variables expanded to their values. To expand them, use the -x flag\n\n"
	"AS WITH ALL COMMANDS THAT CHANGE THE REGISTRY, PATHED CAN CAUSE DAMAGE IF YOU\n"
	"DO NOT KNOW WHAT YOU ARE DOING. IF IN DOUBT, DO NOT USE IT!\n"

	<< endl;
}

//----------------------------------------------------------------------------
// Main for pathed
//----------------------------------------------------------------------------

int main( int argc, char *argv[] )
{
	try {
		CmdLine cl( argc, argv );

		SetFlags( cl );

		if ( cl.Argc() == 1 && ! ( List || Verify || Prune ) ) {
			Help();
			return 0;
		}
		else if ( ! (List || Add || QueryPath || Remove || Verify || Prune )  ) {
			throw Error( "Need one of -a, -r, -l, -q, -p or -v" );
		}

		if ( List ) {
			ListPath();
		}
		else if ( Verify ) {
			return VerifyPath();
		}
		else if ( QueryPath ) {
			return FindPath( cl );
		}
		else if ( Remove ) {
			RemovePath( cl );
		}
		else if ( Prune ) {
			PrunePath( cl );
		}
		else {
			AddPath( cl );
		}

		return 0;
	}
	catch( const Error & e ) {
		cerr << e.what() << endl;
		return 1;
	}
	catch( ... ) {
		cerr << "Unexpected exception" << endl;
		return 1;
	}
}
<commit_msg>comments etc.<commit_after>//----------------------------------------------------------------------------
// main.cpp
//
// main for pathed
//
// Copyright (C) 2011 Neil Butterworth
//----------------------------------------------------------------------------

#include <iostream>
#include <set>
#include "cmdline.h"
#include "error.h"
#include "registry.h"
#include "util.h"

using namespace std;

//----------------------------------------------------------------------------
// Flags controling behaviour in various ways.
//----------------------------------------------------------------------------

const char * const ADD_FLAG = "-a";			// add to path
const char * const REM_FLAG = "-r";			// remove from path
const char * const SYS_FLAG = "-s";			// use system instead of user path
const char * const EXIST_FLAG = "-f";		// check path exists on disk
const char * const LIST_FLAG = "-l";		// list current path
const char * const QUERY_FLAG = "-q";		// list current path
const char * const VERIFY_FLAG = "-v";		// verify path
const char * const EXPAND_FLAG = "-x";		// expand path
const char * const PRUNE_FLAG = "-p";		// prune path

static bool Remove = false,
			Add = false,
			UseSys = false,
			List = false,
			CheckExist = true,
			QueryPath = false,
			Verify = false,
			Expand = false,
			Prune = false;

//----------------------------------------------------------------------------
// Set flags from the command line, shifting them off as they are set.
//----------------------------------------------------------------------------

void SetFlags( CmdLine & cl ) {
	while( cl.Argc() > 1 ) {
		string s = cl.Argv(1);
		if ( s.size() && s[0] == '-' ) {
			if ( s == REM_FLAG ) {
				Remove = true;
			}
			else if ( s == PRUNE_FLAG ){
				Prune = true;
			}
			else if ( s == ADD_FLAG ) {
				Add = true;
			}
			else if ( s == SYS_FLAG ) {
				UseSys = true;
			}
			else if ( s == EXPAND_FLAG ) {
				Expand = true;
			}
			else if ( s == EXIST_FLAG ) {
				CheckExist = false;
			}
			else if ( s == LIST_FLAG ) {
				List = true;
			}
			else if ( s == QUERY_FLAG ) {
				QueryPath = true;
			}
			else if ( s == VERIFY_FLAG ) {
				Verify = true;
			}
			else {
				throw Error( "Invalid flag: " + s );
			}
			cl.Shift(1);
		}
		else {
			break;
		}
	}
}

//----------------------------------------------------------------------------
// List PATH to stdout, one directory per line
//----------------------------------------------------------------------------

void ListPath() {
	RegPath path( UseSys ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER );
	for ( unsigned int i = 0; i < path.Count(); i++ ) {
		cout << ( Expand ? ExpandPath( path.At(i) ) : path.At(i) ) << "\n";
	}
}

//----------------------------------------------------------------------------
// Add an entry to the path
//----------------------------------------------------------------------------

void AddPath( CmdLine & cl ) {
	if ( CheckExist ) {
		DWORD attr = GetFileAttributes( cl.Argv(1).c_str() );
		if ( attr == INVALID_FILE_ATTRIBUTES || ! (attr & FILE_ATTRIBUTE_DIRECTORY ) ) {
			throw Error( "No such directory: " + cl.Argv(1));
		}
	}

	RegPath path( UseSys ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER );
	if ( path.Find( cl.Argv(1), RegPath::NoExpand ) ) {
		throw Error( cl.Argv(1) + " is already on the path" );
	}
	path.Add( cl.Argv(1) );
}

//----------------------------------------------------------------------------
// Remove entry from the path
//----------------------------------------------------------------------------

void RemovePath( CmdLine & cl ) {
	RegPath path( UseSys ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER );
	if ( ! path.Find( cl.Argv(1) , RegPath::NoExpand ) ) {
		throw Error( cl.Argv(1) + " is not on the path" );
	}
	path.Remove( cl.Argv(1) );
}

//----------------------------------------------------------------------------
// Prune duplicates and non-existent dirs from path. Use a set to detect
// dupes, but actually work with vector to meaintain path order.
//----------------------------------------------------------------------------

void PrunePath( CmdLine &  ) {
	RegPath path( UseSys ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER );

	typedef std::set <string> DirSet;
	DirSet uniq;
	std::vector <string> ordered;

	for ( unsigned int i = 0; i < path.Count(); i++ ) {
		string dir = path.At( i );
		std::pair<DirSet::iterator, bool> ok = uniq.insert( dir );
		if ( ok.second ) {
			ordered.push_back( dir );
		}
		else {
			cout << "Pruned: " << dir << endl;
		}
	}

	string entry;

	for ( unsigned int i = 0; i < ordered.size(); i++ ) {
		string dir = ExpandPath( ordered[i] );
		DWORD attr = GetFileAttributes( dir.c_str() );
		if ( attr == INVALID_FILE_ATTRIBUTES ||
						! (attr & FILE_ATTRIBUTE_DIRECTORY ) ) {
			cout << "Pruned: " << ordered[i] << endl;
		}
		else {
			if ( entry != "" ) {
				entry += ";";
			}
			entry += ordered[i];
		}

	}
	path.ReplaceAll( entry );
	std::cout << entry << std::endl;
}

//----------------------------------------------------------------------------
// See if directory is on the path, if so return success code (not boolean!)
//----------------------------------------------------------------------------

int FindPath( CmdLine & cl ) {
	RegPath path( UseSys ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER );
	return  path.Find( cl.Argv(1), Expand ? RegPath::Expand : RegPath::NoExpand ) ? 0 : 1;
}

//----------------------------------------------------------------------------
// Verify directories on path exist.
//----------------------------------------------------------------------------

int VerifyPath() {
	RegPath path( UseSys ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER );
	int bad = 0;
	for ( unsigned int i = 0; i < path.Count(); i++ ) {
		string epath = ExpandPath( path.At(i) );
		DWORD attr = GetFileAttributes( epath.c_str() );
		if ( attr == INVALID_FILE_ATTRIBUTES ) {
			cout << "No such directory: " << epath << "\n";
			bad++;
		}
		else if ( ! (attr & FILE_ATTRIBUTE_DIRECTORY ) ) {
			cout << "Not a directory: " << epath << "\n";
			bad++;
		}
	}
	return bad == 0 ? 0 : 1;
}

//----------------------------------------------------------------------------
// Display help
//----------------------------------------------------------------------------

void Help() {

	cout <<

	"pathed is a command-line tool for changing the Windows path in the registry\n"
	"Version 0.4\n"
	"Copyright (C) 2011 Neil Butterworth\n\n"
	"usage: pathed [-a | -r | -l  | -q | -v | -p] [-s] [-f]  [-x] [dir]\n\n"
	"pathed -a dir    adds dir to the path in  the registry\n"
	"pathed -r dir    removes  dir from the path in the registry\n"
	"pathed -l        lists the entries on the current path\n"
	"pathed -q dir    queries registry, returns 0 if dir is on path, 1 otherwise\n"
	"pathed -v        verifies that all directories on the path exist\n"
	"pathed -p        prunes the path by removing duplicates and non-existent directories\n\n"
	"By default, pathed works on the path in HKEY_CURRENT_USER. You can make it use\n"
	"the system path in HKEY_LOCAL_MACHINE by using the -s flag.\n\n"
	"Normally, pathed will check a directory exists on disk before adding it to the\n"
	"path. To prevent this, use the -f flag.\n\n"
	"Paths containing environment variables such as %systemroot% will not normally have\n"
	"the variables expanded to their values. To expand them, use the -x flag\n\n"
	"AS WITH ALL COMMANDS THAT CHANGE THE REGISTRY, PATHED CAN CAUSE DAMAGE IF YOU\n"
	"DO NOT KNOW WHAT YOU ARE DOING. IF IN DOUBT, DO NOT USE IT!\n"

	<< endl;
}

//----------------------------------------------------------------------------
// Main for pathed
//----------------------------------------------------------------------------

int main( int argc, char *argv[] )
{
	try {
		CmdLine cl( argc, argv );

		SetFlags( cl );

		if ( cl.Argc() == 1 && ! ( List || Verify || Prune ) ) {
			Help();
			return 0;
		}
		else if ( ! (List || Add || QueryPath || Remove || Verify || Prune )  ) {
			throw Error( "Need one of -a, -r, -l, -q, -p or -v" );
		}

		if ( List ) {
			ListPath();
		}
		else if ( Verify ) {
			return VerifyPath();
		}
		else if ( QueryPath ) {
			return FindPath( cl );
		}
		else if ( Remove ) {
			RemovePath( cl );
		}
		else if ( Prune ) {
			PrunePath( cl );
		}
		else {
			AddPath( cl );
		}

		return 0;
	}
	catch( const Error & e ) {
		cerr << e.what() << endl;
		return 1;
	}
	catch( ... ) {
		cerr << "Unexpected exception" << endl;
		return 1;
	}
}
<|endoftext|>


<commit_before>//
//  utils.cpp
//  Xapiand
//
//  Created by Germán M. Bravo on 2/24/15.
//  Copyright (c) 2015 Germán M. Bravo. All rights reserved.
//

#include <stdio.h>

#include "pthread.h"

#include "utils.h"

bool qmtx_inited = false;
pthread_mutex_t qmtx;

std::string repr(const std::string &string)
{
	return repr(string.c_str(), string.size());
}

std::string repr(const char * p, size_t size)
{
	const char *p_end = p + size;
	std::string ret;
	char buff[4];

	while (p != p_end) {
		char c = *p++;
		if (c == 9) {
			ret += "\\t";
		} else if (c == 10) {
			ret += "\\n";
		} else if (c == 13) {
			ret += "\\r";
//		} else if (c == '"') {
//			ret += "\\\"";
		} else if (c == '\'') {
			ret += "\\\'";
		} else if (c >= ' ' && c <= '~') {
			sprintf(buff, "%c", c);
			ret += buff;
		} else {
			sprintf(buff, "\\x%02x", c & 0xff);
			ret += buff;
		}
	}
	return ret;
}

void log(void *obj, const char *format, ...)
{
	if (!qmtx_inited) {
		pthread_mutex_init(&qmtx, 0);
		qmtx_inited = true;
	}

	pthread_mutex_lock(&qmtx);

	FILE * file = stderr;
	fprintf(file, "tid(0x%lx): 0x%lx - ", (unsigned long)pthread_self(), (unsigned long)obj);
	va_list argptr;
	va_start(argptr, format);
	vfprintf(file, format, argptr);
	va_end(argptr);

	pthread_mutex_unlock(&qmtx);
}
<commit_msg>Fixed issues with repr()<commit_after>//
//  utils.cpp
//  Xapiand
//
//  Created by Germán M. Bravo on 2/24/15.
//  Copyright (c) 2015 Germán M. Bravo. All rights reserved.
//

#include <stdio.h>

#include "pthread.h"

#include "utils.h"

bool qmtx_inited = false;
pthread_mutex_t qmtx;

std::string repr(const std::string &string)
{
	return repr(string.c_str(), string.size());
}

std::string repr(const char * p, size_t size)
{
	char *buff = new char[size * 4 + 1];
	char *d = buff;
	const char *p_end = p + size;
	while (p != p_end) {
		char c = *p++;
		if (c == 9) {
			*d++ = '\\';
			*d++ = 't';
		} else if (c == 10) {
			*d++ = '\\';
			*d++ = 'n';
		} else if (c == 13) {
			*d++ = '\\';
			*d++ = 'r';
		} else if (c == '\'') {
			*d++ = '\\';
			*d++ = '\'';
		} else if (c >= ' ' && c <= '~') {
			*d++ = c;
		} else {
			*d++ = '\\';
			*d++ = 'x';
			sprintf(d, "%02x", (unsigned char)c);
			d += 2;
		}
		// printf("%02x: %ld < %ld\n", (unsigned char)c, d - buff, size * 4 + 1);
	}
	*d = '\0';
	std::string ret(buff);
	delete [] buff;
	return ret;
}

void log(void *obj, const char *format, ...)
{
	if (!qmtx_inited) {
		pthread_mutex_init(&qmtx, 0);
		qmtx_inited = true;
	}

	pthread_mutex_lock(&qmtx);

	FILE * file = stderr;
	fprintf(file, "tid(0x%lx): 0x%lx - ", (unsigned long)pthread_self(), (unsigned long)obj);
	va_list argptr;
	va_start(argptr, format);
	vfprintf(file, format, argptr);
	va_end(argptr);

	pthread_mutex_unlock(&qmtx);
}
<|endoftext|>


<commit_before>
#ifndef __LIB_UTILS_HPP
#define __LIB_UTILS_HPP

#include <experimental/optional>

namespace lib::utils {

  template <class Base>
  struct DerivedClass : public Base {
    template <typename ...Args> DerivedClass (Args & ...args) : Base(args ...) {}
  };

  template <typename Base>
  using Nullable = std::experimental::optional<Base>;

  template <typename Base, Base byDefault>
  class Optional : public Nullable<Base> {
  private:
    typedef Nullable<Base> NBase;
  public:
    template <typename ...Args> Optional (Args ...args) : NBase(args ...) {}
    operator Base () {
      return NBase::value_or(byDefault);
    }
  };

}

#endif
<commit_msg>Add/remove some empty lines<commit_after>
#ifndef __LIB_UTILS_HPP
#define __LIB_UTILS_HPP

#include <experimental/optional>

namespace lib::utils {
  template <class Base>
  struct DerivedClass : public Base {
    template <typename ...Args> DerivedClass (Args & ...args) : Base(args ...) {}
  };

  template <typename Base>
  using Nullable = std::experimental::optional<Base>;

  template <typename Base, Base byDefault>
  class Optional : public Nullable<Base> {
  private:
    typedef Nullable<Base> NBase;

  public:
    template <typename ...Args> Optional (Args ...args) : NBase(args ...) {}

    operator Base () {
      return NBase::value_or(byDefault);
    }
  };
}

#endif
<|endoftext|>