<commit_before>#include "midiio.h"

#include "lpd8_sysex.h"
#include "midiportsmodel.h"

#include <QGuiApplication>
#include <QSocketNotifier>
#include <QtDebug>
#include <QStandardItemModel>
#include <QThread>

#include <exception>

MidiIO::MidiIO(QObject *parent) : QObject(parent),
    m_seq_handle(Q_NULLPTR),
    m_pfds(Q_NULLPTR),
    m_seq_port(-1),
    m_ports_model(Q_NULLPTR)
{
    qDebug() << "Opening MIDI sequencer";

    if (snd_seq_open(&m_seq_handle, "default", SND_SEQ_OPEN_DUPLEX, 0) < 0) {
        throw std::runtime_error("Failed opening sequencer");
    }

    // Poll

    int npfd = snd_seq_poll_descriptors_count(m_seq_handle, POLLIN);
    m_pfds = (struct pollfd *)alloca(npfd * sizeof(struct pollfd));
    int npfdf = snd_seq_poll_descriptors(m_seq_handle, m_pfds, npfd, POLLIN);

    for (int i = 0 ; i < npfdf ; ++i) {
        qDebug() << "Enabling MIDI poll descriptor" << i;
        QSocketNotifier* n = new QSocketNotifier(m_pfds[i].fd, QSocketNotifier::Read);
        connect(qGuiApp,
                &QGuiApplication::aboutToQuit,
                [=]() {
                    qDebug() << "Disabling MIDI poll descriptor" << i;
                    n->setEnabled(false);
                }
        );
        connect(n,
                &QSocketNotifier::activated,
                this,
                &MidiIO::readEvents
        );
    }

    //    snd_seq_set_client_event_filter(m_seq_handle, SND_SEQ_EVENT_SYSEX);

    // Try qUtf8Printable
    if (snd_seq_set_client_name(m_seq_handle, qPrintable(qApp->applicationName())) < 0) {
        throw std::runtime_error("Failed setting sequencer name");
    }

    // In port
    m_seq_port = snd_seq_create_simple_port(
                m_seq_handle,
                qPrintable(qGuiApp->applicationName()),
                SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_DUPLEX | SND_SEQ_PORT_CAP_SUBS_READ | SND_SEQ_PORT_CAP_SUBS_WRITE,
                SND_SEQ_PORT_TYPE_APPLICATION);
    if (m_seq_port < 0) {
        throw std::runtime_error("Failed setting sequencer port");
    }

//    m_ports_model = new MidiPortsModel(m_seq_handle, m_seq_port, this);
    m_ports_model = new QStandardItemModel(this);
}

MidiIO::~MidiIO() {
    qDebug() << "Closing MIDI sequencer";
    if (snd_seq_delete_simple_port(m_seq_handle, m_seq_port) >= 0) {
        m_seq_port = -1;
    } else {
        qWarning() << "Failed deleting sequencer port";
    }

    if (snd_seq_close(m_seq_handle) >= 0) {
        m_seq_handle = Q_NULLPTR;
    } else {
        qWarning() << "Failed closing sequencer";
    }
}

QAbstractItemModel* MidiIO::midiPortsModel() const {
    Q_CHECK_PTR(m_ports_model);

    return m_ports_model;
}

void MidiIO::readEvents()
{
    qDebug();
    while (snd_seq_event_input_pending(m_seq_handle, 1) > 0) {
        snd_seq_event_t *ev;
        snd_seq_event_input(m_seq_handle, &ev);
        processEvent(ev);
    }
}

void MidiIO::processEvent(snd_seq_event_t* ev)
{
    switch (ev->type) {
    case SND_SEQ_EVENT_PORT_SUBSCRIBED:
        processPortSubscribed(ev);
        break;
    case SND_SEQ_EVENT_PORT_UNSUBSCRIBED:
        break;
    case SND_SEQ_EVENT_PORT_START:
        break;
    case SND_SEQ_EVENT_PORT_EXIT:
        break;
    case SND_SEQ_EVENT_PORT_CHANGE:
        break;
    case SND_SEQ_EVENT_SYSEX:
        processSysex(ev);
    default:
        break;
    }
}

void MidiIO::processPortSubscribed(snd_seq_event_t* ev) {
    Q_CHECK_PTR(ev);
    Q_ASSERT(ev->type == SND_SEQ_EVENT_PORT_SUBSCRIBED);

//    sendIdRequest();
}

void MidiIO::processSysex(snd_seq_event_t* ev) {
    Q_CHECK_PTR(ev);
    Q_ASSERT(ev->type == SND_SEQ_EVENT_SYSEX);

    QByteArray s(
        static_cast<const char*>(ev->data.ext.ptr),
        ev->data.ext.len);

    switch (sysex::type(s)) {
    case sysex::TypeProgram:
        emit programReceived(sysex::toProgram(s));
        break;
    default:
        break;
    }
    emit sysexReceived(s);
}

void MidiIO::sendIdRequest() const
{
    const unsigned char b[] = {0xF0, 0x7E, 0x00, 0x06, 0x01, 0xF7};
    const QByteArray sysex(reinterpret_cast<const char*>(b), sizeof(b));
    sendSysex(sysex);
}

void MidiIO::sendSysex(QByteArray sysex) const
{
    snd_seq_event_t ev;
    snd_seq_ev_clear(&ev);
    snd_seq_ev_set_subs(&ev);
    snd_seq_ev_set_direct(&ev);
    snd_seq_ev_set_source(&ev, m_seq_port);
    snd_seq_ev_set_sysex(&ev, sysex.length(), sysex.data());

    int err = snd_seq_event_output(m_seq_handle, &ev);
    if (err < 0) {
        throw std::runtime_error(snd_strerror(err));
    }
    err = 1;
    while (err > 0) {
        err = snd_seq_drain_output(m_seq_handle);
        if (err < 0) {
            throw std::runtime_error(snd_strerror(err));
        }
    }
}

void MidiIO::getPrograms() const {
    for (int i = 1 ; i <= 4 ; ++i) {
        sendSysex(sysex::getProgram(i));
    }
}

void MidiIO::sendProgram(pProgram program) const
{
    QByteArray s = sysex::setProgram(program);
    sendSysex(s);
}

void MidiIO::getProgram(int id) const {
    Q_ASSERT(id >= 1 && id <= 4);

    sendSysex(sysex::getProgram(id));
    QThread::sleep(1);
}

enum MidiPortRole {
    ClientRole = Qt::UserRole + 1,
    PortRole
};

// Template it, baby
template<typename T, int Role>
void set(QStandardItem* item, T v) {
    Q_CHECK_PTR(item);

    item->setData(v, Role);
}

template<typename T, int Role>
T get(const QStandardItem* item) {
    Q_CHECK_PTR(item);

    return item->data(Role).value<T>();
}

void (&setClient)(QStandardItem*, int) = set<int, ClientRole>;
void (&setPort)(QStandardItem*, int) = set<int, PortRole>;
int (&client)(const QStandardItem*) = get<int, ClientRole>;
int (&port)(const QStandardItem*) = get<int, PortRole>;

QStandardItem* takeItemFromAlsaAddress(QList<QStandardItem*>& items, const snd_seq_addr_t* addr) {
    Q_CHECK_PTR(addr);

    QStandardItem* item = Q_NULLPTR;
    foreach (item, items) {
        if (client(item) == addr->client && port(item) == addr->port) {
            break;
        }
    }
    if (item) {
        items.removeAt(items.indexOf(item));
    }
    return item;
}

void MidiIO::rescanPorts() {
    Q_CHECK_PTR(m_seq_handle);
    Q_CHECK_PTR(m_ports_model);

    // Existing items
    QList<QStandardItem*> existing;
    for (int i = 0 ; i < m_ports_model->rowCount() ; ++i) {
        existing << m_ports_model->item(i);
    }

    snd_seq_client_info_t *cinfo;
    snd_seq_port_info_t *pinfo;

    snd_seq_client_info_alloca(&cinfo);
    snd_seq_port_info_alloca(&pinfo);

    const int current_client_id = snd_seq_client_id(m_seq_handle);

    snd_seq_client_info_set_client(cinfo, -1);
    while (snd_seq_query_next_client(m_seq_handle, cinfo) >= 0) {
        const int id = snd_seq_client_info_get_client(cinfo);

        // Filter current client and system client (0)
        if (id == current_client_id || id == 0) {
            continue;
        }

        snd_seq_port_info_set_client(pinfo, id);
        snd_seq_port_info_set_port(pinfo, -1);

        while (snd_seq_query_next_port(m_seq_handle, pinfo) >= 0) {
            const unsigned int caps = snd_seq_port_info_get_capability(pinfo);

            const snd_seq_addr_t* addr = snd_seq_port_info_get_addr(pinfo);
            Q_CHECK_PTR(addr);

            // Filter non exportable and non read / write ports
            if ((caps & SND_SEQ_PORT_CAP_NO_EXPORT) > 0 ||
                (caps & SND_SEQ_PORT_CAP_READ) == 0 ||
                (caps & SND_SEQ_PORT_CAP_WRITE) == 0) {
                continue;
            }

            QStandardItem* item = takeItemFromAlsaAddress(existing, addr);
            if (!item) {
                item = new QStandardItem();
                setClient(item, addr->client);
                setPort(item, addr->port);
                m_ports_model->appendRow(item);
            }
            item->setText(snd_seq_port_info_get_name(pinfo));
        }
    }

    // Remove old items
    int rc = m_ports_model->rowCount();
    QStandardItem* item = Q_NULLPTR;
    foreach (item, existing) {
        const QModelIndex index = m_ports_model->indexFromItem(item);
        Q_ASSERT(index.isValid());

        QStandardItem* rowItem = Q_NULLPTR;
        foreach (rowItem, m_ports_model->takeRow(index.row())) {
            Q_CHECK_PTR(rowItem);
            delete rowItem;
        }
        rc = m_ports_model->rowCount();
        Q_UNUSED(rc);
    }
}

void MidiIO::connectPort(const QModelIndex& index) {
    Q_CHECK_PTR(m_ports_model);
    Q_ASSERT(m_seq_port >= 0);

    QStandardItem* item = m_ports_model->itemFromIndex(index);
    Q_CHECK_PTR(item);

    const int c = client(item);
    const int p = port(item);

    if (snd_seq_connect_from(m_seq_handle, m_seq_port, c, p) < 0) {
        qDebug() << "Cannot connect from";
    }

    if (snd_seq_connect_to(m_seq_handle, m_seq_port, c, p) < 0) {
        qDebug() << "Cannot connect to";
    }
}
<commit_msg>Do no connect if already connected<commit_after>#include "midiio.h"

#include "lpd8_sysex.h"
#include "midiportsmodel.h"

#include <QGuiApplication>
#include <QSocketNotifier>
#include <QtDebug>
#include <QStandardItemModel>
#include <QThread>

#include <exception>

MidiIO::MidiIO(QObject *parent) : QObject(parent),
    m_seq_handle(Q_NULLPTR),
    m_pfds(Q_NULLPTR),
    m_seq_port(-1),
    m_ports_model(Q_NULLPTR)
{
    qDebug() << "Opening MIDI sequencer";

    if (snd_seq_open(&m_seq_handle, "default", SND_SEQ_OPEN_DUPLEX, 0) < 0) {
        throw std::runtime_error("Failed opening sequencer");
    }

    // Poll

    int npfd = snd_seq_poll_descriptors_count(m_seq_handle, POLLIN);
    m_pfds = (struct pollfd *)alloca(npfd * sizeof(struct pollfd));
    int npfdf = snd_seq_poll_descriptors(m_seq_handle, m_pfds, npfd, POLLIN);

    for (int i = 0 ; i < npfdf ; ++i) {
        qDebug() << "Enabling MIDI poll descriptor" << i;
        QSocketNotifier* n = new QSocketNotifier(m_pfds[i].fd, QSocketNotifier::Read);
        connect(qGuiApp,
                &QGuiApplication::aboutToQuit,
                [=]() {
                    qDebug() << "Disabling MIDI poll descriptor" << i;
                    n->setEnabled(false);
                }
        );
        connect(n,
                &QSocketNotifier::activated,
                this,
                &MidiIO::readEvents
        );
    }

    //    snd_seq_set_client_event_filter(m_seq_handle, SND_SEQ_EVENT_SYSEX);

    // Try qUtf8Printable
    if (snd_seq_set_client_name(m_seq_handle, qPrintable(qApp->applicationName())) < 0) {
        throw std::runtime_error("Failed setting sequencer name");
    }

    // In port
    m_seq_port = snd_seq_create_simple_port(
                m_seq_handle,
                qPrintable(qGuiApp->applicationName()),
                SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_DUPLEX | SND_SEQ_PORT_CAP_SUBS_READ | SND_SEQ_PORT_CAP_SUBS_WRITE,
                SND_SEQ_PORT_TYPE_APPLICATION);
    if (m_seq_port < 0) {
        throw std::runtime_error("Failed setting sequencer port");
    }

//    m_ports_model = new MidiPortsModel(m_seq_handle, m_seq_port, this);
    m_ports_model = new QStandardItemModel(this);
}

MidiIO::~MidiIO() {
    qDebug() << "Closing MIDI sequencer";
    if (snd_seq_delete_simple_port(m_seq_handle, m_seq_port) >= 0) {
        m_seq_port = -1;
    } else {
        qWarning() << "Failed deleting sequencer port";
    }

    if (snd_seq_close(m_seq_handle) >= 0) {
        m_seq_handle = Q_NULLPTR;
    } else {
        qWarning() << "Failed closing sequencer";
    }
}

QAbstractItemModel* MidiIO::midiPortsModel() const {
    Q_CHECK_PTR(m_ports_model);

    return m_ports_model;
}

void MidiIO::readEvents()
{
    qDebug();
    while (snd_seq_event_input_pending(m_seq_handle, 1) > 0) {
        snd_seq_event_t *ev;
        snd_seq_event_input(m_seq_handle, &ev);
        processEvent(ev);
    }
}

void MidiIO::processEvent(snd_seq_event_t* ev)
{
    switch (ev->type) {
    case SND_SEQ_EVENT_PORT_SUBSCRIBED:
        processPortSubscribed(ev);
        break;
    case SND_SEQ_EVENT_PORT_UNSUBSCRIBED:
        break;
    case SND_SEQ_EVENT_PORT_START:
        break;
    case SND_SEQ_EVENT_PORT_EXIT:
        break;
    case SND_SEQ_EVENT_PORT_CHANGE:
        break;
    case SND_SEQ_EVENT_SYSEX:
        processSysex(ev);
    default:
        break;
    }
}

void MidiIO::processPortSubscribed(snd_seq_event_t* ev) {
    Q_CHECK_PTR(ev);
    Q_ASSERT(ev->type == SND_SEQ_EVENT_PORT_SUBSCRIBED);

//    sendIdRequest();
}

void MidiIO::processSysex(snd_seq_event_t* ev) {
    Q_CHECK_PTR(ev);
    Q_ASSERT(ev->type == SND_SEQ_EVENT_SYSEX);

    QByteArray s(
        static_cast<const char*>(ev->data.ext.ptr),
        ev->data.ext.len);

    switch (sysex::type(s)) {
    case sysex::TypeProgram:
        emit programReceived(sysex::toProgram(s));
        break;
    default:
        break;
    }
    emit sysexReceived(s);
}

void MidiIO::sendIdRequest() const
{
    const unsigned char b[] = {0xF0, 0x7E, 0x00, 0x06, 0x01, 0xF7};
    const QByteArray sysex(reinterpret_cast<const char*>(b), sizeof(b));
    sendSysex(sysex);
}

void MidiIO::sendSysex(QByteArray sysex) const
{
    snd_seq_event_t ev;
    snd_seq_ev_clear(&ev);
    snd_seq_ev_set_subs(&ev);
    snd_seq_ev_set_direct(&ev);
    snd_seq_ev_set_source(&ev, m_seq_port);
    snd_seq_ev_set_sysex(&ev, sysex.length(), sysex.data());

    int err = snd_seq_event_output(m_seq_handle, &ev);
    if (err < 0) {
        throw std::runtime_error(snd_strerror(err));
    }
    err = 1;
    while (err > 0) {
        err = snd_seq_drain_output(m_seq_handle);
        if (err < 0) {
            throw std::runtime_error(snd_strerror(err));
        }
    }
}

void MidiIO::getPrograms() const {
    for (int i = 1 ; i <= 4 ; ++i) {
        sendSysex(sysex::getProgram(i));
    }
}

void MidiIO::sendProgram(pProgram program) const
{
    QByteArray s = sysex::setProgram(program);
    sendSysex(s);
}

void MidiIO::getProgram(int id) const {
    Q_ASSERT(id >= 1 && id <= 4);

    sendSysex(sysex::getProgram(id));
    QThread::sleep(1);
}

enum MidiPortRole {
    ClientRole = Qt::UserRole + 1,
    PortRole
};

// Template it, baby
template<typename T, int Role>
void set(QStandardItem* item, T v) {
    Q_CHECK_PTR(item);

    item->setData(v, Role);
}

template<typename T, int Role>
T get(const QStandardItem* item) {
    Q_CHECK_PTR(item);

    return item->data(Role).value<T>();
}

void (&setClient)(QStandardItem*, int) = set<int, ClientRole>;
void (&setPort)(QStandardItem*, int) = set<int, PortRole>;
int (&client)(const QStandardItem*) = get<int, ClientRole>;
int (&port)(const QStandardItem*) = get<int, PortRole>;

QStandardItem* takeItemFromAlsaAddress(QList<QStandardItem*>& items, const snd_seq_addr_t* addr) {
    Q_CHECK_PTR(addr);

    QStandardItem* item = Q_NULLPTR;
    foreach (item, items) {
        if (client(item) == addr->client && port(item) == addr->port) {
            break;
        }
    }
    if (item) {
        items.removeAt(items.indexOf(item));
    }
    return item;
}

void MidiIO::rescanPorts() {
    Q_CHECK_PTR(m_seq_handle);
    Q_CHECK_PTR(m_ports_model);

    // Existing items
    QList<QStandardItem*> existing;
    for (int i = 0 ; i < m_ports_model->rowCount() ; ++i) {
        existing << m_ports_model->item(i);
    }

    snd_seq_client_info_t *cinfo;
    snd_seq_port_info_t *pinfo;

    snd_seq_client_info_alloca(&cinfo);
    snd_seq_port_info_alloca(&pinfo);

    const int current_client_id = snd_seq_client_id(m_seq_handle);

    snd_seq_client_info_set_client(cinfo, -1);
    while (snd_seq_query_next_client(m_seq_handle, cinfo) >= 0) {
        const int id = snd_seq_client_info_get_client(cinfo);

        // Filter current client and system client (0)
        if (id == current_client_id || id == 0) {
            continue;
        }

        snd_seq_port_info_set_client(pinfo, id);
        snd_seq_port_info_set_port(pinfo, -1);

        while (snd_seq_query_next_port(m_seq_handle, pinfo) >= 0) {
            const unsigned int caps = snd_seq_port_info_get_capability(pinfo);

            const snd_seq_addr_t* addr = snd_seq_port_info_get_addr(pinfo);
            Q_CHECK_PTR(addr);

            // Filter non exportable and non read / write ports
            if ((caps & SND_SEQ_PORT_CAP_NO_EXPORT) > 0 ||
                (caps & SND_SEQ_PORT_CAP_READ) == 0 ||
                (caps & SND_SEQ_PORT_CAP_WRITE) == 0) {
                continue;
            }

            QStandardItem* item = takeItemFromAlsaAddress(existing, addr);
            if (!item) {
                item = new QStandardItem();
                setClient(item, addr->client);
                setPort(item, addr->port);
                m_ports_model->appendRow(item);
            }
            item->setText(snd_seq_port_info_get_name(pinfo));
        }
    }

    // Remove old items
    int rc = m_ports_model->rowCount();
    QStandardItem* item = Q_NULLPTR;
    foreach (item, existing) {
        const QModelIndex index = m_ports_model->indexFromItem(item);
        Q_ASSERT(index.isValid());

        QStandardItem* rowItem = Q_NULLPTR;
        foreach (rowItem, m_ports_model->takeRow(index.row())) {
            Q_CHECK_PTR(rowItem);
            delete rowItem;
        }
        rc = m_ports_model->rowCount();
        Q_UNUSED(rc);
    }
}

void MidiIO::connectPort(const QModelIndex& index) {
    Q_CHECK_PTR(m_ports_model);
    Q_ASSERT(m_seq_port >= 0);

    QStandardItem* item = m_ports_model->itemFromIndex(index);
    Q_CHECK_PTR(item);

    const snd_seq_addr_t ownaddr = {
        static_cast<unsigned char>(snd_seq_client_id(m_seq_handle)),
        static_cast<unsigned char>(m_seq_port)
    };

    const int c = client(item);
    const int p = port(item);
    const snd_seq_addr_t addr = {
        static_cast<unsigned char>(c),
        static_cast<unsigned char>(p)
    };

    snd_seq_port_subscribe_t *subs;
    snd_seq_port_subscribe_alloca(&subs);

    snd_seq_port_subscribe_set_sender(subs, &ownaddr);
    snd_seq_port_subscribe_set_dest(subs, &addr);
    if (snd_seq_get_port_subscription(m_seq_handle, subs) == 0) {
        qDebug() << "Already connected from" << item->text();
        return;
    }

    if (snd_seq_connect_from(m_seq_handle, m_seq_port, c, p) < 0) {
        qDebug() << "Cannot connect from";
    }

    if (snd_seq_connect_to(m_seq_handle, m_seq_port, c, p) < 0) {
        qDebug() << "Cannot connect to";
    }
}
<|endoftext|>


<commit_before>/*
  +----------------------------------------------------------------------+
  | Swoole                                                               |
  +----------------------------------------------------------------------+
  | This source file is subject to version 2.0 of the Apache license,    |
  | that is bundled with this package in the file LICENSE, and is        |
  | available through the world-wide-web at the following url:           |
  | http://www.apache.org/licenses/LICENSE-2.0.html                      |
  | If you did not receive a copy of the Apache2.0 license and are unable|
  | to obtain it through the world-wide-web, please send a note to       |
  | license@swoole.com so we can mail you a copy immediately.            |
  +----------------------------------------------------------------------+
  | Author: Tianfeng Han  <mikan.tenny@gmail.com>                        |
  +----------------------------------------------------------------------+
*/
#include "swoole.h"
#include "swoole_api.h"

#include "coroutine.h"
#include "coroutine_system.h"

#include <list>
#include <unordered_map>

using namespace std;
using namespace swoole;
using swoole::coroutine::System;

struct wait_task
{
    Coroutine *co;
    pid_t pid;
    int status;
};

static list<wait_task *> wait_list;
static unordered_map<int, wait_task *> waitpid_map;
static unordered_map<int, int> child_processes;

bool signal_ready = false;

static void signal_handler(int signo)
{
    if (signo == SIGCHLD)
    {
        int __stat_loc;

        while (true)
        {
            pid_t __pid = waitpid(-1, &__stat_loc, WNOHANG);
            if (__pid <= 0)
            {
                break;
            }

            wait_task *task = nullptr;
            if (waitpid_map.find(__pid) != waitpid_map.end())
            {
                task = waitpid_map[__pid];
            }
            else if (!wait_list.empty())
            {
                task = wait_list.front();
            }
            else
            {
                child_processes[__pid] = __stat_loc;
            }

            if (task)
            {
                task->status = __stat_loc;
                task->pid = __pid;
                task->co->resume();
            }
        }
    }
}

static void signal_free(void *nullopt)
{
    signal_ready = false;
    swSignal_clear();
}

static void signal_init()
{
    if (!signal_ready)
    {
        swReactor *reactor = SwooleTG.reactor;
        swSignal_add(SIGCHLD, signal_handler);
#ifdef HAVE_SIGNALFD
        if (SwooleG.use_signalfd && !swReactor_isset_handler(reactor, SW_FD_SIGNAL))
        {
            swSignalfd_setup(reactor);
        }
#endif
        swReactor_add_destroy_callback(reactor, (swCallback) signal_free, nullptr);
        signal_ready = true;
    }
}

pid_t System::wait(int *__stat_loc , double timeout)
{
    return System::waitpid(-1, __stat_loc, 0, timeout);
}

pid_t System::waitpid(pid_t __pid, int *__stat_loc, int __options, double timeout)
{
    if (__pid < 0)
    {
        if (!child_processes.empty())
        {
            auto i = child_processes.begin();
            pid_t __pid = i->first;
            *__stat_loc = i->second;
            child_processes.erase(i);
            return __pid;
        }
    }
    else
    {
        auto i = child_processes.find(__pid);
        if (i != child_processes.end())
        {
            *__stat_loc = i->second;
            child_processes.erase(i);
            return __pid;
        }
    }

    if (sw_unlikely(SwooleTG.reactor == nullptr || !Coroutine::get_current() || (__options & WNOHANG)))
    {
        return ::waitpid(__pid, __stat_loc, __options);
    }

    /* try once if failed we init the task */
    wait_task task;
    task.pid = ::waitpid(__pid, __stat_loc, __options | WNOHANG);
    if (task.pid > 0)
    {
        return task.pid;
    }

    signal_init();

    task.pid = -1;
    task.status = 0;
    task.co = Coroutine::get_current();

    /* enqueue */
    if (__pid < 0)
    {
        wait_list.push_back(&task);
    }
    else
    {
        waitpid_map[__pid] = &task;
    }

    /* timeout controller */
    swTimer_node* timer = nullptr;
    if (timeout > 0)
    {
        timer = swoole_timer_add(timeout * 1000, 0, [](swTimer *timer, swTimer_node *tnode) {
            Coroutine *co = (Coroutine *) tnode->data;
            co->resume();
        }, task.co);
    }

    task.co->yield();

    /* dequeue */
    if (__pid < 0)
    {
        if (task.pid > 0)
        {
            wait_list.pop_front();
        }
        else
        {
            /* timeout so we should remove it from the list */
            wait_list.remove(&task);
        }
    }
    else
    {
        waitpid_map.erase(__pid);
    }

    /* clear and assign result */
    if (task.pid > 0)
    {
        if (timer)
        {
            swoole_timer_del(timer);
        }
        *__stat_loc = task.status;
    }
    else
    {
        errno = ETIMEDOUT;
    }

    return task.pid;
}

extern "C"
{

size_t swoole_coroutine_wait_count()
{
    return wait_list.size() + waitpid_map.size();
}

pid_t swoole_coroutine_wait(int *__stat_loc)
{
    return System::wait(__stat_loc);
}

pid_t swoole_coroutine_waitpid(pid_t __pid, int *__stat_loc, int __options)
{
    return System::waitpid(__pid, __stat_loc, __options);
}

}
<commit_msg>fix: fix #3444 (#3446)<commit_after>/*
  +----------------------------------------------------------------------+
  | Swoole                                                               |
  +----------------------------------------------------------------------+
  | This source file is subject to version 2.0 of the Apache license,    |
  | that is bundled with this package in the file LICENSE, and is        |
  | available through the world-wide-web at the following url:           |
  | http://www.apache.org/licenses/LICENSE-2.0.html                      |
  | If you did not receive a copy of the Apache2.0 license and are unable|
  | to obtain it through the world-wide-web, please send a note to       |
  | license@swoole.com so we can mail you a copy immediately.            |
  +----------------------------------------------------------------------+
  | Author: Tianfeng Han  <mikan.tenny@gmail.com>                        |
  +----------------------------------------------------------------------+
*/
#include "swoole.h"
#include "swoole_api.h"

#include "coroutine.h"
#include "coroutine_system.h"

#include <list>
#include <unordered_map>

using namespace std;
using namespace swoole;
using swoole::coroutine::System;

struct wait_task
{
    Coroutine *co;
    pid_t pid;
    int status;
};

static list<wait_task *> wait_list;
static unordered_map<int, wait_task *> waitpid_map;
static unordered_map<int, int> child_processes;

bool signal_ready = false;

static void signal_handler(int signo)
{
    if (signo == SIGCHLD)
    {
        int __stat_loc;

        while (true)
        {
            pid_t __pid = waitpid(-1, &__stat_loc, WNOHANG);
            if (__pid <= 0)
            {
                break;
            }

            wait_task *task = nullptr;
            if (waitpid_map.find(__pid) != waitpid_map.end())
            {
                task = waitpid_map[__pid];
            }
            else if (!wait_list.empty())
            {
                task = wait_list.front();
            }
            else
            {
                child_processes[__pid] = __stat_loc;
            }

            if (task)
            {
                task->status = __stat_loc;
                task->pid = __pid;
                task->co->resume();
            }
        }
    }
}

static void signal_free(void *nullopt)
{
    signal_ready = false;
    swSignal_clear();
}

static void signal_init()
{
    if (!signal_ready)
    {
        swReactor *reactor = SwooleTG.reactor;
        swSignal_add(SIGCHLD, signal_handler);
#ifdef HAVE_SIGNALFD
        if (SwooleG.use_signalfd && !swReactor_isset_handler(reactor, SW_FD_SIGNAL))
        {
            swSignalfd_setup(reactor);
        }
#endif
        swReactor_add_destroy_callback(reactor, (swCallback) signal_free, nullptr);
        signal_ready = true;
    }
}

pid_t System::wait(int *__stat_loc , double timeout)
{
    return System::waitpid(-1, __stat_loc, 0, timeout);
}

pid_t System::waitpid(pid_t __pid, int *__stat_loc, int __options, double timeout)
{
    if (__pid < 0)
    {
        if (!child_processes.empty())
        {
            auto i = child_processes.begin();
            pid_t __pid = i->first;
            *__stat_loc = i->second;
            child_processes.erase(i);
            return __pid;
        }
    }
    else
    {
        auto i = child_processes.find(__pid);
        if (i != child_processes.end())
        {
            *__stat_loc = i->second;
            child_processes.erase(i);
            return __pid;
        }
    }

    if (sw_unlikely(SwooleTG.reactor == nullptr || !Coroutine::get_current() || (__options & WNOHANG)))
    {
        return ::waitpid(__pid, __stat_loc, __options);
    }

    /* try once if failed we init the task, and we must register SIGCHLD before try waitpid, or we may lose the SIGCHLD */
    wait_task task;
    signal_init();
    task.pid = ::waitpid(__pid, __stat_loc, __options | WNOHANG);
    if (task.pid > 0)
    {
        return task.pid;
    }

    task.pid = -1;
    task.status = 0;
    task.co = Coroutine::get_current();

    /* enqueue */
    if (__pid < 0)
    {
        wait_list.push_back(&task);
    }
    else
    {
        waitpid_map[__pid] = &task;
    }

    /* timeout controller */
    swTimer_node* timer = nullptr;
    if (timeout > 0)
    {
        timer = swoole_timer_add(timeout * 1000, 0, [](swTimer *timer, swTimer_node *tnode) {
            Coroutine *co = (Coroutine *) tnode->data;
            co->resume();
        }, task.co);
    }

    task.co->yield();

    /* dequeue */
    if (__pid < 0)
    {
        if (task.pid > 0)
        {
            wait_list.pop_front();
        }
        else
        {
            /* timeout so we should remove it from the list */
            wait_list.remove(&task);
        }
    }
    else
    {
        waitpid_map.erase(__pid);
    }

    /* clear and assign result */
    if (task.pid > 0)
    {
        if (timer)
        {
            swoole_timer_del(timer);
        }
        *__stat_loc = task.status;
    }
    else
    {
        errno = ETIMEDOUT;
    }

    return task.pid;
}

extern "C"
{

size_t swoole_coroutine_wait_count()
{
    return wait_list.size() + waitpid_map.size();
}

pid_t swoole_coroutine_wait(int *__stat_loc)
{
    return System::wait(__stat_loc);
}

pid_t swoole_coroutine_waitpid(pid_t __pid, int *__stat_loc, int __options)
{
    return System::waitpid(__pid, __stat_loc, __options);
}

}
<|endoftext|>


<commit_before>/*
    Licensed under The MIT License (MIT)
    You will find the full license legal mumbo jumbo in file "LICENSE"

    Copyright (c) 2015 - 2018 Oscar Campbell

    Inspired by Ben Noordhuis module node-mmap - which does the same thing for older node
    versions, sans advise and sync.
*/
#include <nan.h>
#include <errno.h>
#include <string>

#ifdef _WIN32
#include <windows.h>
#include "mman.h"
#else
#include <unistd.h>
#include <sys/mman.h>
#endif

/* #include <future> */

using namespace v8;

// Just a bit more clear as to intent
#define JS_FN(a) NAN_METHOD(a)

// This lib is one of those pieces of code where clarity is better then puny micro opts (in
// comparison to the massive blocking that will occur when the data is first read from disk)
// Since casting `size` to `void*` feels a little "out there" considering that void* may be
// 32b or 64b (or, I dunno, 47b on some quant particle system), we throw this struct in.
struct MMap {
    MMap(char* data, size_t size) : data(data), size(size) {}
    char*   data = nullptr;
    size_t  size = 0;
};

void do_mmap_cleanup(char* data, void* hint) {
            auto map_info = static_cast<MMap*>(hint);
            munmap(data, map_info->size);
            delete map_info;
}

inline int do_mmap_advice(char* addr, size_t length, int advise) {
            return madvise(static_cast<void*>(addr), length, advise);
}

JS_FN(mmap_map) {
            Nan::HandleScope();

            if (info.Length() < 4 && info.Length() > 6) {
                return Nan::ThrowError(
                    "map() takes 4, 5 or 6 arguments: (size :int, protection :int, flags :int, fd :int [, offset :int [, advise :int]])."
                );
            }

            // Try to be a little (motherly) helpful to us poor clueless developers
            if (!info[0]->IsNumber())    return Nan::ThrowError("mmap: size (arg[0]) must be an integer");
            if (!info[1]->IsNumber())    return Nan::ThrowError("mmap: protection_flags (arg[1]) must be an integer");
            if (!info[2]->IsNumber())    return Nan::ThrowError("mmap: flags (arg[2]) must be an integer");
            if (!info[3]->IsNumber())    return Nan::ThrowError("mmap: fd (arg[3]) must be an integer (a file descriptor)");
            // Offset and advise are optional

            constexpr void* hinted_address  = nullptr;  // Just making things uber-clear...
            const size_t    size            = Nan::To<int>(info[0]).FromJust(); //ToInteger()->Value();   // ToUint64()->Value();
            const int       protection      = info[1]->IntegerValue();
            const int       flags           = info[2]->ToInteger()->Value();
            const int       fd              = info[3]->ToInteger()->Value();
            const size_t    offset          = info[4]->ToInteger()->Value();   // ToInt64()->Value();
            const int       advise          = info[5]->ToInteger()->Value();

            char* data = static_cast<char*>( mmap( hinted_address, size, protection, flags, fd, offset) );

            if (data == MAP_FAILED) {
                return Nan::ThrowError((std::string("mmap failed, ") + std::to_string(errno)).c_str());
            }
            else {
                if (advise != 0) {
                    auto ret = do_mmap_advice(data, size, advise);
                    if (ret) {
                        return Nan::ThrowError((std::string("madvise() failed, ") + std::to_string(errno)).c_str());
                    }

                //     // Asynchronous read-ahead to minimisze blocking. This
                //     // has worked flawless, but is not necessary, and any
                //     // gains are speculative.
                //     //
                //     // Play with it if you want to.
                //     //
                //     std::async(std::launch::async, [=](){
                //         auto ret = do_mmap_advice(data, size, advise);
                //         if (ret) {
                //             return Nan::ThrowError((std::string("madvise() failed, ") + std::to_string(errno)).c_str());
                //         }
                //         readahead(fd, offset, 1024 * 1024 * 4);
                //     });

                }

                auto map_info = new MMap(data, size);
                Nan::MaybeLocal<Object> buf = Nan::NewBuffer(data, size, do_mmap_cleanup, static_cast<void*>(map_info));
                if (buf.IsEmpty()) {
                    return Nan::ThrowError(std::string("couldn't allocate Node Buffer()").c_str());
                } else {
                    info.GetReturnValue().Set(buf.ToLocalChecked());
                }
            }
}

JS_FN(mmap_advise) {
            Nan::HandleScope();

            if (info.Length() != 2 && info.Length() != 4) {
                return Nan::ThrowError(
                    "advise() takes 2 or 4 arguments: (buffer :Buffer, advise :int) | (buffer :Buffer, offset :int, length :int, advise :int)."
                );
            }
            if (!info[0]->IsObject())    return Nan::ThrowError("advice(): buffer (arg[0]) must be a Buffer");
            if (!info[1]->IsNumber())    return Nan::ThrowError("advice(): (arg[1]) must be an integer");

            Local<Object>   buf     = info[0]->ToObject();
            char*           data    = node::Buffer::Data(buf);
            size_t          size    = node::Buffer::Length(buf);
            int ret;

            if (info.Length() == 2) {
                int advise = info[1]->ToInteger()->Value();
                ret = do_mmap_advice(data, size, advise);
            }
            else {
                int offset = info[1]->ToInteger()->Value();
                int length = info[2]->ToInteger()->Value();
                int advise = info[3]->ToInteger()->Value();
                ret = do_mmap_advice(data + offset, length, advise);
            }
            if (ret) {
                return Nan::ThrowError((std::string("madvise() failed, ") + std::to_string(errno)).c_str());
            }

            //Nan::ReturnUndefined();
}

JS_FN(mmap_incore) {
            Nan::HandleScope();

            if (info.Length() != 1) {
                return Nan::ThrowError(
                    "incore() takes 1 argument: (buffer :Buffer) ."
                );
            }

            if (!info[0]->IsObject())    return Nan::ThrowError("advice(): buffer (arg[0]) must be a Buffer");

            Local<Object>   buf     = info[0]->ToObject();
            char*           data    = node::Buffer::Data(buf);
            size_t          size    = node::Buffer::Length(buf);

#ifdef _WIN32
            SYSTEM_INFO sysinfo;
            GetSystemInfo(&sysinfo);
            size_t          page_size = sysinfo.dwPageSize;
#else
            size_t          page_size = sysconf(_SC_PAGESIZE);
#endif

            size_t          needed_bytes = (size+page_size-1) / page_size;
            size_t          pages = size / page_size;

#ifdef __APPLE__
            char*  resultData = (char *)malloc(needed_bytes);
#else
            unsigned char*  resultData = (unsigned char *)malloc(needed_bytes);
#endif

            if (size % page_size > 0) {
                pages++;
            }

            int ret = mincore(data, size, resultData);

            if (ret) {
                free(resultData);
                if (errno == ENOSYS) {
                    return Nan::ThrowError("mincore() not implemented");
                } else {
                    return Nan::ThrowError((std::string("mincore() failed, ") + std::to_string(errno)).c_str());
                }
            }

            // Now we want to check all of the pages
            uint32_t pages_mapped = 0;
            uint32_t pages_unmapped = 0;

            for(size_t i = 0; i < pages; i++) {
                if(!(resultData[i] & 0x1)) {
                    pages_unmapped++;
                } else {
                    pages_mapped++;
                }
            }

            free(resultData);

            v8::Local<v8::Array> arr = Nan::New<v8::Array>(2);
            Nan::Set(arr, 0, Nan::New(pages_unmapped));
            Nan::Set(arr, 1, Nan::New(pages_mapped));
            info.GetReturnValue().Set(arr);
}

JS_FN(mmap_sync_lib_private_) {
            Nan::HandleScope();

            // I barfed at the thought of implementing all variants of info-combos in C++, so
            // the arg-shuffling and checking is done in a ES wrapper function - see "mmap-io.ls"
            if (info.Length() != 5) {
                return Nan::ThrowError(
                    "sync() takes 5 arguments: (buffer :Buffer, offset :int, length :int, do_blocking_sync :bool, invalidate_pages_and_signal_refresh_to_consumers :bool)."
                );
            }

            if (!info[0]->IsObject())    return Nan::ThrowError("sync(): buffer (arg[0]) must be a Buffer");

            Local<Object>   buf             = info[0]->ToObject();
            char*           data            = node::Buffer::Data(buf);

            int             offset          = info[1]->ToInteger()->Value();
            size_t          length          = info[2]->ToInteger()->Value();
            bool            blocking_sync   = info[3]->ToBoolean()->Value();
            bool            invalidate      = info[4]->ToBoolean()->Value();
            int             flags           = ( (blocking_sync ? MS_SYNC : MS_ASYNC) | (invalidate ? MS_INVALIDATE : 0) );

            int ret = msync(data + offset, length, flags);

            if (ret) {
                return Nan::ThrowError((std::string("msync() failed, ") + std::to_string(errno)).c_str());
            }
            //Nan::ReturnUndefined();
}

NAN_MODULE_INIT(Init) {
            auto exports = target;
            constexpr auto property_attrs = static_cast<PropertyAttribute>(ReadOnly | DontDelete);
            using JsFnType = decltype(mmap_map);

            auto set_int_prop = [&](const char* key, int val) -> void {
                Nan::DefineOwnProperty(exports, Nan::New(key).ToLocalChecked(), Nan::New(val), property_attrs);
            };

            auto set_fn_prop = [&](const char* key, JsFnType fn) -> void {
                Nan::DefineOwnProperty(exports, Nan::New(key).ToLocalChecked(), Nan::New<FunctionTemplate>(fn)->GetFunction(), property_attrs);
            };

            set_int_prop("PROT_READ", PROT_READ);
            set_int_prop("PROT_WRITE", PROT_WRITE);
            set_int_prop("PROT_EXEC", PROT_EXEC);
            set_int_prop("PROT_NONE", PROT_NONE);

            set_int_prop("MAP_SHARED", MAP_SHARED);
            set_int_prop("MAP_PRIVATE", MAP_PRIVATE);

#ifdef MAP_NONBLOCK
            set_int_prop("MAP_NONBLOCK", MAP_NONBLOCK);
#endif

#ifdef MAP_POPULATE
            set_int_prop("MAP_POPULATE", MAP_POPULATE);
#endif

            set_int_prop("MADV_NORMAL", MADV_NORMAL);
            set_int_prop("MADV_RANDOM", MADV_RANDOM);
            set_int_prop("MADV_SEQUENTIAL", MADV_SEQUENTIAL);
            set_int_prop("MADV_WILLNEED", MADV_WILLNEED);
            set_int_prop("MADV_DONTNEED", MADV_DONTNEED);

            //set_int_prop("MS_ASYNC", MS_ASYNC);
            //set_int_prop("MS_SYNC", MS_SYNC);
            //set_int_prop("MS_INVALIDATE", MS_INVALIDATE);

#ifdef _WIN32
            SYSTEM_INFO sysinfo;
            GetSystemInfo(&sysinfo);
            set_int_prop("PAGESIZE", sysinfo.dwPageSize);
#else
            set_int_prop("PAGESIZE", sysconf(_SC_PAGESIZE));
#endif

            set_fn_prop("map", mmap_map);
            set_fn_prop("advise", mmap_advise);
            set_fn_prop("incore", mmap_incore);
            // This one is wrapped by a JS-function and deleted from obj to hide from user
            // *TODO* perhaps call is sync so that we simply can drop in to the sync-name in JS, no deleting
            set_fn_prop("sync_lib_private__", mmap_sync_lib_private_);

}

NODE_MODULE(mmap_io, Init)
<commit_msg>node::Buffer::New allows to map buffers up to 2GB (2GB - 64KB in my test)<commit_after>/*
    Licensed under The MIT License (MIT)
    You will find the full license legal mumbo jumbo in file "LICENSE"

    Copyright (c) 2015 - 2018 Oscar Campbell

    Inspired by Ben Noordhuis module node-mmap - which does the same thing for older node
    versions, sans advise and sync.
*/
#include <nan.h>
#include <errno.h>
#include <string>

#ifdef _WIN32
#include <windows.h>
#include "mman.h"
#else
#include <unistd.h>
#include <sys/mman.h>
#endif

/* #include <future> */

using namespace v8;

// Just a bit more clear as to intent
#define JS_FN(a) NAN_METHOD(a)

// This lib is one of those pieces of code where clarity is better then puny micro opts (in
// comparison to the massive blocking that will occur when the data is first read from disk)
// Since casting `size` to `void*` feels a little "out there" considering that void* may be
// 32b or 64b (or, I dunno, 47b on some quant particle system), we throw this struct in.
struct MMap {
    MMap(char* data, size_t size) : data(data), size(size) {}
    char*   data = nullptr;
    size_t  size = 0;
};

void do_mmap_cleanup(char* data, void* hint) {
            auto map_info = static_cast<MMap*>(hint);
            munmap(data, map_info->size);
            delete map_info;
}

inline int do_mmap_advice(char* addr, size_t length, int advise) {
            return madvise(static_cast<void*>(addr), length, advise);
}

JS_FN(mmap_map) {
            Nan::HandleScope();

            if (info.Length() < 4 && info.Length() > 6) {
                return Nan::ThrowError(
                    "map() takes 4, 5 or 6 arguments: (size :int, protection :int, flags :int, fd :int [, offset :int [, advise :int]])."
                );
            }

            // Try to be a little (motherly) helpful to us poor clueless developers
            if (!info[0]->IsNumber())    return Nan::ThrowError("mmap: size (arg[0]) must be an integer");
            if (!info[1]->IsNumber())    return Nan::ThrowError("mmap: protection_flags (arg[1]) must be an integer");
            if (!info[2]->IsNumber())    return Nan::ThrowError("mmap: flags (arg[2]) must be an integer");
            if (!info[3]->IsNumber())    return Nan::ThrowError("mmap: fd (arg[3]) must be an integer (a file descriptor)");
            // Offset and advise are optional

            constexpr void* hinted_address  = nullptr;  // Just making things uber-clear...
            const size_t    size            = Nan::To<int>(info[0]).FromJust(); //ToInteger()->Value();   // ToUint64()->Value();
            const int       protection      = info[1]->IntegerValue();
            const int       flags           = info[2]->ToInteger()->Value();
            const int       fd              = info[3]->ToInteger()->Value();
            const size_t    offset          = info[4]->ToInteger()->Value();   // ToInt64()->Value();
            const int       advise          = info[5]->ToInteger()->Value();

            char* data = static_cast<char*>( mmap( hinted_address, size, protection, flags, fd, offset) );

            if (data == MAP_FAILED) {
                return Nan::ThrowError((std::string("mmap failed, ") + std::to_string(errno)).c_str());
            }
            else {
                if (advise != 0) {
                    auto ret = do_mmap_advice(data, size, advise);
                    if (ret) {
                        return Nan::ThrowError((std::string("madvise() failed, ") + std::to_string(errno)).c_str());
                    }

                //     // Asynchronous read-ahead to minimisze blocking. This
                //     // has worked flawless, but is not necessary, and any
                //     // gains are speculative.
                //     //
                //     // Play with it if you want to.
                //     //
                //     std::async(std::launch::async, [=](){
                //         auto ret = do_mmap_advice(data, size, advise);
                //         if (ret) {
                //             return Nan::ThrowError((std::string("madvise() failed, ") + std::to_string(errno)).c_str());
                //         }
                //         readahead(fd, offset, 1024 * 1024 * 4);
                //     });

                }

                auto map_info = new MMap(data, size);
				Nan::MaybeLocal<Object> buf = node::Buffer::New(
					v8::Isolate::GetCurrent(), data, size, do_mmap_cleanup, static_cast<void*>(map_info));
                if (buf.IsEmpty()) {
                    return Nan::ThrowError(std::string("couldn't allocate Node Buffer()").c_str());
                } else {
                    info.GetReturnValue().Set(buf.ToLocalChecked());
                }
            }
}

JS_FN(mmap_advise) {
            Nan::HandleScope();

            if (info.Length() != 2 && info.Length() != 4) {
                return Nan::ThrowError(
                    "advise() takes 2 or 4 arguments: (buffer :Buffer, advise :int) | (buffer :Buffer, offset :int, length :int, advise :int)."
                );
            }
            if (!info[0]->IsObject())    return Nan::ThrowError("advice(): buffer (arg[0]) must be a Buffer");
            if (!info[1]->IsNumber())    return Nan::ThrowError("advice(): (arg[1]) must be an integer");

            Local<Object>   buf     = info[0]->ToObject();
            char*           data    = node::Buffer::Data(buf);
            size_t          size    = node::Buffer::Length(buf);
            int ret;

            if (info.Length() == 2) {
                int advise = info[1]->ToInteger()->Value();
                ret = do_mmap_advice(data, size, advise);
            }
            else {
                int offset = info[1]->ToInteger()->Value();
                int length = info[2]->ToInteger()->Value();
                int advise = info[3]->ToInteger()->Value();
                ret = do_mmap_advice(data + offset, length, advise);
            }
            if (ret) {
                return Nan::ThrowError((std::string("madvise() failed, ") + std::to_string(errno)).c_str());
            }

            //Nan::ReturnUndefined();
}

JS_FN(mmap_incore) {
            Nan::HandleScope();

            if (info.Length() != 1) {
                return Nan::ThrowError(
                    "incore() takes 1 argument: (buffer :Buffer) ."
                );
            }

            if (!info[0]->IsObject())    return Nan::ThrowError("advice(): buffer (arg[0]) must be a Buffer");

            Local<Object>   buf     = info[0]->ToObject();
            char*           data    = node::Buffer::Data(buf);
            size_t          size    = node::Buffer::Length(buf);

#ifdef _WIN32
            SYSTEM_INFO sysinfo;
            GetSystemInfo(&sysinfo);
            size_t          page_size = sysinfo.dwPageSize;
#else
            size_t          page_size = sysconf(_SC_PAGESIZE);
#endif

            size_t          needed_bytes = (size+page_size-1) / page_size;
            size_t          pages = size / page_size;

#ifdef __APPLE__
            char*  resultData = (char *)malloc(needed_bytes);
#else
            unsigned char*  resultData = (unsigned char *)malloc(needed_bytes);
#endif

            if (size % page_size > 0) {
                pages++;
            }

            int ret = mincore(data, size, resultData);

            if (ret) {
                free(resultData);
                if (errno == ENOSYS) {
                    return Nan::ThrowError("mincore() not implemented");
                } else {
                    return Nan::ThrowError((std::string("mincore() failed, ") + std::to_string(errno)).c_str());
                }
            }

            // Now we want to check all of the pages
            uint32_t pages_mapped = 0;
            uint32_t pages_unmapped = 0;

            for(size_t i = 0; i < pages; i++) {
                if(!(resultData[i] & 0x1)) {
                    pages_unmapped++;
                } else {
                    pages_mapped++;
                }
            }

            free(resultData);

            v8::Local<v8::Array> arr = Nan::New<v8::Array>(2);
            Nan::Set(arr, 0, Nan::New(pages_unmapped));
            Nan::Set(arr, 1, Nan::New(pages_mapped));
            info.GetReturnValue().Set(arr);
}

JS_FN(mmap_sync_lib_private_) {
            Nan::HandleScope();

            // I barfed at the thought of implementing all variants of info-combos in C++, so
            // the arg-shuffling and checking is done in a ES wrapper function - see "mmap-io.ls"
            if (info.Length() != 5) {
                return Nan::ThrowError(
                    "sync() takes 5 arguments: (buffer :Buffer, offset :int, length :int, do_blocking_sync :bool, invalidate_pages_and_signal_refresh_to_consumers :bool)."
                );
            }

            if (!info[0]->IsObject())    return Nan::ThrowError("sync(): buffer (arg[0]) must be a Buffer");

            Local<Object>   buf             = info[0]->ToObject();
            char*           data            = node::Buffer::Data(buf);

            int             offset          = info[1]->ToInteger()->Value();
            size_t          length          = info[2]->ToInteger()->Value();
            bool            blocking_sync   = info[3]->ToBoolean()->Value();
            bool            invalidate      = info[4]->ToBoolean()->Value();
            int             flags           = ( (blocking_sync ? MS_SYNC : MS_ASYNC) | (invalidate ? MS_INVALIDATE : 0) );

            int ret = msync(data + offset, length, flags);

            if (ret) {
                return Nan::ThrowError((std::string("msync() failed, ") + std::to_string(errno)).c_str());
            }
            //Nan::ReturnUndefined();
}

NAN_MODULE_INIT(Init) {
            auto exports = target;
            constexpr auto property_attrs = static_cast<PropertyAttribute>(ReadOnly | DontDelete);
            using JsFnType = decltype(mmap_map);

            auto set_int_prop = [&](const char* key, int val) -> void {
                Nan::DefineOwnProperty(exports, Nan::New(key).ToLocalChecked(), Nan::New(val), property_attrs);
            };

            auto set_fn_prop = [&](const char* key, JsFnType fn) -> void {
                Nan::DefineOwnProperty(exports, Nan::New(key).ToLocalChecked(), Nan::New<FunctionTemplate>(fn)->GetFunction(), property_attrs);
            };

            set_int_prop("PROT_READ", PROT_READ);
            set_int_prop("PROT_WRITE", PROT_WRITE);
            set_int_prop("PROT_EXEC", PROT_EXEC);
            set_int_prop("PROT_NONE", PROT_NONE);

            set_int_prop("MAP_SHARED", MAP_SHARED);
            set_int_prop("MAP_PRIVATE", MAP_PRIVATE);

#ifdef MAP_NONBLOCK
            set_int_prop("MAP_NONBLOCK", MAP_NONBLOCK);
#endif

#ifdef MAP_POPULATE
            set_int_prop("MAP_POPULATE", MAP_POPULATE);
#endif

            set_int_prop("MADV_NORMAL", MADV_NORMAL);
            set_int_prop("MADV_RANDOM", MADV_RANDOM);
            set_int_prop("MADV_SEQUENTIAL", MADV_SEQUENTIAL);
            set_int_prop("MADV_WILLNEED", MADV_WILLNEED);
            set_int_prop("MADV_DONTNEED", MADV_DONTNEED);

            //set_int_prop("MS_ASYNC", MS_ASYNC);
            //set_int_prop("MS_SYNC", MS_SYNC);
            //set_int_prop("MS_INVALIDATE", MS_INVALIDATE);

#ifdef _WIN32
            SYSTEM_INFO sysinfo;
            GetSystemInfo(&sysinfo);
            set_int_prop("PAGESIZE", sysinfo.dwPageSize);
#else
            set_int_prop("PAGESIZE", sysconf(_SC_PAGESIZE));
#endif

            set_fn_prop("map", mmap_map);
            set_fn_prop("advise", mmap_advise);
            set_fn_prop("incore", mmap_incore);
            // This one is wrapped by a JS-function and deleted from obj to hide from user
            // *TODO* perhaps call is sync so that we simply can drop in to the sync-name in JS, no deleting
            set_fn_prop("sync_lib_private__", mmap_sync_lib_private_);

}

NODE_MODULE(mmap_io, Init)
<|endoftext|>


<commit_before>#include "symbolic_planning_utils/moveGroupInterface.h"

namespace symbolic_planning_utils
{
//MoveGroupInterface* MoveGroupInterface::instance = new MoveGroupInterface();
MoveGroupInterface* MoveGroupInterface::instance_ = NULL;

MoveGroupInterface::MoveGroupInterface()
{
	right_arm_group_ = new moveit::planning_interface::MoveGroup("right_arm");
	left_arm_group_ = new moveit::planning_interface::MoveGroup("left_arm");
//    arms_group_ = new moveit::planning_interface::MoveGroup("arms");
    head_group_ = new moveit::planning_interface::MoveGroup("head");
    torso_group_ = new moveit::planning_interface::MoveGroup("torso");
}

MoveGroupInterface::MoveGroupInterface(const MoveGroupInterface* mgi)
{
	MoveGroupInterface::instance_ = mgi->instance_;
}

MoveGroupInterface* MoveGroupInterface::operator= (const MoveGroupInterface* mgi)
{
	if (this != mgi)
	{
		MoveGroupInterface::instance_ = mgi->instance_;
	}
	return this;
}

MoveGroupInterface::~MoveGroupInterface()
{
}

MoveGroupInterface* MoveGroupInterface::getInstance()
{
	if (MoveGroupInterface::instance_ == NULL)
		MoveGroupInterface::instance_ = new MoveGroupInterface();
    return MoveGroupInterface::instance_;
}

moveit::planning_interface::MoveGroup* MoveGroupInterface::getRightArmGroup()
{
	return right_arm_group_;
}

moveit::planning_interface::MoveGroup* MoveGroupInterface::getLeftArmGroup()
{
	return left_arm_group_;
}

moveit::planning_interface::MoveGroup* MoveGroupInterface::getArmsGroup()
{
	return arms_group_;
}

moveit::planning_interface::MoveGroup* MoveGroupInterface::getHeadGroup()
{
	return head_group_;
}

moveit::planning_interface::MoveGroup* MoveGroupInterface::getTorsoGroup()
{
	return torso_group_;
}

};
<commit_msg>added arms group<commit_after>#include "symbolic_planning_utils/moveGroupInterface.h"

namespace symbolic_planning_utils
{
//MoveGroupInterface* MoveGroupInterface::instance = new MoveGroupInterface();
MoveGroupInterface* MoveGroupInterface::instance_ = NULL;

MoveGroupInterface::MoveGroupInterface()
{
	right_arm_group_ = new moveit::planning_interface::MoveGroup("right_arm");
	left_arm_group_ = new moveit::planning_interface::MoveGroup("left_arm");
    arms_group_ = new moveit::planning_interface::MoveGroup("arms");
    head_group_ = new moveit::planning_interface::MoveGroup("head");
    torso_group_ = new moveit::planning_interface::MoveGroup("torso");
}

MoveGroupInterface::MoveGroupInterface(const MoveGroupInterface* mgi)
{
	MoveGroupInterface::instance_ = mgi->instance_;
}

MoveGroupInterface* MoveGroupInterface::operator= (const MoveGroupInterface* mgi)
{
	if (this != mgi)
	{
		MoveGroupInterface::instance_ = mgi->instance_;
	}
	return this;
}

MoveGroupInterface::~MoveGroupInterface()
{
}

MoveGroupInterface* MoveGroupInterface::getInstance()
{
	if (MoveGroupInterface::instance_ == NULL)
		MoveGroupInterface::instance_ = new MoveGroupInterface();
    return MoveGroupInterface::instance_;
}

moveit::planning_interface::MoveGroup* MoveGroupInterface::getRightArmGroup()
{
	return right_arm_group_;
}

moveit::planning_interface::MoveGroup* MoveGroupInterface::getLeftArmGroup()
{
	return left_arm_group_;
}

moveit::planning_interface::MoveGroup* MoveGroupInterface::getArmsGroup()
{
	return arms_group_;
}

moveit::planning_interface::MoveGroup* MoveGroupInterface::getHeadGroup()
{
	return head_group_;
}

moveit::planning_interface::MoveGroup* MoveGroupInterface::getTorsoGroup()
{
	return torso_group_;
}

};
<|endoftext|>


<commit_before>#include "parser.h"

Parser::Parser()
{
    clear();
}

Parser::~Parser()
{
    clear();
}

void Parser::clear()
{
    m_index = -1;
    m_scope = 0;
    m_indentation = Unset;
    m_source = 0;
}

void Parser::parse(SourceBuffer* source)
{
    clear();
    m_source = source;

    while (m_index < m_source->tokenCount() - 1) {
        advance(1);
        const Token& tok = current();

        switch (tok.type) {
        case Comment:
            continue;
        case Whitespace:
            parseWhitespace(tok); break;
        case Tab:
            parseTab(tok); break;
        case Newline:
        {
            const Token& next = look(1);
            switch (next.type) {
            case Whitespace:
                parseWhitespace(next); break;
            case Tab:
                parseTab(next); break;
            default: break;
            }
            break;
        }
        default:
            error(tok, "unexpected token when parsing translation unit"); break;
        }
    }
}

void Parser::newline()
{
}

void Parser::advance(int i)
{
    m_index += i;
}

Token Parser::current() const
{
    Q_ASSERT(m_index >= 0);
    Q_ASSERT(m_index < m_source->tokenCount());
    return look(0);
}

Token Parser::look(int i) const
{
    int index = m_index + i;
    Q_ASSERT(m_index >= 0);
    if (index >= m_source->tokenCount())
        return Token();
    return m_source->tokenAt(index);
}

void Parser::error(const Token& tok, const QString& str) const
{
    QString location = m_source->name()
        + ":" + QString::number(tok.start.line)
        + ":" + QString::number(tok.start.column)
        + " error: " + str;
    QString context = m_source->lineForToken(tok);
    QString caret(tok.start.column - 1, ' ');
    context.replace('\t', ' ');
    caret.replace('\t', ' ');
    caret += QString(tok.end.column - tok.start.column + 1, '^');

    // TODO: Print in color to the output
    QTextStream out(stderr);
    out << location << '\n' << context << '\n' << caret << '\n';
}

void Parser::parseWhitespace(const Token& tok)
{
    if (m_indentation == Unset)
        m_indentation = Spaces;
    else if (m_indentation == Tabs)
        error(tok, "unexpected ' ' when already using '\\t' for indentation");
}

void Parser::parseTab(const Token& tok)
{
    if (m_indentation == Unset)
        m_indentation = Tabs;
    else if (m_indentation == Spaces)
        error(tok, "unexpected '\\t' when already using ' ' for indentation");
}
<commit_msg>Add nice colored error messages much like clang :)<commit_after>#include "parser.h"

Parser::Parser()
{
    clear();
}

Parser::~Parser()
{
    clear();
}

void Parser::clear()
{
    m_index = -1;
    m_scope = 0;
    m_indentation = Unset;
    m_source = 0;
}

void Parser::parse(SourceBuffer* source)
{
    clear();
    m_source = source;

    while (m_index < m_source->tokenCount() - 1) {
        advance(1);
        const Token& tok = current();

        switch (tok.type) {
        case Comment:
            continue;
        case Whitespace:
            parseWhitespace(tok); break;
        case Tab:
            parseTab(tok); break;
        case Newline:
        {
            const Token& next = look(1);
            switch (next.type) {
            case Whitespace:
                parseWhitespace(next); break;
            case Tab:
                parseTab(next); break;
            default: break;
            }
            break;
        }
        default:
            error(tok, "unexpected token when parsing translation unit"); break;
        }
    }
}

void Parser::newline()
{
}

void Parser::advance(int i)
{
    m_index += i;
}

Token Parser::current() const
{
    Q_ASSERT(m_index >= 0);
    Q_ASSERT(m_index < m_source->tokenCount());
    return look(0);
}

Token Parser::look(int i) const
{
    int index = m_index + i;
    Q_ASSERT(m_index >= 0);
    if (index >= m_source->tokenCount())
        return Token();
    return m_source->tokenAt(index);
}

void Parser::error(const Token& tok, const QString& str) const
{
    QString location = m_source->name()
        + ":" + QString::number(tok.start.line)
        + ":" + QString::number(tok.start.column)
#ifdef Q_OS_UNIX
        + "\033[91m error\033[39m: " + str;
#else
        + " error: " + str;
#endif
    QString context = m_source->lineForToken(tok);
    QString caret(tok.start.column - 1, ' ');
    context.replace('\t', ' ');
    caret.replace('\t', ' ');
#ifdef Q_OS_UNIX
    caret += "\033[92m" + QString(tok.end.column - tok.start.column + 1, '^') + "\033[39m";
#else
    caret += QString(tok.end.column - tok.start.column + 1, '^');
#endif

    QTextStream out(stderr);
    out << location << '\n' << context << '\n' << caret << '\n';
}

void Parser::parseWhitespace(const Token& tok)
{
    if (m_indentation == Unset)
        m_indentation = Spaces;
    else if (m_indentation == Tabs)
        error(tok, "unexpected ' ' when already using '\\t' for indentation");
}

void Parser::parseTab(const Token& tok)
{
    if (m_indentation == Unset)
        m_indentation = Tabs;
    else if (m_indentation == Spaces)
        error(tok, "unexpected '\\t' when already using ' ' for indentation");
}
<|endoftext|>


<commit_before>#include "./parser.hpp"

using namespace json;

std::regex Parser::startBrace = std::regex 	 ("^(?:\\s*)(\\{)");
std::regex Parser::startBracket = std::regex     ("^(?:\\s*)(\\[)");
std::regex Parser::keyDef = std::regex           ("^(?:\\s*)(?:\")([^,]+?)(?:\")(?:\\s*):");
std::regex Parser::finalQuote = std::regex       ("^(?:\\s*)(?:\")(.*?)(?:\")(?:\\s*)(,)?");
std::regex Parser::finalNumberInt = std::regex   ("^(?:\\s*)((?:\\+|\\-)?\\d+)(?:\\s*)(,)?");
std::regex Parser::finalNumberFloat = std::regex ("^(?:\\s*)((?:\\+|\\-)?(?:\\d+)?(?:(?:(?:\\.\\d+)?e(?:\\+|\\-)?\\d+)|(?:\\.\\d+)))(?:\\s*)(,)?");
std::regex Parser::finalBoolean = std::regex     ("^(?:\\s*)(true|false)(?:\\s*)(,)?");
std::regex Parser::nextBrace = std::regex 	 ("^(?:\\s*)(\\})(?:\\s*)(,)?");
std::regex Parser::nextBracket = std::regex      ("^(?:\\s*)(\\])(?:\\s*)(,)?");

int Parser::parseFile (std::string fileName, JsonTree& tree, bool verbs ) {
  verbose = verbs;
  errors.resize (0);
  warnings.resize (0);
  int returnValue = OK;
  if (openFile(fileName)) {
    std::stringstream buffer;
    buffer << getFile().rdbuf();
    std::string fileContent = buffer.str();
    ObjectNameFlag result = parseExpectingElement (fileContent, "");
    file.close();
    tree.setTop (result.element);
    if (result.flag == EMPTY)
      return EMPTY_FILE;
    if (hasWarnings())
      returnValue += WARNINGS;
    if (hasErrors()) {
      returnValue += ERRORS;
      return returnValue & (INT_MAX - 1); // removes the OK flag
    }
  } else {
    return CANT_OPEN_FILE;
  }
  return returnValue;
}

int Parser::parseString (std::string content, JsonTree& tree, bool verbs ) {
  verbose = verbs;
  errors.resize (0);
  warnings.resize (0);
  int returnValue = OK;
    ObjectNameFlag result = parseExpectingElement (content, "");
    tree.setTop (result.element);
    if (result.flag == EMPTY)
      return EMPTY_FILE;
    if (hasWarnings())
      returnValue += WARNINGS;
    if (hasErrors()) {
      returnValue += ERRORS;
      return returnValue & (INT_MAX - 1); // removes the OK flag
    }
  return returnValue;
}

Parser::Parser () :
  errors (0),
  warnings (0)
  {}

bool Parser::openFile (std::string fileName) {
  file.open(fileName, std::ifstream::in);
  if (file.is_open())
    return true;
  else
    return false;
}

bool Parser::hasComma (std::string buffer) {
  return (buffer.size() > 0);
}

Parser::ObjectNameFlag Parser::parseFinal (std::string& content, std::smatch& matcher, ObjectFinal* obj) {
  obj->replaceValue(matcher[1]);
  content = content.substr(matcher[0].length(), content.size());
  return {obj, "", hasComma(matcher[2])};
}

Parser::ObjectNameFlag Parser::parseContainer (std::string& content, std::smatch& matcher,
                            std::regex& endSymbol, std::function<ObjectNameFlag(std::string&, std::string)> parseFunction, ObjectContainer* obj, std::string path)
{
  content = content.substr(matcher[0].length(), content.size());
  ObjectNameFlag aux;
  int flag = REGULAR_ELEMENT;
  do {
    aux = parseFunction (content, path);
    if (aux.flag == EMPTY) {
      evaluateFlag(EMPTY, path, aux.key);
      break;
    }
    if (!obj->insert (aux.key, aux.element)) {
      evaluateFlag(INVALID_KEY, path, aux.key);
      break;
    }
  } while (!std::regex_search (content, matcher, endSymbol) && aux.flag == REGULAR_ELEMENT);
  std::regex_search (content, matcher, endSymbol);
  if (aux.flag == REGULAR_ELEMENT) {
    flag = EXPECTED_MORE;
    evaluateFlag(flag, path, aux.key);
  } else if (matcher[0].length() > 0) { 													// has matched
    content = content.substr(matcher[0].length(), content.size());
    flag = hasComma(matcher[2]);
  } else {
    flag = NO_CLOSED;
    evaluateFlag(flag, path, aux.key);
  }
  return {obj, "", flag};
}

void Parser::evaluateFlag (int flag, std::string path, std::string finalElement) {
  path.append(".").append(finalElement);
  if (flag < CONTROL_WARNING) {
    errors.push_back ({path, flag});
    if (verbose)
      std::cerr << "Error";
  } else {
    warnings.push_back ({path, flag});
    if (verbose)
      std::cerr << "Warning";
  }
  if (verbose)
    std::cerr << " parsing JSON: " << reverseflag[flag] << " in path: " << path << std::endl;
}

Parser::ObjectNameFlag Parser::parseExpectingKeyDef (std::string &content, std::string path) {
  std::smatch matcher;
  ObjectNameFlag Obj;
  if (std::regex_search (content, matcher, keyDef)) {
      std::string key = matcher[1];
      content = content.substr(matcher[0].length(), content.size());
      path.append(".").append(key);
      ObjectNameFlag aux = parseExpectingElement (content, path);
      return {aux.element, key, aux.flag};
  } else {
    return {nullptr, "", EMPTY};
  }
}

Parser::ObjectNameFlag Parser::parseExpectingElement (std::string& content, std::string path) {
  std::smatch matcher;
  ObjectNameFlag Obj;
  if (std::regex_search(content, matcher, finalQuote))
    return parseFinal (content, matcher, new ObjectFinalString());
  else if (std::regex_search(content, matcher, finalBoolean))
    return parseFinal (content, matcher, new ObjectFinalBool());
  else if (std::regex_search(content, matcher, finalNumberFloat))
    return parseFinal (content, matcher, new ObjectFinalNumberFloat());
  else if (std::regex_search(content, matcher, finalNumberInt))
    return parseFinal (content, matcher, new ObjectFinalNumberInt());
  else if (std::regex_search (content, matcher, startBrace))
    return parseContainer (content, matcher, nextBrace,
           [&](std::string& a, std::string b) { return parseExpectingKeyDef(a, b); },
    new ObjectMap (), path);
  else if (std::regex_search (content, matcher, startBracket))
    return parseContainer (content, matcher, nextBracket,
           [&](std::string& a, std::string b) { return parseExpectingElement(a, b); },
    new ObjectVector (), path);
  return {nullptr, "", EMPTY};
}

int Parser::saveFile (std::string fileName, JsonTree& tree, bool uglify) {
  std::ofstream file;
  file.open (fileName);
  if (!file.is_open())
    return CANT_OPEN_FILE;
  file << tree.toText(uglify);
  file.close ();
  return OK;
}
<commit_msg>Improve parser performance<commit_after>#include "./parser.hpp"

using namespace json;

std::regex Parser::startBrace = std::regex 	 ("^(?:\\s*)(\\{)");
std::regex Parser::startBracket = std::regex     ("^(?:\\s*)(\\[)");
std::regex Parser::keyDef = std::regex           ("^(?:\\s*)(?:\")([^,]+?)(?:\")(?:\\s*):");
std::regex Parser::finalQuote = std::regex       ("^(?:\\s*)(?:\")(.*?)(?:\")(?:\\s*)(,)?");
std::regex Parser::finalNumberInt = std::regex   ("^(?:\\s*)((?:\\+|\\-)?\\d+)(?:\\s*)(,)?");
std::regex Parser::finalNumberFloat = std::regex ("^(?:\\s*)((?:\\+|\\-)?(?:\\d+)?(?:(?:(?:\\.\\d+)?e(?:\\+|\\-)?\\d+)|(?:\\.\\d+)))(?:\\s*)(,)?");
std::regex Parser::finalBoolean = std::regex     ("^(?:\\s*)(true|false)(?:\\s*)(,)?");
std::regex Parser::nextBrace = std::regex 	 ("^(?:\\s*)(\\})(?:\\s*)(,)?");
std::regex Parser::nextBracket = std::regex      ("^(?:\\s*)(\\])(?:\\s*)(,)?");

int Parser::parseFile (std::string fileName, JsonTree& tree, bool verbs ) {
  verbose = verbs;
  errors.resize (0);
  warnings.resize (0);
  int returnValue = OK;
  if (openFile(fileName)) {
    std::stringstream buffer;
    buffer << getFile().rdbuf();
    std::string fileContent = buffer.str();
    ObjectNameFlag result = parseExpectingElement (fileContent, "");
    file.close();
    tree.setTop (result.element);
    if (result.flag == EMPTY)
      return EMPTY_FILE;
    if (hasWarnings())
      returnValue += WARNINGS;
    if (hasErrors()) {
      returnValue += ERRORS;
      return returnValue & (INT_MAX - 1); // removes the OK flag
    }
  } else {
    return CANT_OPEN_FILE;
  }
  return returnValue;
}

int Parser::parseString (std::string content, JsonTree& tree, bool verbs ) {
  verbose = verbs;
  errors.resize (0);
  warnings.resize (0);
  int returnValue = OK;
    ObjectNameFlag result = parseExpectingElement (content, "");
    tree.setTop (result.element);
    if (result.flag == EMPTY)
      return EMPTY_FILE;
    if (hasWarnings())
      returnValue += WARNINGS;
    if (hasErrors()) {
      returnValue += ERRORS;
      return returnValue & (INT_MAX - 1); // removes the OK flag
    }
  return returnValue;
}

Parser::Parser () :
  errors (0),
  warnings (0)
  {}

bool Parser::openFile (std::string fileName) {
  file.open(fileName, std::ifstream::in);
  if (file.is_open())
    return true;
  else
    return false;
}

bool Parser::hasComma (std::string buffer) {
  return (buffer.size() > 0);
}

Parser::ObjectNameFlag Parser::parseFinal (std::string& content, std::smatch& matcher, ObjectFinal* obj) {
  obj->replaceValue(matcher[1]);
  content.erase(0, matcher[0].length());
  return {obj, "", hasComma(matcher[2])};
}

Parser::ObjectNameFlag Parser::parseContainer (std::string& content, std::smatch& matcher,
                            std::regex& endSymbol, std::function<ObjectNameFlag(std::string&, std::string)> parseFunction, ObjectContainer* obj, std::string path)
{
  content.erase(0, matcher[0].length());
  ObjectNameFlag aux;
  int flag = REGULAR_ELEMENT;
  do {
    aux = parseFunction (content, path);
    if (aux.flag == EMPTY) {
      evaluateFlag(EMPTY, path, aux.key);
      break;
    }
    if (!obj->insert (aux.key, aux.element)) {
      evaluateFlag(INVALID_KEY, path, aux.key);
      break;
    }
  } while (!std::regex_search (content, matcher, endSymbol) && aux.flag == REGULAR_ELEMENT);
  std::regex_search (content, matcher, endSymbol);
  if (aux.flag == REGULAR_ELEMENT) {
    flag = EXPECTED_MORE;
    evaluateFlag(flag, path, aux.key);
  } else if (matcher[0].length() > 0) { 													// has matched
    content.erase(0, matcher[0].length());
    flag = hasComma(matcher[2]);
  } else {
    flag = NO_CLOSED;
    evaluateFlag(flag, path, aux.key);
  }
  return {obj, "", flag};
}

void Parser::evaluateFlag (int flag, std::string path, std::string finalElement) {
  path.append(".").append(finalElement);
  if (flag < CONTROL_WARNING) {
    errors.push_back ({path, flag});
    if (verbose)
      std::cerr << "Error";
  } else {
    warnings.push_back ({path, flag});
    if (verbose)
      std::cerr << "Warning";
  }
  if (verbose)
    std::cerr << " parsing JSON: " << reverseflag[flag] << " in path: " << path << std::endl;
}

Parser::ObjectNameFlag Parser::parseExpectingKeyDef (std::string &content, std::string path) {
  std::smatch matcher;
  ObjectNameFlag Obj;
  if (std::regex_search (content, matcher, keyDef)) {
      std::string key = matcher[1];
      content.erase(0, matcher[0].length());
      path.append(".").append(key);
      ObjectNameFlag aux = parseExpectingElement (content, path);
      return {aux.element, key, aux.flag};
  } else {
    return {nullptr, "", EMPTY};
  }
}

Parser::ObjectNameFlag Parser::parseExpectingElement (std::string& content, std::string path) {
  std::smatch matcher;
  ObjectNameFlag Obj;
  if (std::regex_search(content, matcher, finalQuote))
    return parseFinal (content, matcher, new ObjectFinalString());
  else if (std::regex_search(content, matcher, finalBoolean))
    return parseFinal (content, matcher, new ObjectFinalBool());
  else if (std::regex_search(content, matcher, finalNumberFloat))
    return parseFinal (content, matcher, new ObjectFinalNumberFloat());
  else if (std::regex_search(content, matcher, finalNumberInt))
    return parseFinal (content, matcher, new ObjectFinalNumberInt());
  else if (std::regex_search (content, matcher, startBrace))
    return parseContainer (content, matcher, nextBrace,
           [&](std::string& a, std::string b) { return parseExpectingKeyDef(a, b); },
    new ObjectMap (), path);
  else if (std::regex_search (content, matcher, startBracket))
    return parseContainer (content, matcher, nextBracket,
           [&](std::string& a, std::string b) { return parseExpectingElement(a, b); },
    new ObjectVector (), path);
  return {nullptr, "", EMPTY};
}

int Parser::saveFile (std::string fileName, JsonTree& tree, bool uglify) {
  std::ofstream file;
  file.open (fileName);
  if (!file.is_open())
    return CANT_OPEN_FILE;
  file << tree.toText(uglify);
  file.close ();
  return OK;
}
<|endoftext|>


<commit_before>#include "config.h"
#include "ylib.h"
#include "ylocale.h"
#include "yxapp.h"
#include "yxtray.h"
#include "base.h"
#include "debug.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "yprefs.h"

extern void logEvent(const XEvent &xev);

char const *ApplicationName = "icewmtray";

#include "yconfig.h"

#ifdef CONFIG_TASKBAR
YColor *taskBarBg;

XSV(const char *, clrDefaultTaskBar,            "rgb:C0/C0/C0")

cfoption icewmbg_prefs[] = {
    OSV("ColorDefaultTaskBar",                  &clrDefaultTaskBar,             "Background of the taskbar"),
    OK0()
};
#endif

class SysTray: public YWindow, public YXTrayNotifier {
public:
    SysTray();
    bool checkMessageEvent(const XClientMessageEvent &message);
    void requestDock();

    void handleUnmap(const XUnmapEvent &) {
        MSG(("hide"));
        if (visible())
            hide();
    }
    void trayChanged();
private:
    Atom icewm_internal_tray;
    Atom _NET_SYSTEM_TRAY_OPCODE;
    YXTray *fTray2;
};

class SysTrayApp: public YXApplication {
public:
    SysTrayApp(int *argc, char ***argv, const char *displayName = 0);
    ~SysTrayApp();

    bool filterEvent(const XEvent &xev);
private:
    SysTray *tray;
};

SysTrayApp::SysTrayApp(int *argc, char ***argv, const char *displayName):
    YXApplication(argc, argv, displayName)
{
    desktop->setStyle(YWindow::wsDesktopAware);
#ifdef CONFIG_TASKBAR
    if (taskBarBg == 0)
        taskBarBg = new YColor(clrDefaultTaskBar);
#endif
    tray = new SysTray();
}

SysTrayApp::~SysTrayApp() {

}

bool SysTrayApp::filterEvent(const XEvent &xev) {
#ifdef DEBUG
    logEvent(xev);
#endif
    if (xev.type == ClientMessage) {
        tray->checkMessageEvent(xev.xclient);
        return false;
    } else if (xev.type == MappingNotify) {
            MSG(("tray mapping1"));
        if (xev.xmapping.window == tray->handle()) {
            MSG(("tray mapping"));
        }
    }
    return false;
}

SysTray::SysTray(): YWindow(0) {
    desktop->setStyle(YWindow::wsDesktopAware);

    char trayatom[64];
    sprintf(trayatom, "_NET_SYSTEM_TRAY_S%d", xapp->screen());
    fTray2 = new YXTray(this, false, trayatom, this);

    char trayatom2[64];
    sprintf(trayatom2, "_ICEWM_INTTRAY_S%d", xapp->screen());
    icewm_internal_tray =
        XInternAtom(xapp->display(), trayatom2, False);

    _NET_SYSTEM_TRAY_OPCODE =
        XInternAtom(xapp->display(),
                    "_NET_SYSTEM_TRAY_OPCODE",
                    False);

    fTray2->relayout();
    setSize(fTray2->width(),
            fTray2->height());
    fTray2->show();
    requestDock();
}

void SysTray::trayChanged() {
    fTray2->relayout();
    setSize(fTray2->width(),
            fTray2->height());
}

void SysTray::requestDock() {
    Window w = XGetSelectionOwner(xapp->display(), icewm_internal_tray);

    if (w && w != handle()) {
        XClientMessageEvent xev;
        memset(&xev, 0, sizeof(xev));

        xev.type = ClientMessage;
        xev.window = w;
        xev.message_type = _NET_SYSTEM_TRAY_OPCODE;
        xev.format = 32;
        xev.data.l[0] = CurrentTime;
        xev.data.l[1] = SYSTEM_TRAY_REQUEST_DOCK;
        xev.data.l[2] = handle(); //fTray2->handle();

        XSendEvent(xapp->display(), w, False, StructureNotifyMask, (XEvent *) &xev);
    }
}

bool SysTray::checkMessageEvent(const XClientMessageEvent &message) {
    if (message.message_type == icewm_internal_tray) {
        MSG(("requestDock"));
        requestDock();
    }
    return true;
}

int main(int argc, char **argv) {
    YLocale locale;

    SysTrayApp stapp(&argc, &argv);

#ifdef CONFIG_TASKBAR
#ifndef NO_CONFIGURE
    {
        cfoption theme_prefs[] = {
            OSV("Theme", &themeName, "Theme name"),
            OK0()
        };

        app->loadConfig(theme_prefs, "preferences");
        app->loadConfig(theme_prefs, "theme");
    }
    YApplication::loadConfig(icewmbg_prefs, "preferences");
    if (themeName != 0) {
        MSG(("themeName=%s", themeName));

        char *theme = strJoin("themes/", themeName, NULL);
        YApplication::loadConfig(icewmbg_prefs, theme);
        delete [] theme;
    }
    YApplication::loadConfig(icewmbg_prefs, "prefoverride");
#endif
#endif

    return app->mainLoop();
}
<commit_msg>handle termination cleanly<commit_after>#include "config.h"
#include "ylib.h"
#include "ylocale.h"
#include "yxapp.h"
#include "yxtray.h"
#include "base.h"
#include "debug.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "yprefs.h"

extern void logEvent(const XEvent &xev);

char const *ApplicationName = "icewmtray";

#include "yconfig.h"

#ifdef CONFIG_TASKBAR
YColor *taskBarBg;

XSV(const char *, clrDefaultTaskBar,            "rgb:C0/C0/C0")

cfoption icewmbg_prefs[] = {
    OSV("ColorDefaultTaskBar",                  &clrDefaultTaskBar,             "Background of the taskbar"),
    OK0()
};
#endif

class SysTray: public YWindow, public YXTrayNotifier {
public:
    SysTray();
    bool checkMessageEvent(const XClientMessageEvent &message);
    void requestDock();

    void handleUnmap(const XUnmapEvent &) {
        MSG(("hide"));
        if (visible())
            hide();
    }

    void trayChanged();
private:
    Atom icewm_internal_tray;
    Atom _NET_SYSTEM_TRAY_OPCODE;
    YXTray *fTray2;
};

class SysTrayApp: public YXApplication {
public:
    SysTrayApp(int *argc, char ***argv, const char *displayName = 0);
    ~SysTrayApp();

    bool filterEvent(const XEvent &xev);
    void handleSignal(int sig);

private:
    SysTray *tray;
};

SysTrayApp::SysTrayApp(int *argc, char ***argv, const char *displayName):
    YXApplication(argc, argv, displayName)
{
    desktop->setStyle(YWindow::wsDesktopAware);
    catchSignal(SIGINT);
    catchSignal(SIGTERM);
#ifdef CONFIG_TASKBAR
    if (taskBarBg == 0)
        taskBarBg = new YColor(clrDefaultTaskBar);
#endif
    tray = new SysTray();
}

SysTrayApp::~SysTrayApp() {

}

bool SysTrayApp::filterEvent(const XEvent &xev) {
#ifdef DEBUG
    logEvent(xev);
#endif
    if (xev.type == ClientMessage) {
        tray->checkMessageEvent(xev.xclient);
        return false;
    } else if (xev.type == MappingNotify) {
            MSG(("tray mapping1"));
        if (xev.xmapping.window == tray->handle()) {
            MSG(("tray mapping"));
        }
    }
    return false;
}

void SysTrayApp::handleSignal(int sig) {
    switch (sig) {
    case SIGINT:
    case SIGTERM:
        msg("exiting.");
        exit(0);
        return;
    }
    YXApplication::handleSignal(sig);
}

SysTray::SysTray(): YWindow(0) {
    desktop->setStyle(YWindow::wsDesktopAware);

    char trayatom[64];
    sprintf(trayatom, "_NET_SYSTEM_TRAY_S%d", xapp->screen());
    fTray2 = new YXTray(this, false, trayatom, this);

    char trayatom2[64];
    sprintf(trayatom2, "_ICEWM_INTTRAY_S%d", xapp->screen());
    icewm_internal_tray =
        XInternAtom(xapp->display(), trayatom2, False);

    _NET_SYSTEM_TRAY_OPCODE =
        XInternAtom(xapp->display(),
                    "_NET_SYSTEM_TRAY_OPCODE",
                    False);

    fTray2->relayout();
    setSize(fTray2->width(),
            fTray2->height());
    fTray2->show();
    requestDock();
}

void SysTray::trayChanged() {
    fTray2->relayout();
    setSize(fTray2->width(),
            fTray2->height());
}

void SysTray::requestDock() {
    Window w = XGetSelectionOwner(xapp->display(), icewm_internal_tray);

    if (w && w != handle()) {
        XClientMessageEvent xev;
        memset(&xev, 0, sizeof(xev));

        xev.type = ClientMessage;
        xev.window = w;
        xev.message_type = _NET_SYSTEM_TRAY_OPCODE;
        xev.format = 32;
        xev.data.l[0] = CurrentTime;
        xev.data.l[1] = SYSTEM_TRAY_REQUEST_DOCK;
        xev.data.l[2] = handle(); //fTray2->handle();

        XSendEvent(xapp->display(), w, False, StructureNotifyMask, (XEvent *) &xev);
    }
}

bool SysTray::checkMessageEvent(const XClientMessageEvent &message) {
    if (message.message_type == icewm_internal_tray) {
        MSG(("requestDock"));
        requestDock();
    }
    return true;
}

int main(int argc, char **argv) {
    YLocale locale;

    SysTrayApp stapp(&argc, &argv);

#ifdef CONFIG_TASKBAR
#ifndef NO_CONFIGURE
    {
        cfoption theme_prefs[] = {
            OSV("Theme", &themeName, "Theme name"),
            OK0()
        };

        app->loadConfig(theme_prefs, "preferences");
        app->loadConfig(theme_prefs, "theme");
    }
    YApplication::loadConfig(icewmbg_prefs, "preferences");
    if (themeName != 0) {
        MSG(("themeName=%s", themeName));

        char *theme = strJoin("themes/", themeName, NULL);
        YApplication::loadConfig(icewmbg_prefs, theme);
        delete [] theme;
    }
    YApplication::loadConfig(icewmbg_prefs, "prefoverride");
#endif
#endif

    return app->mainLoop();
}
<|endoftext|>