<commit_before>#include "widgets/splitcontainer.hpp"
#include "common.hpp"
#include "singletons/thememanager.hpp"
#include "util/helpers.hpp"
#include "util/layoutcreator.hpp"
#include "widgets/helper/notebooktab.hpp"
#include "widgets/notebook.hpp"
#include "widgets/split.hpp"

#include <QApplication>
#include <QDebug>
#include <QHBoxLayout>
#include <QMimeData>
#include <QObject>
#include <QPainter>
#include <QVBoxLayout>
#include <QWidget>
#include <boost/foreach.hpp>

#include <algorithm>

namespace chatterino {
namespace widgets {

bool SplitContainer::isDraggingSplit = false;
Split *SplitContainer::draggingSplit = nullptr;
std::pair<int, int> SplitContainer::dropPosition = std::pair<int, int>(-1, -1);

SplitContainer::SplitContainer(Notebook *parent, NotebookTab *_tab)
    : BaseWidget(parent->themeManager, parent)
    , tab(_tab)
    , dropPreview(this)
{
    this->tab->page = this;

    this->setLayout(&this->ui.parentLayout);

    this->setHidden(true);
    this->setAcceptDrops(true);

    this->ui.parentLayout.addSpacing(1);
    this->ui.parentLayout.addLayout(&this->ui.hbox);
    this->ui.parentLayout.setMargin(0);

    this->ui.hbox.setSpacing(1);
    this->ui.hbox.setMargin(0);

    this->refreshTitle();
}

void SplitContainer::updateFlexValues()
{
    for (int i = 0; i < this->ui.hbox.count(); i++) {
        QVBoxLayout *vbox = (QVBoxLayout *)ui.hbox.itemAt(i)->layout();

        if (vbox->count() != 0) {
            ui.hbox.setStretch(i, (int)(1000 * ((Split *)vbox->itemAt(0))->getFlexSizeX()));
        }
    }
}

int SplitContainer::splitCount() const
{
    return this->splits.size();
}

std::pair<int, int> SplitContainer::removeFromLayout(Split *widget)
{
    // remove reference to chat widget from chatWidgets vector
    auto it = std::find(std::begin(this->splits), std::end(this->splits), widget);
    if (it != std::end(this->splits)) {
        this->splits.erase(it);

        this->refreshTitle();
    }

    // remove from box and return location
    for (int i = 0; i < this->ui.hbox.count(); ++i) {
        auto vbox = static_cast<QVBoxLayout *>(this->ui.hbox.itemAt(i));

        for (int j = 0; j < vbox->count(); ++j) {
            if (vbox->itemAt(j)->widget() != widget) {
                continue;
            }

            widget->setParent(nullptr);

            bool isLastItem = vbox->count() == 0;

            if (isLastItem) {
                this->ui.hbox.removeItem(vbox);

                delete vbox;
            }

            return std::pair<int, int>(i, isLastItem ? -1 : j);
        }
    }

    return std::pair<int, int>(-1, -1);
}

void SplitContainer::addToLayout(Split *widget, std::pair<int, int> position)
{
    this->splits.push_back(widget);

    this->refreshTitle();

    widget->giveFocus(Qt::MouseFocusReason);

    // add vbox at the end
    if (position.first < 0 || position.first >= this->ui.hbox.count()) {
        auto vbox = new QVBoxLayout();
        vbox->addWidget(widget);

        this->ui.hbox.addLayout(vbox, 1);

        this->refreshCurrentFocusCoordinates();
        return;
    }

    // insert vbox
    if (position.second == -1) {
        auto vbox = new QVBoxLayout();
        vbox->addWidget(widget);

        this->ui.hbox.insertLayout(position.first, vbox, 1);
        this->refreshCurrentFocusCoordinates();
        return;
    }

    // add to existing vbox
    auto vbox = static_cast<QVBoxLayout *>(this->ui.hbox.itemAt(position.first));

    vbox->insertWidget(std::max(0, std::min(vbox->count(), position.second)), widget);

    this->refreshCurrentFocusCoordinates();
}

const std::vector<Split *> &SplitContainer::getSplits() const
{
    return this->splits;
}

std::vector<std::vector<Split *>> SplitContainer::getColumns() const
{
    std::vector<std::vector<Split *>> columns;

    for (int i = 0; i < this->ui.hbox.count(); i++) {
        std::vector<Split *> cells;

        QLayout *vbox = this->ui.hbox.itemAt(i)->layout();
        for (int j = 0; j < vbox->count(); j++) {
            cells.push_back(dynamic_cast<Split *>(vbox->itemAt(j)->widget()));
        }

        columns.push_back(cells);
    }

    return columns;
}

NotebookTab *SplitContainer::getTab() const
{
    return this->tab;
}

void SplitContainer::addChat(bool openChannelNameDialog, std::string chatUUID)
{
    if (chatUUID.empty()) {
        chatUUID = CreateUUID().toStdString();
    }
    Split *w = this->createChatWidget(chatUUID);

    if (openChannelNameDialog) {
        bool ret = w->showChangeChannelPopup("Open channel name", true);

        if (!ret) {
            delete w;
            return;
        }
    }

    this->addToLayout(w, std::pair<int, int>(-1, -1));
}

void SplitContainer::refreshCurrentFocusCoordinates(bool alsoSetLastRequested)
{
    int setX = -1;
    int setY = -1;
    bool doBreak = false;
    for (int x = 0; x < this->ui.hbox.count(); ++x) {
        QLayoutItem *item = this->ui.hbox.itemAt(x);
        if (item->isEmpty()) {
            setX = x;
            break;
        }
        QVBoxLayout *vbox = static_cast<QVBoxLayout *>(item->layout());

        for (int y = 0; y < vbox->count(); ++y) {
            QLayoutItem *innerItem = vbox->itemAt(y);

            if (innerItem->isEmpty()) {
                setX = x;
                setY = y;
                doBreak = true;
                break;
            }

            QWidget *w = innerItem->widget();
            if (w) {
                Split *chatWidget = static_cast<Split *>(w);
                if (chatWidget->hasFocus()) {
                    setX = x;
                    setY = y;
                    doBreak = true;
                    break;
                }
            }
        }

        if (doBreak) {
            break;
        }
    }

    if (setX != -1) {
        this->currentX = setX;

        if (setY != -1) {
            this->currentY = setY;

            if (alsoSetLastRequested) {
                this->lastRequestedY[setX] = setY;
            }
        }
    }
}

void SplitContainer::requestFocus(int requestedX, int requestedY)
{
    // XXX: Perhaps if we request an Y coordinate out of bounds, we shuold set all previously set
    // requestedYs to 0 (if -1 is requested) or that x-coordinates vbox count (if requestedY >=
    // currentvbox.count() is requested)
    if (requestedX < 0 || requestedX >= this->ui.hbox.count()) {
        return;
    }

    QLayoutItem *item = this->ui.hbox.itemAt(requestedX);
    QWidget *xW = item->widget();
    if (item->isEmpty()) {
        qDebug() << "Requested hbox item " << requestedX << "is empty";
        if (xW) {
            qDebug() << "but xW is not null";
            // TODO: figure out what to do here
        }
        return;
    }

    QVBoxLayout *vbox = static_cast<QVBoxLayout *>(item->layout());

    if (requestedY < 0) {
        requestedY = 0;
    } else if (requestedY >= vbox->count()) {
        requestedY = vbox->count() - 1;
    }

    this->lastRequestedY[requestedX] = requestedY;

    QLayoutItem *innerItem = vbox->itemAt(requestedY);

    if (innerItem->isEmpty()) {
        qDebug() << "Requested vbox item " << requestedY << "is empty";
        return;
    }

    QWidget *w = innerItem->widget();
    if (w) {
        Split *chatWidget = static_cast<Split *>(w);
        chatWidget->giveFocus(Qt::OtherFocusReason);
    }
}

void SplitContainer::enterEvent(QEvent *)
{
    if (this->ui.hbox.count() == 0) {
        this->setCursor(QCursor(Qt::PointingHandCursor));
    } else {
        this->setCursor(QCursor(Qt::ArrowCursor));
    }
}

void SplitContainer::leaveEvent(QEvent *)
{
}

void SplitContainer::mouseReleaseEvent(QMouseEvent *event)
{
    if (this->ui.hbox.count() == 0 && event->button() == Qt::LeftButton) {
        // "Add Chat" was clicked
        this->addChat(true);

        this->setCursor(QCursor(Qt::ArrowCursor));
    }
}

void SplitContainer::dragEnterEvent(QDragEnterEvent *event)
{
    if (!event->mimeData()->hasFormat("chatterino/split"))
        return;

    if (!isDraggingSplit) {
        return;
    }

    this->dropRegions.clear();

    if (this->ui.hbox.count() == 0) {
        this->dropRegions.push_back(DropRegion(rect(), std::pair<int, int>(-1, -1)));
    } else {
        for (int i = 0; i < this->ui.hbox.count() + 1; ++i) {
            this->dropRegions.push_back(
                DropRegion(QRect(((i * 4 - 1) * width() / this->ui.hbox.count()) / 4, 0,
                                 width() / this->ui.hbox.count() / 2 + 1, height() + 1),
                           std::pair<int, int>(i, -1)));
        }

        for (int i = 0; i < this->ui.hbox.count(); ++i) {
            auto vbox = static_cast<QVBoxLayout *>(this->ui.hbox.itemAt(i));

            for (int j = 0; j < vbox->count() + 1; ++j) {
                this->dropRegions.push_back(DropRegion(
                    QRect(i * width() / this->ui.hbox.count(),
                          ((j * 2 - 1) * height() / vbox->count()) / 2,
                          width() / this->ui.hbox.count() + 1, height() / vbox->count() + 1),

                    std::pair<int, int>(i, j)));
            }
        }
    }

    setPreviewRect(event->pos());

    event->acceptProposedAction();
}

void SplitContainer::dragMoveEvent(QDragMoveEvent *event)
{
    setPreviewRect(event->pos());
}

void SplitContainer::setPreviewRect(QPoint mousePos)
{
    for (DropRegion region : this->dropRegions) {
        if (region.rect.contains(mousePos)) {
            this->dropPreview.setBounds(region.rect);

            if (!this->dropPreview.isVisible()) {
                this->dropPreview.show();
                this->dropPreview.raise();
            }

            dropPosition = region.position;

            return;
        }
    }

    this->dropPreview.hide();
}

void SplitContainer::dragLeaveEvent(QDragLeaveEvent *event)
{
    this->dropPreview.hide();
}

void SplitContainer::dropEvent(QDropEvent *event)
{
    if (isDraggingSplit) {
        event->acceptProposedAction();

        SplitContainer::draggingSplit->setParent(this);

        addToLayout(SplitContainer::draggingSplit, dropPosition);
    }

    this->dropPreview.hide();
}

bool SplitContainer::eventFilter(QObject *object, QEvent *event)
{
    if (event->type() == QEvent::FocusIn) {
        QFocusEvent *focusEvent = static_cast<QFocusEvent *>(event);

        this->refreshCurrentFocusCoordinates((focusEvent->reason() == Qt::MouseFocusReason));
    }

    return false;
}

void SplitContainer::paintEvent(QPaintEvent *)
{
    QPainter painter(this);

    if (this->ui.hbox.count() == 0) {
        painter.fillRect(rect(), this->themeManager.splits.background);

        painter.setPen(this->themeManager.splits.header.text);

        QString text = "Click to add a <split>";

        Notebook *notebook = dynamic_cast<Notebook *>(this->parentWidget());

        if (notebook != nullptr) {
            if (notebook->tabCount() > 1) {
                text += "\n\ntip: you can drag a <split> while holding <Alt>";
                text += "\nor add another one by pressing <Ctrl+T>";
            }
        }

        painter.drawText(rect(), text, QTextOption(Qt::AlignCenter));
    } else {
        painter.fillRect(rect(), this->themeManager.splits.messageSeperator);
    }

    QBrush accentColor = (QApplication::activeWindow() == this->window()
                              ? this->themeManager.tabs.selected.backgrounds.regular
                              : this->themeManager.tabs.selected.backgrounds.unfocused);

    painter.fillRect(0, 0, width(), 1, accentColor);
}

void SplitContainer::showEvent(QShowEvent *event)
{
    // Whenever this notebook page is shown, give focus to the last focused chat widget
    // If this is the first time this notebook page is shown, it will give focus to the top-left
    // chat widget
    this->requestFocus(this->currentX, this->currentY);
}

static std::pair<int, int> getWidgetPositionInLayout(QLayout *layout, const Split *chatWidget)
{
    for (int i = 0; i < layout->count(); ++i) {
        printf("xD\n");
    }

    return std::make_pair(-1, -1);
}

std::pair<int, int> SplitContainer::getChatPosition(const Split *chatWidget)
{
    auto layout = this->ui.hbox.layout();

    if (layout == nullptr) {
        return std::make_pair(-1, -1);
    }

    return getWidgetPositionInLayout(layout, chatWidget);
}

Split *SplitContainer::createChatWidget(const std::string &uuid)
{
    auto split = new Split(this);

    split->getChannelView().highlightedMessageReceived.connect([this] {
        // fourtf: error potentionally here
        this->tab->setHighlightState(HighlightState::Highlighted);  //
    });

    return split;
}

void SplitContainer::refreshTitle()
{
    if (!this->tab->useDefaultTitle) {
        return;
    }

    QString newTitle = "";
    bool first = true;

    for (const auto &chatWidget : this->splits) {
        auto channelName = chatWidget->getChannel()->name;
        if (channelName.isEmpty()) {
            continue;
        }

        if (!first) {
            newTitle += ", ";
        }
        newTitle += channelName;

        first = false;
    }

    if (newTitle.isEmpty()) {
        newTitle = "empty";
    }

    this->tab->setTitle(newTitle);
}

}  // namespace widgets
}  // namespace chatterino
<commit_msg>Closing splits now tries to focus a neighbouring split<commit_after>#include "widgets/splitcontainer.hpp"
#include "common.hpp"
#include "singletons/thememanager.hpp"
#include "util/helpers.hpp"
#include "util/layoutcreator.hpp"
#include "widgets/helper/notebooktab.hpp"
#include "widgets/notebook.hpp"
#include "widgets/split.hpp"

#include <QApplication>
#include <QDebug>
#include <QHBoxLayout>
#include <QMimeData>
#include <QObject>
#include <QPainter>
#include <QVBoxLayout>
#include <QWidget>
#include <boost/foreach.hpp>

#include <algorithm>

namespace chatterino {
namespace widgets {

bool SplitContainer::isDraggingSplit = false;
Split *SplitContainer::draggingSplit = nullptr;
std::pair<int, int> SplitContainer::dropPosition = std::pair<int, int>(-1, -1);

SplitContainer::SplitContainer(Notebook *parent, NotebookTab *_tab)
    : BaseWidget(parent->themeManager, parent)
    , tab(_tab)
    , dropPreview(this)
{
    this->tab->page = this;

    this->setLayout(&this->ui.parentLayout);

    this->setHidden(true);
    this->setAcceptDrops(true);

    this->ui.parentLayout.addSpacing(1);
    this->ui.parentLayout.addLayout(&this->ui.hbox);
    this->ui.parentLayout.setMargin(0);

    this->ui.hbox.setSpacing(1);
    this->ui.hbox.setMargin(0);

    this->refreshTitle();
}

void SplitContainer::updateFlexValues()
{
    for (int i = 0; i < this->ui.hbox.count(); i++) {
        QVBoxLayout *vbox = (QVBoxLayout *)ui.hbox.itemAt(i)->layout();

        if (vbox->count() != 0) {
            ui.hbox.setStretch(i, (int)(1000 * ((Split *)vbox->itemAt(0))->getFlexSizeX()));
        }
    }
}

int SplitContainer::splitCount() const
{
    return this->splits.size();
}

std::pair<int, int> SplitContainer::removeFromLayout(Split *widget)
{
    // remove reference to chat widget from chatWidgets vector
    auto it = std::find(std::begin(this->splits), std::end(this->splits), widget);
    if (it != std::end(this->splits)) {
        this->splits.erase(it);

        this->refreshTitle();
    }

    Split *neighbouringSplit = nullptr;

    // Position the split was found at
    int positionX = -1, positionY = -1;

    bool removed = false;

    QVBoxLayout *layoutToRemove = nullptr;

    // Find widget in box, remove it, return its position
    for (int i = 0; i < this->ui.hbox.count(); ++i) {
        auto vbox = static_cast<QVBoxLayout *>(this->ui.hbox.itemAt(i));

        auto vboxCount = vbox->count();

        for (int j = 0; j < vboxCount; ++j) {
            if (vbox->itemAt(j)->widget() != widget) {
                neighbouringSplit = dynamic_cast<Split *>(vbox->itemAt(j)->widget());

                if (removed && neighbouringSplit != nullptr) {
                    // The widget we searched for has been found, and we have a split to switch
                    // focus to
                    break;
                }

                continue;
            }

            removed = true;
            positionX = i;

            // Remove split from box
            widget->setParent(nullptr);

            if (vbox->count() == 0) {
                // The split was the last item remaining in the vbox
                // Remove the vbox once all iteration is done
                layoutToRemove = vbox;
                positionY = -1;
                break;
            }

            // Don't break here yet, we want to keep iterating this vbox if possible to find the
            // closest still-alive neighbour that we can switch focus to
            positionY = j;

            --j;
            --vboxCount;
        }

        if (removed && neighbouringSplit != nullptr) {
            // The widget we searched for has been found, and we have a split to switch focus to
            break;
        }
    }

    if (removed) {
        if (layoutToRemove != nullptr) {
            // The split we removed was the last split in its box. Remove the box
            // We delay the removing of the box so we can keep iterating over hbox safely
            this->ui.hbox.removeItem(layoutToRemove);
            delete layoutToRemove;
        }

        if (neighbouringSplit != nullptr) {
            // We found a neighbour split we can switch focus to
            neighbouringSplit->giveFocus(Qt::MouseFocusReason);
        }
    }

    return std::make_pair(positionX, positionY);
}

void SplitContainer::addToLayout(Split *widget, std::pair<int, int> position)
{
    this->splits.push_back(widget);

    this->refreshTitle();

    widget->giveFocus(Qt::MouseFocusReason);

    // add vbox at the end
    if (position.first < 0 || position.first >= this->ui.hbox.count()) {
        auto vbox = new QVBoxLayout();
        vbox->addWidget(widget);

        this->ui.hbox.addLayout(vbox, 1);

        this->refreshCurrentFocusCoordinates();
        return;
    }

    // insert vbox
    if (position.second == -1) {
        auto vbox = new QVBoxLayout();
        vbox->addWidget(widget);

        this->ui.hbox.insertLayout(position.first, vbox, 1);
        this->refreshCurrentFocusCoordinates();
        return;
    }

    // add to existing vbox
    auto vbox = static_cast<QVBoxLayout *>(this->ui.hbox.itemAt(position.first));

    vbox->insertWidget(std::max(0, std::min(vbox->count(), position.second)), widget);

    this->refreshCurrentFocusCoordinates();
}

const std::vector<Split *> &SplitContainer::getSplits() const
{
    return this->splits;
}

std::vector<std::vector<Split *>> SplitContainer::getColumns() const
{
    std::vector<std::vector<Split *>> columns;

    for (int i = 0; i < this->ui.hbox.count(); i++) {
        std::vector<Split *> cells;

        QLayout *vbox = this->ui.hbox.itemAt(i)->layout();
        for (int j = 0; j < vbox->count(); j++) {
            cells.push_back(dynamic_cast<Split *>(vbox->itemAt(j)->widget()));
        }

        columns.push_back(cells);
    }

    return columns;
}

NotebookTab *SplitContainer::getTab() const
{
    return this->tab;
}

void SplitContainer::addChat(bool openChannelNameDialog, std::string chatUUID)
{
    if (chatUUID.empty()) {
        chatUUID = CreateUUID().toStdString();
    }
    Split *w = this->createChatWidget(chatUUID);

    if (openChannelNameDialog) {
        bool ret = w->showChangeChannelPopup("Open channel name", true);

        if (!ret) {
            delete w;
            return;
        }
    }

    this->addToLayout(w, std::pair<int, int>(-1, -1));
}

void SplitContainer::refreshCurrentFocusCoordinates(bool alsoSetLastRequested)
{
    int setX = -1;
    int setY = -1;
    bool doBreak = false;
    for (int x = 0; x < this->ui.hbox.count(); ++x) {
        QLayoutItem *item = this->ui.hbox.itemAt(x);
        if (item->isEmpty()) {
            setX = x;
            break;
        }
        QVBoxLayout *vbox = static_cast<QVBoxLayout *>(item->layout());

        for (int y = 0; y < vbox->count(); ++y) {
            QLayoutItem *innerItem = vbox->itemAt(y);

            if (innerItem->isEmpty()) {
                setX = x;
                setY = y;
                doBreak = true;
                break;
            }

            QWidget *w = innerItem->widget();
            if (w) {
                Split *chatWidget = static_cast<Split *>(w);
                if (chatWidget->hasFocus()) {
                    setX = x;
                    setY = y;
                    doBreak = true;
                    break;
                }
            }
        }

        if (doBreak) {
            break;
        }
    }

    if (setX != -1) {
        this->currentX = setX;

        if (setY != -1) {
            this->currentY = setY;

            if (alsoSetLastRequested) {
                this->lastRequestedY[setX] = setY;
            }
        }
    }
}

void SplitContainer::requestFocus(int requestedX, int requestedY)
{
    // XXX: Perhaps if we request an Y coordinate out of bounds, we shuold set all previously set
    // requestedYs to 0 (if -1 is requested) or that x-coordinates vbox count (if requestedY >=
    // currentvbox.count() is requested)
    if (requestedX < 0 || requestedX >= this->ui.hbox.count()) {
        return;
    }

    QLayoutItem *item = this->ui.hbox.itemAt(requestedX);
    QWidget *xW = item->widget();
    if (item->isEmpty()) {
        qDebug() << "Requested hbox item " << requestedX << "is empty";
        if (xW) {
            qDebug() << "but xW is not null";
            // TODO: figure out what to do here
        }
        return;
    }

    QVBoxLayout *vbox = static_cast<QVBoxLayout *>(item->layout());

    if (requestedY < 0) {
        requestedY = 0;
    } else if (requestedY >= vbox->count()) {
        requestedY = vbox->count() - 1;
    }

    this->lastRequestedY[requestedX] = requestedY;

    QLayoutItem *innerItem = vbox->itemAt(requestedY);

    if (innerItem->isEmpty()) {
        qDebug() << "Requested vbox item " << requestedY << "is empty";
        return;
    }

    QWidget *w = innerItem->widget();
    if (w) {
        Split *chatWidget = static_cast<Split *>(w);
        chatWidget->giveFocus(Qt::OtherFocusReason);
    }
}

void SplitContainer::enterEvent(QEvent *)
{
    if (this->ui.hbox.count() == 0) {
        this->setCursor(QCursor(Qt::PointingHandCursor));
    } else {
        this->setCursor(QCursor(Qt::ArrowCursor));
    }
}

void SplitContainer::leaveEvent(QEvent *)
{
}

void SplitContainer::mouseReleaseEvent(QMouseEvent *event)
{
    if (this->ui.hbox.count() == 0 && event->button() == Qt::LeftButton) {
        // "Add Chat" was clicked
        this->addChat(true);

        this->setCursor(QCursor(Qt::ArrowCursor));
    }
}

void SplitContainer::dragEnterEvent(QDragEnterEvent *event)
{
    if (!event->mimeData()->hasFormat("chatterino/split"))
        return;

    if (!isDraggingSplit) {
        return;
    }

    this->dropRegions.clear();

    if (this->ui.hbox.count() == 0) {
        this->dropRegions.push_back(DropRegion(rect(), std::pair<int, int>(-1, -1)));
    } else {
        for (int i = 0; i < this->ui.hbox.count() + 1; ++i) {
            this->dropRegions.push_back(
                DropRegion(QRect(((i * 4 - 1) * width() / this->ui.hbox.count()) / 4, 0,
                                 width() / this->ui.hbox.count() / 2 + 1, height() + 1),
                           std::pair<int, int>(i, -1)));
        }

        for (int i = 0; i < this->ui.hbox.count(); ++i) {
            auto vbox = static_cast<QVBoxLayout *>(this->ui.hbox.itemAt(i));

            for (int j = 0; j < vbox->count() + 1; ++j) {
                this->dropRegions.push_back(DropRegion(
                    QRect(i * width() / this->ui.hbox.count(),
                          ((j * 2 - 1) * height() / vbox->count()) / 2,
                          width() / this->ui.hbox.count() + 1, height() / vbox->count() + 1),

                    std::pair<int, int>(i, j)));
            }
        }
    }

    setPreviewRect(event->pos());

    event->acceptProposedAction();
}

void SplitContainer::dragMoveEvent(QDragMoveEvent *event)
{
    setPreviewRect(event->pos());
}

void SplitContainer::setPreviewRect(QPoint mousePos)
{
    for (DropRegion region : this->dropRegions) {
        if (region.rect.contains(mousePos)) {
            this->dropPreview.setBounds(region.rect);

            if (!this->dropPreview.isVisible()) {
                this->dropPreview.show();
                this->dropPreview.raise();
            }

            dropPosition = region.position;

            return;
        }
    }

    this->dropPreview.hide();
}

void SplitContainer::dragLeaveEvent(QDragLeaveEvent *event)
{
    this->dropPreview.hide();
}

void SplitContainer::dropEvent(QDropEvent *event)
{
    if (isDraggingSplit) {
        event->acceptProposedAction();

        SplitContainer::draggingSplit->setParent(this);

        addToLayout(SplitContainer::draggingSplit, dropPosition);
    }

    this->dropPreview.hide();
}

bool SplitContainer::eventFilter(QObject *object, QEvent *event)
{
    if (event->type() == QEvent::FocusIn) {
        QFocusEvent *focusEvent = static_cast<QFocusEvent *>(event);

        this->refreshCurrentFocusCoordinates((focusEvent->reason() == Qt::MouseFocusReason));
    }

    return false;
}

void SplitContainer::paintEvent(QPaintEvent *)
{
    QPainter painter(this);

    if (this->ui.hbox.count() == 0) {
        painter.fillRect(rect(), this->themeManager.splits.background);

        painter.setPen(this->themeManager.splits.header.text);

        QString text = "Click to add a <split>";

        Notebook *notebook = dynamic_cast<Notebook *>(this->parentWidget());

        if (notebook != nullptr) {
            if (notebook->tabCount() > 1) {
                text += "\n\ntip: you can drag a <split> while holding <Alt>";
                text += "\nor add another one by pressing <Ctrl+T>";
            }
        }

        painter.drawText(rect(), text, QTextOption(Qt::AlignCenter));
    } else {
        painter.fillRect(rect(), this->themeManager.splits.messageSeperator);
    }

    QBrush accentColor = (QApplication::activeWindow() == this->window()
                              ? this->themeManager.tabs.selected.backgrounds.regular
                              : this->themeManager.tabs.selected.backgrounds.unfocused);

    painter.fillRect(0, 0, width(), 1, accentColor);
}

void SplitContainer::showEvent(QShowEvent *event)
{
    // Whenever this notebook page is shown, give focus to the last focused chat widget
    // If this is the first time this notebook page is shown, it will give focus to the top-left
    // chat widget
    this->requestFocus(this->currentX, this->currentY);
}

static std::pair<int, int> getWidgetPositionInLayout(QLayout *layout, const Split *chatWidget)
{
    for (int i = 0; i < layout->count(); ++i) {
        printf("xD\n");
    }

    return std::make_pair(-1, -1);
}

std::pair<int, int> SplitContainer::getChatPosition(const Split *chatWidget)
{
    auto layout = this->ui.hbox.layout();

    if (layout == nullptr) {
        return std::make_pair(-1, -1);
    }

    return getWidgetPositionInLayout(layout, chatWidget);
}

Split *SplitContainer::createChatWidget(const std::string &uuid)
{
    auto split = new Split(this);

    split->getChannelView().highlightedMessageReceived.connect([this] {
        // fourtf: error potentionally here
        this->tab->setHighlightState(HighlightState::Highlighted);  //
    });

    return split;
}

void SplitContainer::refreshTitle()
{
    if (!this->tab->useDefaultTitle) {
        return;
    }

    QString newTitle = "";
    bool first = true;

    for (const auto &chatWidget : this->splits) {
        auto channelName = chatWidget->getChannel()->name;
        if (channelName.isEmpty()) {
            continue;
        }

        if (!first) {
            newTitle += ", ";
        }
        newTitle += channelName;

        first = false;
    }

    if (newTitle.isEmpty()) {
        newTitle = "empty";
    }

    this->tab->setTitle(newTitle);
}

}  // namespace widgets
}  // namespace chatterino
<|endoftext|>


<commit_before>#ifndef __STAN__AGRAD__REV__TRUNC_HPP__
#define __STAN__AGRAD__REV__TRUNC_HPP__

#include <stan/agrad/rev/var.hpp>
#include <stan/agrad/rev/vari.hpp>

namespace stan {
  namespace agrad {

    namespace {
      // derivative 0 almost everywhere
      class trunc_vari : public vari {
      public:
        trunc_vari(vari* avi) :
          vari(boost::math::trunc(avi->val_)) {
        }
      };
    }

    /**
     * Returns the truncatation of the specified variable (C99).
     *
     * See boost::math::trunc() for the double-based version.
     *
     * The derivative is zero everywhere but at integer values, so for
     * convenience the derivative is defined to be everywhere zero,
     *
     * \f$\frac{d}{dx} \mbox{trunc}(x) = 0\f$.
     *
     * @param a Specified variable.
     * @return Truncation of the variable.
     */
    inline var trunc(const stan::agrad::var& a) {
      return var(new trunc_vari(a.vi_));
    }

  }
}
#endif
<commit_msg>moving trunc tests out of test/agrad/special_functions<commit_after>#ifndef __STAN__AGRAD__REV__TRUNC_HPP__
#define __STAN__AGRAD__REV__TRUNC_HPP__

#include <boost/math/special_functions/trunc.hpp>
#include <stan/agrad/rev/var.hpp>
#include <stan/agrad/rev/vari.hpp>

namespace stan {
  namespace agrad {

    namespace {
      // derivative 0 almost everywhere
      class trunc_vari : public vari {
      public:
        trunc_vari(vari* avi) :
          vari(boost::math::trunc(avi->val_)) {
        }
      };
    }

    /**
     * Returns the truncatation of the specified variable (C99).
     *
     * See boost::math::trunc() for the double-based version.
     *
     * The derivative is zero everywhere but at integer values, so for
     * convenience the derivative is defined to be everywhere zero,
     *
     * \f$\frac{d}{dx} \mbox{trunc}(x) = 0\f$.
     *
     * @param a Specified variable.
     * @return Truncation of the variable.
     */
    inline var trunc(const stan::agrad::var& a) {
      return var(new trunc_vari(a.vi_));
    }

  }
}
#endif
<|endoftext|>


<commit_before>/*
* OCSP
* (C) 2012,2013 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#include <botan/ocsp.h>
#include <botan/certstor.h>
#include <botan/der_enc.h>
#include <botan/ber_dec.h>
#include <botan/x509_ext.h>
#include <botan/oids.h>
#include <botan/base64.h>
#include <botan/pubkey.h>
#include <botan/x509path.h>

#if defined(BOTAN_HAS_HTTP_UTIL)
  #include <botan/http_util.h>
#endif

namespace Botan {

namespace OCSP {

namespace {

// TODO: should this be in a header somewhere?
void decode_optional_list(BER_Decoder& ber,
                          ASN1_Tag tag,
                          std::vector<X509_Certificate>& output)
   {
   BER_Object obj = ber.get_next_object();

   if(obj.type_tag != tag || obj.class_tag != (CONTEXT_SPECIFIC | CONSTRUCTED))
      {
      ber.push_back(obj);
      return;
      }

   BER_Decoder list(obj.value);

   while(list.more_items())
      {
      BER_Object certbits = list.get_next_object();
      X509_Certificate cert(unlock(certbits.value));
      output.push_back(std::move(cert));
      }
   }

}

Request::Request(const X509_Certificate& issuer_cert,
                 const X509_Certificate& subject_cert) :
   m_issuer(issuer_cert),
   m_subject(subject_cert),
   m_certid(m_issuer, m_subject)
   {
   }

std::vector<byte> Request::BER_encode() const
   {
   return DER_Encoder().start_cons(SEQUENCE)
        .start_cons(SEQUENCE)
          .start_explicit(0)
            .encode(static_cast<size_t>(0)) // version #
          .end_explicit()
            .start_cons(SEQUENCE)
              .start_cons(SEQUENCE)
                .encode(m_certid)
              .end_cons()
            .end_cons()
          .end_cons()
      .end_cons().get_contents_unlocked();
   }

std::string Request::base64_encode() const
   {
   return Botan::base64_encode(BER_encode());
   }

Response::Response(const std::vector<byte>& response_bits)
   {
   BER_Decoder response_outer = BER_Decoder(response_bits).start_cons(SEQUENCE);

   size_t resp_status = 0;

   response_outer.decode(resp_status, ENUMERATED, UNIVERSAL);

   if(resp_status != 0)
      throw Exception("OCSP response status " + std::to_string(resp_status));

   if(response_outer.more_items())
      {
      BER_Decoder response_bytes =
         response_outer.start_cons(ASN1_Tag(0), CONTEXT_SPECIFIC).start_cons(SEQUENCE);

      response_bytes.decode_and_check(OID("1.3.6.1.5.5.7.48.1.1"),
                                      "Unknown response type in OCSP response");

      BER_Decoder basicresponse =
         BER_Decoder(response_bytes.get_next_octet_string()).start_cons(SEQUENCE);

      basicresponse.start_cons(SEQUENCE)
           .raw_bytes(m_tbs_bits)
         .end_cons()
         .decode(m_sig_algo)
         .decode(m_signature, BIT_STRING);
      decode_optional_list(basicresponse, ASN1_Tag(0), m_certs);

      size_t responsedata_version = 0;
      Extensions extensions;

      BER_Decoder(m_tbs_bits)
         .decode_optional(responsedata_version, ASN1_Tag(0),
                          ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC))

         .decode_optional(m_signer_name, ASN1_Tag(1),
                          ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC))

         .decode_optional_string(m_key_hash, OCTET_STRING, 2,
                                 ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC))

         .decode(m_produced_at)

         .decode_list(m_responses)

         .decode_optional(extensions, ASN1_Tag(1),
                          ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC));
      }

   response_outer.end_cons();
   }

Certificate_Status_Code Response::verify_signature(const X509_Certificate& issuer) const
   {
   try
      {
      std::unique_ptr<Public_Key> pub_key(issuer.subject_public_key());

      const std::vector<std::string> sig_info =
         split_on(OIDS::lookup(m_sig_algo.oid), '/');

      if(sig_info.size() != 2 || sig_info[0] != pub_key->algo_name())
         return Certificate_Status_Code::OCSP_RESPONSE_INVALID;

      std::string padding = sig_info[1];
      Signature_Format format = (pub_key->message_parts() >= 2) ? DER_SEQUENCE : IEEE_1363;

      PK_Verifier verifier(*pub_key, padding, format);

      if(verifier.verify_message(ASN1::put_in_sequence(m_tbs_bits), m_signature))
         return Certificate_Status_Code::OCSP_SIGNATURE_OK;
      else
         return Certificate_Status_Code::OCSP_SIGNATURE_ERROR;
      }
   catch(Exception&)
      {
      return Certificate_Status_Code::OCSP_SIGNATURE_ERROR;
      }
   }

Certificate_Status_Code Response::check_signature(const std::vector<Certificate_Store*>& trusted_roots,
                                                  const std::vector<std::shared_ptr<const X509_Certificate>>& ee_cert_path) const
   {
   std::shared_ptr<const X509_Certificate> signing_cert;

   for(size_t i = 0; i != trusted_roots.size(); ++i)
      {
      if(m_signer_name.empty() && m_key_hash.empty())
         return Certificate_Status_Code::OCSP_RESPONSE_INVALID;

      if(!m_signer_name.empty())
         {
         signing_cert = trusted_roots[i]->find_cert(m_signer_name, std::vector<byte>());
         if(signing_cert)
            {
            break;
            }
         }

      if(m_key_hash.size() > 0)
         {
         signing_cert = trusted_roots[i]->find_cert_by_pubkey_sha1(m_key_hash);
         if(signing_cert)
            {
            break;
            }
         }
      }

   if(!signing_cert)
      {
      for(size_t i = 1; i < ee_cert_path.size(); ++i)
         {
         // Check all CA certificates in the (assumed validated) EE cert path
         if(!m_signer_name.empty() && ee_cert_path[i]->subject_dn() == m_signer_name)
            {
            signing_cert = ee_cert_path[i];
            break;
            }

         if(m_key_hash.size() > 0 && ee_cert_path[i]->subject_public_key_bitstring_sha1() == m_key_hash)
            {
            signing_cert = ee_cert_path[i];
            break;
            }
         }
      }

   // TODO: this ignores m_certs

   if(!signing_cert)
      return Certificate_Status_Code::OCSP_ISSUER_NOT_FOUND;

   if(!signing_cert->allowed_extended_usage("PKIX.OCSPSigning"))
      return Certificate_Status_Code::OCSP_RESPONSE_MISSING_KEYUSAGE;

   return this->verify_signature(*signing_cert);
   }

Certificate_Status_Code Response::status_for(const X509_Certificate& issuer,
                                             const X509_Certificate& subject,
                                             std::chrono::system_clock::time_point ref_time) const
   {
   for(const auto& response : m_responses)
      {
      if(response.certid().is_id_for(issuer, subject))
         {
         X509_Time x509_ref_time(ref_time);

         if(response.cert_status() == 1)
            return Certificate_Status_Code::CERT_IS_REVOKED;

         if(response.this_update() > x509_ref_time)
            return Certificate_Status_Code::OCSP_NOT_YET_VALID;

         if(response.next_update().time_is_set() && x509_ref_time > response.next_update())
            return Certificate_Status_Code::OCSP_HAS_EXPIRED;

         if(response.cert_status() == 0)
            return Certificate_Status_Code::OCSP_RESPONSE_GOOD;
         else
            return Certificate_Status_Code::OCSP_BAD_STATUS;
         }
      }

   return Certificate_Status_Code::OCSP_CERT_NOT_LISTED;
   }

#if defined(BOTAN_HAS_HTTP_UTIL)

Response online_check(const X509_Certificate& issuer,
                      const X509_Certificate& subject,
                      Certificate_Store* trusted_roots)
   {
   const std::string responder_url = subject.ocsp_responder();

   if(responder_url.empty())
      throw Exception("No OCSP responder specified");

   OCSP::Request req(issuer, subject);

   auto http = HTTP::POST_sync(responder_url,
                               "application/ocsp-request",
                               req.BER_encode());

   http.throw_unless_ok();

   // Check the MIME type?

   OCSP::Response response(http.body());

   std::vector<Certificate_Store*> trusted_roots_vec;
   trusted_roots_vec.push_back(trusted_roots);

   if(trusted_roots)
      response.check_signature(trusted_roots_vec);

   return response;
   }

#endif

}

}
<commit_msg>Consult the response for matching certs also, fixes Symantec OCSP<commit_after>/*
* OCSP
* (C) 2012,2013 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#include <botan/ocsp.h>
#include <botan/certstor.h>
#include <botan/der_enc.h>
#include <botan/ber_dec.h>
#include <botan/x509_ext.h>
#include <botan/oids.h>
#include <botan/base64.h>
#include <botan/pubkey.h>
#include <botan/x509path.h>

#if defined(BOTAN_HAS_HTTP_UTIL)
  #include <botan/http_util.h>
#endif

namespace Botan {

namespace OCSP {

namespace {

// TODO: should this be in a header somewhere?
void decode_optional_list(BER_Decoder& ber,
                          ASN1_Tag tag,
                          std::vector<X509_Certificate>& output)
   {
   BER_Object obj = ber.get_next_object();

   if(obj.type_tag != tag || obj.class_tag != (CONTEXT_SPECIFIC | CONSTRUCTED))
      {
      ber.push_back(obj);
      return;
      }

   BER_Decoder list(obj.value);

   while(list.more_items())
      {
      BER_Object certbits = list.get_next_object();
      X509_Certificate cert(unlock(certbits.value));
      output.push_back(std::move(cert));
      }
   }

}

Request::Request(const X509_Certificate& issuer_cert,
                 const X509_Certificate& subject_cert) :
   m_issuer(issuer_cert),
   m_subject(subject_cert),
   m_certid(m_issuer, m_subject)
   {
   }

std::vector<byte> Request::BER_encode() const
   {
   return DER_Encoder().start_cons(SEQUENCE)
        .start_cons(SEQUENCE)
          .start_explicit(0)
            .encode(static_cast<size_t>(0)) // version #
          .end_explicit()
            .start_cons(SEQUENCE)
              .start_cons(SEQUENCE)
                .encode(m_certid)
              .end_cons()
            .end_cons()
          .end_cons()
      .end_cons().get_contents_unlocked();
   }

std::string Request::base64_encode() const
   {
   return Botan::base64_encode(BER_encode());
   }

Response::Response(const std::vector<byte>& response_bits)
   {
   BER_Decoder response_outer = BER_Decoder(response_bits).start_cons(SEQUENCE);

   size_t resp_status = 0;

   response_outer.decode(resp_status, ENUMERATED, UNIVERSAL);

   if(resp_status != 0)
      throw Exception("OCSP response status " + std::to_string(resp_status));

   if(response_outer.more_items())
      {
      BER_Decoder response_bytes =
         response_outer.start_cons(ASN1_Tag(0), CONTEXT_SPECIFIC).start_cons(SEQUENCE);

      response_bytes.decode_and_check(OID("1.3.6.1.5.5.7.48.1.1"),
                                      "Unknown response type in OCSP response");

      BER_Decoder basicresponse =
         BER_Decoder(response_bytes.get_next_octet_string()).start_cons(SEQUENCE);

      basicresponse.start_cons(SEQUENCE)
           .raw_bytes(m_tbs_bits)
         .end_cons()
         .decode(m_sig_algo)
         .decode(m_signature, BIT_STRING);
      decode_optional_list(basicresponse, ASN1_Tag(0), m_certs);

      size_t responsedata_version = 0;
      Extensions extensions;

      BER_Decoder(m_tbs_bits)
         .decode_optional(responsedata_version, ASN1_Tag(0),
                          ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC))

         .decode_optional(m_signer_name, ASN1_Tag(1),
                          ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC))

         .decode_optional_string(m_key_hash, OCTET_STRING, 2,
                                 ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC))

         .decode(m_produced_at)

         .decode_list(m_responses)

         .decode_optional(extensions, ASN1_Tag(1),
                          ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC));
      }

   response_outer.end_cons();
   }

Certificate_Status_Code Response::verify_signature(const X509_Certificate& issuer) const
   {
   try
      {
      std::unique_ptr<Public_Key> pub_key(issuer.subject_public_key());

      const std::vector<std::string> sig_info =
         split_on(OIDS::lookup(m_sig_algo.oid), '/');

      if(sig_info.size() != 2 || sig_info[0] != pub_key->algo_name())
         return Certificate_Status_Code::OCSP_RESPONSE_INVALID;

      std::string padding = sig_info[1];
      Signature_Format format = (pub_key->message_parts() >= 2) ? DER_SEQUENCE : IEEE_1363;

      PK_Verifier verifier(*pub_key, padding, format);

      if(verifier.verify_message(ASN1::put_in_sequence(m_tbs_bits), m_signature))
         return Certificate_Status_Code::OCSP_SIGNATURE_OK;
      else
         return Certificate_Status_Code::OCSP_SIGNATURE_ERROR;
      }
   catch(Exception&)
      {
      return Certificate_Status_Code::OCSP_SIGNATURE_ERROR;
      }
   }

Certificate_Status_Code Response::check_signature(const std::vector<Certificate_Store*>& trusted_roots,
                                                  const std::vector<std::shared_ptr<const X509_Certificate>>& ee_cert_path) const
   {
   std::shared_ptr<const X509_Certificate> signing_cert;

   for(size_t i = 0; i != trusted_roots.size(); ++i)
      {
      if(m_signer_name.empty() && m_key_hash.empty())
         return Certificate_Status_Code::OCSP_RESPONSE_INVALID;

      if(!m_signer_name.empty())
         {
         signing_cert = trusted_roots[i]->find_cert(m_signer_name, std::vector<byte>());
         if(signing_cert)
            {
            break;
            }
         }

      if(m_key_hash.size() > 0)
         {
         signing_cert = trusted_roots[i]->find_cert_by_pubkey_sha1(m_key_hash);
         if(signing_cert)
            {
            break;
            }
         }
      }

   if(!signing_cert && ee_cert_path.size() > 1)
      {
      // End entity cert is not allowed to sign their own OCSP request :)
      for(size_t i = 1; i < ee_cert_path.size(); ++i)
         {
         // Check all CA certificates in the (assumed validated) EE cert path
         if(!m_signer_name.empty() && ee_cert_path[i]->subject_dn() == m_signer_name)
            {
            signing_cert = ee_cert_path[i];
            break;
            }

         if(m_key_hash.size() > 0 && ee_cert_path[i]->subject_public_key_bitstring_sha1() == m_key_hash)
            {
            signing_cert = ee_cert_path[i];
            break;
            }
         }
      }

   if(!signing_cert && m_certs.size() > 0)
      {
      for(size_t i = 0; i < m_certs.size(); ++i)
         {
         // Check all CA certificates in the (assumed validated) EE cert path
         if(!m_signer_name.empty() && m_certs[i].subject_dn() == m_signer_name)
            {
            signing_cert = std::make_shared<const X509_Certificate>(m_certs[i]);
            break;
            }

         if(m_key_hash.size() > 0 && m_certs[i].subject_public_key_bitstring_sha1() == m_key_hash)
            {
            signing_cert = std::make_shared<const X509_Certificate>(m_certs[i]);
            break;
            }
         }
      }

   if(!signing_cert)
      return Certificate_Status_Code::OCSP_ISSUER_NOT_FOUND;

   if(!signing_cert->allowed_extended_usage("PKIX.OCSPSigning"))
      return Certificate_Status_Code::OCSP_RESPONSE_MISSING_KEYUSAGE;

   return this->verify_signature(*signing_cert);
   }

Certificate_Status_Code Response::status_for(const X509_Certificate& issuer,
                                             const X509_Certificate& subject,
                                             std::chrono::system_clock::time_point ref_time) const
   {
   for(const auto& response : m_responses)
      {
      if(response.certid().is_id_for(issuer, subject))
         {
         X509_Time x509_ref_time(ref_time);

         if(response.cert_status() == 1)
            return Certificate_Status_Code::CERT_IS_REVOKED;

         if(response.this_update() > x509_ref_time)
            return Certificate_Status_Code::OCSP_NOT_YET_VALID;

         if(response.next_update().time_is_set() && x509_ref_time > response.next_update())
            return Certificate_Status_Code::OCSP_HAS_EXPIRED;

         if(response.cert_status() == 0)
            return Certificate_Status_Code::OCSP_RESPONSE_GOOD;
         else
            return Certificate_Status_Code::OCSP_BAD_STATUS;
         }
      }

   return Certificate_Status_Code::OCSP_CERT_NOT_LISTED;
   }

#if defined(BOTAN_HAS_HTTP_UTIL)

Response online_check(const X509_Certificate& issuer,
                      const X509_Certificate& subject,
                      Certificate_Store* trusted_roots)
   {
   const std::string responder_url = subject.ocsp_responder();

   if(responder_url.empty())
      throw Exception("No OCSP responder specified");

   OCSP::Request req(issuer, subject);

   auto http = HTTP::POST_sync(responder_url,
                               "application/ocsp-request",
                               req.BER_encode());

   http.throw_unless_ok();

   // Check the MIME type?

   OCSP::Response response(http.body());

   std::vector<Certificate_Store*> trusted_roots_vec;
   trusted_roots_vec.push_back(trusted_roots);

   if(trusted_roots)
      response.check_signature(trusted_roots_vec);

   return response;
   }

#endif

}

}
<|endoftext|>


<commit_before>#include "reader.hpp"

namespace clpr_d{

	reader::reader(clpr_proc_db & db){

		uint64_t global_label=0;
		while(1){

			ifstream pipe_in(CLPR_INPUT_PIPE);
			struct stat st;

			if (!(S_ISFIFO(st.st_mode)))
				std::invalid_argument("bad or non-existant fifo");

			string in;

			//input:
			//pidstat -d -u -h -l -r -w -U  -v | grep -v root
			string host_info="?";
			string index;
			while (getline(pipe_in,in)){

				istringstream iss(in);
				vector<string> tokens{istream_iterator<string>{iss},
					istream_iterator<string>{}};

				//not a blank line nor a header
				if ((tokens.size()>0) && (tokens.size()!=23)){

					if (tokens.size()<=20){
						host_info=in;
					}
					if (tokens.size()>20){

						index = get_uid_blob_label(tokens);
						uid_blob blob = db.get(index,global_label);
						blob.set(host_info,tokens);
						db.insert(blob,index);

					} //else {

					//	host_info=in;
					//}
				}
			}
		}
	};
};
<commit_msg>reader needs proper check for fifo<commit_after>#include "reader.hpp"

namespace clpr_d{

	reader::reader(clpr_proc_db & db){

		uint64_t global_label=0;
		while(1){

			ifstream pipe_in(CLPR_INPUT_PIPE);

			//FIXME
			//struct stat st;

			//fstat(pipe_in, &st);
			//if (!(S_ISFIFO(st.st_mode)))
			//	std::invalid_argument("bad or non-existant fifo");

			string in;

			//input:
			//pidstat -d -u -h -l -r -w -U  -v | grep -v root
			string host_info="?";
			string index;
			while (getline(pipe_in,in)){

				istringstream iss(in);
				vector<string> tokens{istream_iterator<string>{iss},
					istream_iterator<string>{}};

				//not a blank line nor a header
				if ((tokens.size()>0) && (tokens.size()!=23)){

					if (tokens.size()<=20){
						host_info=in;
					}
					if (tokens.size()>20){

						index = get_uid_blob_label(tokens);
						uid_blob blob = db.get(index,global_label);
						blob.set(host_info,tokens);
						db.insert(blob,index);

					} //else {

					//	host_info=in;
					//}
				}
			}
		}
	};
};
<|endoftext|>


<commit_before>#pragma once

#include <cinttypes>
#include <cstdint>
#include <string>
#include <vector>

#include "../include/processwarp/processwarp.h"

namespace processwarp {
  class Process;
  class Thread;

  /** 通信プロトコルのメジャーバージョン */
  static const int PROTOCOL_MAJOR_VERSION = 0;
  /** 通信プロトコルのマイナーバージョン */
  static const int PROTOCOL_MINOR_VERSION = 1;

  /** 仮想アドレス */
  typedef __pw_vm_ptr_t vaddr_t;

  static const unsigned int VMEMORY_RESERVE_MIN  = 8;
  static const unsigned int VMEMORY_RESERVE_BASE = 16;
  static const unsigned int VMEMORY_RESERVE_MAX  = 64;

  /**
   * VM組み込み関数に渡すパラメタ。
   */
  union BuiltinFuncParam {
    void* ptr;
    int64_t i64;
  };

  /** Post process type of builtin function. */
  enum BuiltinPost {
    BP_NORMAL, ///< Normally run next instruction.
    BP_RE_ENTRY, ///< Re-entry by stack deciding.
    BP_RETRY_LATER, ///< Retry the same instruction later other thread.
  };

  /**
   * Type definition of builtin function.
   * @param process 実行中のプロセス。
   * @param thread 実行中のスレッド。
   * @param p 固定パラメータ。
   * @param dst 戻り値格納先。
   * @param src 呼び出しパラメタ格納先。
   * @return スタック構造などを書き換え、execの再実行が必要な場合trueを戻す。
   */
  typedef BuiltinPost (*builtin_func_t)(Process& proc, Thread& thread, BuiltinFuncParam p,
					vaddr_t dst, std::vector<uint8_t>& src);

  /** システム中で扱う最長のuint */
  typedef std::uint64_t longest_uint_t;

  /** システム中で扱う最長のint */
  typedef std::uint64_t longest_int_t;

  /** 最長のuintを1うめしたもの */
  //static longest_uint_t LONGEST_UINT_FILL = 0xFFFFFFFFFFFFFFFF;

  /** ライブラリなど外部関数の関数の型 */
  typedef void (*external_func_t)();

  /** NULLのアドレス */
  static const vaddr_t VADDR_NULL = 0x00000000;
  /** アドレスに何も割り当てられていない状態の定数 */
  static const vaddr_t VADDR_NON  = 0x00000000;

  /** 命令 */
  typedef std::uint32_t instruction_t;

  /** スタックの作業用バッファサイズ */
  static const int STACK_BUFFER_SIZE = 2;

  /** オペランドの最大値 */
  static const instruction_t FILL_OPERAND = 0x03FFFFFF;
  static const instruction_t HEAD_OPERAND = 0x02000000;

  /** VM内のint相当のint型 */
  typedef __pw_vm_int_t vm_int_t;
  /** VM内のint相当のint型 */
  typedef __pw_vm_uint_t vm_uint_t;

  /** メモリの内容ごとに割り当てるアドレスの判定フラグ */
  enum AddrType : vaddr_t {
    AD_META     = 0x0000000000000000, ///< Meta data (possible changeing).
    AD_VALUE_08 = 0x1000000000000000, ///< 0〜255Byte空間
    AD_VALUE_16 = 0x2000000000000000, ///< 256〜65KByte空間
    AD_VALUE_24 = 0x3000000000000000, ///< 65K〜16MByte空間
    AD_VALUE_32 = 0x4000000000000000, ///< 16M〜4GByte空間
    AD_VALUE_40 = 0x5000000000000000, ///< 4G〜1TByte空間
    AD_VALUE_48 = 0x6000000000000000, ///< 1T〜256TByte空間
    AD_PROGRAM  = 0xF000000000000000, ///< Function, Type.
    AD_MASK     = 0xF000000000000000,
    AD_PTR      = 0x4000000100000000,
  };

  /** ID of data allocated in program area. */
  enum ProgramType : uint8_t {
    /** Normal function data. */
    PT_NORMAL   = 0x01,
    /** Built-in/Native function data. */
    PT_EXTERNAL = 0x02,
    /** Type data. */
    PT_TYPE     = 0xFF,
  };

  /** process-id */
  typedef std::string vpid_t;
  /** thread-id */
  typedef vm_uint_t vtid_t;
  /** all thread */
  static const vtid_t ALL_THREAD = 0;

  /** device-id */
  typedef std::string dev_id_t;
  /** To set when broadcast. */
  static const dev_id_t DEV_BROADCAST = "";

  /** trueを表す値 */
  static const uint8_t I8_TRUE = 0x1;
  /** falseを表す値 */
  static const uint8_t I8_FALSE = 0x0;

  /** Function type. */
  enum FuncType : uint8_t {
    /** Normal function type. */
    FC_NORMAL       = 0x01,
    /** Built-in function type. */
    FC_BUILTIN      = 0x02,
    /** Native funcion type. */
    FC_NATIVE       = 0x03,
  };

  /** 型の種類 */
  enum TypeKind : uint8_t {
    TK_BASIC        = 0x01, ///< 基本型
    TK_STRUCT       = 0x02, ///< 構造体
    TK_ARRAY        = 0x03, ///< 配列
    TK_VECTOR       = 0x04, ///< vector
  };

  /** 基本型に予約するアドレス */
  enum BasicType : vaddr_t {
    TY_VOID     = 0x0000000000000001, ///< void型
    TY_POINTER  = 0x0000000000000002, ///< ポインタ
    TY_FUNCTION = 0x0000000000000003, ///< 関数

    TY_UI8      = 0x0000000000000011, ///< 8bit整数型
    TY_UI16     = 0x0000000000000012, ///< 16bit整数型
    TY_UI32     = 0x0000000000000013, ///< 32bit整数型
    TY_UI64     = 0x0000000000000014, ///< 64bit整数型
    TY_UI128    = 0x0000000000000015, ///< 128bit整数型
    TY_UI256    = 0x0000000000000016, ///< 256bit整数型
    TY_UI512    = 0x0000000000000017, ///< 512bit整数型

    TY_SI8      = 0x0000000000000021, ///< 8bit整数型
    TY_SI16     = 0x0000000000000022, ///< 16bit整数型
    TY_SI32     = 0x0000000000000023, ///< 32bit整数型
    TY_SI64     = 0x0000000000000024, ///< 64bit整数型
    TY_SI128    = 0x0000000000000025, ///< 128bit整数型
    TY_SI256    = 0x0000000000000026, ///< 256bit整数型
    TY_SI512    = 0x0000000000000027, ///< 512bit整数型

    // TY_F16
    TY_F32      = 0x0000000000000032, ///< 単精度浮動小数点型
    TY_F64      = 0x0000000000000033, ///< 倍精度浮動小数点型
    // TY_F80
    TY_F128     = 0x0000000000000035, ///< 四倍精度浮動小数点型
    TY_MAX      = 0x00000000000000FF, ///< 基本型最大値
  };

  /** 仮想マシンのOpcode */
  enum Opcode : uint8_t {
    // ----------------------------------------------------------------------
    // name		args	description
    // ----------------------------------------------------------------------
    NOP = 0,
      EXTRA,
      CALL,
      TAILCALL,
      RETURN,
      SET_TYPE,
      SET_OUTPUT,
      SET_VALUE,
      SET_OV_PTR,
      ADD,
      SUB, // 10
      MUL,
      DIV,
      REM,
      SHL,
      SHR,
      AND,
      NAND,
      OR,
      XOR,
      MAX, // 20
      MIN,
      SET,
      SET_PTR,
      SET_ADR,
      SET_ALIGN,
      ADD_ADR,
      MUL_ADR,
      GET_ADR,
      LOAD,
      STORE, // 30
      CMPXCHG,
      ALLOCA,
      TEST,
      TEST_EQ,
      JUMP,
      INDIRECT_JUMP,
      PHI,
      TYPE_CAST,
      BIT_CAST,
      EQUAL, // 40
      NOT_EQUAL,
      GREATER,
      GREATER_EQUAL,
      NOT_NANS,
      OR_NANS,
      SELECT,
      SHUFFLE,
      VA_ARG,
  };
}
<commit_msg>change BasicType address because type assign to AD_PROGRAM area<commit_after>#pragma once

#include <cinttypes>
#include <cstdint>
#include <string>
#include <vector>

#include "../include/processwarp/processwarp.h"

namespace processwarp {
  class Process;
  class Thread;

  /** 通信プロトコルのメジャーバージョン */
  static const int PROTOCOL_MAJOR_VERSION = 0;
  /** 通信プロトコルのマイナーバージョン */
  static const int PROTOCOL_MINOR_VERSION = 1;

  /** 仮想アドレス */
  typedef __pw_vm_ptr_t vaddr_t;

  static const unsigned int VMEMORY_RESERVE_MIN  = 8;
  static const unsigned int VMEMORY_RESERVE_BASE = 16;
  static const unsigned int VMEMORY_RESERVE_MAX  = 64;

  /**
   * VM組み込み関数に渡すパラメタ。
   */
  union BuiltinFuncParam {
    void* ptr;
    int64_t i64;
  };

  /** Post process type of builtin function. */
  enum BuiltinPost {
    BP_NORMAL, ///< Normally run next instruction.
    BP_RE_ENTRY, ///< Re-entry by stack deciding.
    BP_RETRY_LATER, ///< Retry the same instruction later other thread.
  };

  /**
   * Type definition of builtin function.
   * @param process 実行中のプロセス。
   * @param thread 実行中のスレッド。
   * @param p 固定パラメータ。
   * @param dst 戻り値格納先。
   * @param src 呼び出しパラメタ格納先。
   * @return スタック構造などを書き換え、execの再実行が必要な場合trueを戻す。
   */
  typedef BuiltinPost (*builtin_func_t)(Process& proc, Thread& thread, BuiltinFuncParam p,
					vaddr_t dst, std::vector<uint8_t>& src);

  /** システム中で扱う最長のuint */
  typedef std::uint64_t longest_uint_t;

  /** システム中で扱う最長のint */
  typedef std::uint64_t longest_int_t;

  /** 最長のuintを1うめしたもの */
  //static longest_uint_t LONGEST_UINT_FILL = 0xFFFFFFFFFFFFFFFF;

  /** ライブラリなど外部関数の関数の型 */
  typedef void (*external_func_t)();

  /** NULLのアドレス */
  static const vaddr_t VADDR_NULL = 0x00000000;
  /** アドレスに何も割り当てられていない状態の定数 */
  static const vaddr_t VADDR_NON  = 0x00000000;

  /** 命令 */
  typedef std::uint32_t instruction_t;

  /** スタックの作業用バッファサイズ */
  static const int STACK_BUFFER_SIZE = 2;

  /** オペランドの最大値 */
  static const instruction_t FILL_OPERAND = 0x03FFFFFF;
  static const instruction_t HEAD_OPERAND = 0x02000000;

  /** VM内のint相当のint型 */
  typedef __pw_vm_int_t vm_int_t;
  /** VM内のint相当のint型 */
  typedef __pw_vm_uint_t vm_uint_t;

  /** メモリの内容ごとに割り当てるアドレスの判定フラグ */
  enum AddrType : vaddr_t {
    AD_META     = 0x0000000000000000, ///< Meta data (possible changeing).
    AD_VALUE_08 = 0x1000000000000000, ///< 0〜255Byte空間
    AD_VALUE_16 = 0x2000000000000000, ///< 256〜65KByte空間
    AD_VALUE_24 = 0x3000000000000000, ///< 65K〜16MByte空間
    AD_VALUE_32 = 0x4000000000000000, ///< 16M〜4GByte空間
    AD_VALUE_40 = 0x5000000000000000, ///< 4G〜1TByte空間
    AD_VALUE_48 = 0x6000000000000000, ///< 1T〜256TByte空間
    AD_PROGRAM  = 0xF000000000000000, ///< Function, Type.
    AD_MASK     = 0xF000000000000000,
    AD_PTR      = 0x4000000100000000,
  };

  /** ID of data allocated in program area. */
  enum ProgramType : uint8_t {
    /** Normal function data. */
    PT_NORMAL   = 0x01,
    /** Built-in/Native function data. */
    PT_EXTERNAL = 0x02,
    /** Type data. */
    PT_TYPE     = 0xFF,
  };

  /** process-id */
  typedef std::string vpid_t;
  /** thread-id */
  typedef vm_uint_t vtid_t;
  /** all thread */
  static const vtid_t ALL_THREAD = 0;

  /** device-id */
  typedef std::string dev_id_t;
  /** To set when broadcast. */
  static const dev_id_t DEV_BROADCAST = "";

  /** trueを表す値 */
  static const uint8_t I8_TRUE = 0x1;
  /** falseを表す値 */
  static const uint8_t I8_FALSE = 0x0;

  /** Function type. */
  enum FuncType : uint8_t {
    /** Normal function type. */
    FC_NORMAL       = 0x01,
    /** Built-in function type. */
    FC_BUILTIN      = 0x02,
    /** Native funcion type. */
    FC_NATIVE       = 0x03,
  };

  /** 型の種類 */
  enum TypeKind : uint8_t {
    TK_BASIC        = 0x01, ///< 基本型
    TK_STRUCT       = 0x02, ///< 構造体
    TK_ARRAY        = 0x03, ///< 配列
    TK_VECTOR       = 0x04, ///< vector
  };

  /** 基本型に予約するアドレス */
  enum BasicType : vaddr_t {
    TY_VOID     = 0xF000000000000001, ///< void型
    TY_POINTER  = 0xF000000000000002, ///< ポインタ
    TY_FUNCTION = 0xF000000000000003, ///< 関数

    TY_UI8      = 0xF000000000000011, ///< 8bit整数型
    TY_UI16     = 0xF000000000000012, ///< 16bit整数型
    TY_UI32     = 0xF000000000000013, ///< 32bit整数型
    TY_UI64     = 0xF000000000000014, ///< 64bit整数型
    TY_UI128    = 0xF000000000000015, ///< 128bit整数型
    TY_UI256    = 0xF000000000000016, ///< 256bit整数型
    TY_UI512    = 0xF000000000000017, ///< 512bit整数型

    TY_SI8      = 0xF000000000000021, ///< 8bit整数型
    TY_SI16     = 0xF000000000000022, ///< 16bit整数型
    TY_SI32     = 0xF000000000000023, ///< 32bit整数型
    TY_SI64     = 0xF000000000000024, ///< 64bit整数型
    TY_SI128    = 0xF000000000000025, ///< 128bit整数型
    TY_SI256    = 0xF000000000000026, ///< 256bit整数型
    TY_SI512    = 0xF000000000000027, ///< 512bit整数型

    // TY_F16
    TY_F32      = 0xF000000000000032, ///< 単精度浮動小数点型
    TY_F64      = 0xF000000000000033, ///< 倍精度浮動小数点型
    // TY_F80
    TY_F128     = 0xF000000000000035, ///< 四倍精度浮動小数点型
    TY_MAX      = 0xF0000000000000FF, ///< 基本型最大値
  };

  /** 仮想マシンのOpcode */
  enum Opcode : uint8_t {
    // ----------------------------------------------------------------------
    // name		args	description
    // ----------------------------------------------------------------------
    NOP = 0,
      EXTRA,
      CALL,
      TAILCALL,
      RETURN,
      SET_TYPE,
      SET_OUTPUT,
      SET_VALUE,
      SET_OV_PTR,
      ADD,
      SUB, // 10
      MUL,
      DIV,
      REM,
      SHL,
      SHR,
      AND,
      NAND,
      OR,
      XOR,
      MAX, // 20
      MIN,
      SET,
      SET_PTR,
      SET_ADR,
      SET_ALIGN,
      ADD_ADR,
      MUL_ADR,
      GET_ADR,
      LOAD,
      STORE, // 30
      CMPXCHG,
      ALLOCA,
      TEST,
      TEST_EQ,
      JUMP,
      INDIRECT_JUMP,
      PHI,
      TYPE_CAST,
      BIT_CAST,
      EQUAL, // 40
      NOT_EQUAL,
      GREATER,
      GREATER_EQUAL,
      NOT_NANS,
      OR_NANS,
      SELECT,
      SHUFFLE,
      VA_ARG,
  };
}
<|endoftext|>


<commit_before>//=======================================================================
// Copyright Baptiste Wicht 2013-2016.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include <types.hpp>
#include <unique_ptr.hpp>
#include <algorithms.hpp>

#include <tlib/errors.hpp>

#include "fs/sysfs.hpp"

#include "console.hpp"
#include "assert.hpp"

namespace {

struct sys_value {
    std::string name;
    std::string _value;
    sysfs::dynamic_fun_t fun = nullptr;

    sys_value(){}
    sys_value(std::string name, std::string value) : name(name), _value(value){
        //Nothing else to init
    }

    sys_value(std::string name, sysfs::dynamic_fun_t fun) : name(name), fun(fun){
        //Nothing else to init
    }

    std::string value() const {
        if(fun){
            return fun();
        } else {
            return _value;
        }
    }
};

struct sys_folder {
    std::string name;
    std::vector<sys_folder> folders;
    std::vector<sys_value> values;

    sys_folder(){}

    sys_folder(std::string name) : name(name) {
        //Nothing else to init
    }
};

std::vector<sys_folder> root_folders;

sys_folder& find_root_folder(const path& mount_point){
    thor_assert(mount_point.is_sub_root(), "Unsupported mount point");

    for(auto& sys_folder : root_folders){
        if(sys_folder.name == mount_point.sub_root_name()){
            return sys_folder;
        }
    }

    root_folders.emplace_back(mount_point.sub_root_name());

    return root_folders.back();
}

sys_folder& find_folder(sys_folder& root, const path& file_path, size_t i, size_t last){
    auto& name = file_path[i];

    for(auto& folder : root.folders){
        if(folder.name == name){
            if(i == last - 1){
                return folder;
            } else {
                return find_folder(folder, file_path, i + 1, last);
            }
        }
    }

    root.folders.emplace_back(name);

    if(i == last - 1){
        return root.folders.back();
    } else {
        return find_folder(root.folders.back(), file_path, i + 1, last);
    }
}

bool exists_folder(sys_folder& root, const path& file_path, size_t i, size_t last){
    auto& name = file_path[i];

    for(auto& folder : root.folders){
        if(folder.name == name){
            if(i == last - 1){
                return true;
            } else {
                return exists_folder(folder, file_path, i + 1, last);
            }
        }
    }

    return false;
}

size_t get_file(const sys_folder& folder, const path& file_path, vfs::file& f){
    for(auto& file : folder.folders){
        if(file.name == file_path.base_name()){
            f.file_name = file.name;
            f.directory = true;
            f.hidden = false;
            f.system = false;
            f.size = 0;

            return 0;
        }
    }

    for(auto& file : folder.values){
        if(file.name == file_path.base_name()){
            f.file_name = file.name;
            f.directory = false;
            f.hidden = false;
            f.system = false;
            f.size = file.value().size();

            return 0;
        }
    }

    return std::ERROR_NOT_EXISTS;
}

size_t ls(const sys_folder& folder, std::vector<vfs::file>& contents){
    for(auto& file : folder.folders){
        vfs::file f;
        f.file_name = file.name;
        f.directory = true;
        f.hidden = false;
        f.system = false;
        f.size = 0;
        contents.push_back(f);
    }

    for(auto& file : folder.values){
        vfs::file f;
        f.file_name = file.name;
        f.directory = false;
        f.hidden = false;
        f.system = false;
        f.size = file.value().size();
        contents.push_back(f);
    }

    return 0;
}

size_t read(const sys_folder& folder, const path& file_path, char* buffer, size_t count, size_t offset, size_t& read){
    for(auto& file : folder.values){
        if(file.name == file_path.base_name()){
            auto value = file.value();

            if(offset > value.size()){
                return std::ERROR_INVALID_OFFSET;
            }

            read = std::min(count, value.size() - offset);
            std::copy_n(value.c_str() + offset, read, buffer);

            return 0;
        }
    }

    for(auto& file : folder.folders){
        if(file.name == file_path.base_name()){
            return std::ERROR_DIRECTORY;
        }
    }

    return std::ERROR_NOT_EXISTS;
}

void set_value(sys_folder& folder, const std::string& name, const std::string& value){
    for(auto& v : folder.values){
        if(v.name == name){
            v._value = value;
            return;
        }
    }

    folder.values.emplace_back(name, value);
}

void set_value(sys_folder& folder, const std::string& name, sysfs::dynamic_fun_t fun){
    for(auto& v : folder.values){
        if(v.name == name){
            v.fun = fun;
            return;
        }
    }

    folder.values.emplace_back(name, fun);
}

void delete_value(sys_folder& folder, const std::string& name){
    for(size_t i = 0; i < folder.values.size(); ++i){
        auto& v = folder.values[i];

        if(v.name == name){
            folder.values.erase(i);
            break;
        }
    }
}

void delete_folder(sys_folder& folder, const std::string& name){
    for(size_t i = 0; i < folder.folders.size(); ++i){
        auto& v = folder.folders[i];

        if(v.name == name){
            folder.folders.erase(i);
            break;
        }
    }
}

} //end of anonymous namespace

sysfs::sysfs_file_system::sysfs_file_system(path mp) : mount_point(mp) {
    //Nothing to init
}

sysfs::sysfs_file_system::~sysfs_file_system(){
    //Nothing to delete
}

size_t sysfs::sysfs_file_system::get_file(const path& file_path, vfs::file& f){
    auto& root_folder = find_root_folder(mount_point);

    if(file_path.is_root()){
        f.file_name = "/";
        f.directory = true;
        f.hidden = false;
        f.system = false;
        f.size = 0;

        return 0;
    } else if(file_path.size() == 2){
        return ::get_file(root_folder, file_path, f);
    } else {
        if(exists_folder(root_folder, file_path, 1, file_path.size() - 1)){
            auto& folder = find_folder(root_folder, file_path, 1, file_path.size() - 1);

            return ::get_file(folder, file_path, f);
        }

        return std::ERROR_NOT_EXISTS;
    }
}

size_t sysfs::sysfs_file_system::read(const path& file_path, char* buffer, size_t count, size_t offset, size_t& read){
    auto& root_folder = find_root_folder(mount_point);

    if(file_path.is_root()){
        return std::ERROR_DIRECTORY;
    } else if(file_path.size() == 2){
        return ::read(root_folder, file_path, buffer, count, offset, read);
    } else {
        if(exists_folder(root_folder, file_path, 1, file_path.size() - 1)){
            auto& folder = find_folder(root_folder, file_path, 1, file_path.size() - 1);

            return ::read(folder, file_path, buffer, count, offset, read);
        }

        return std::ERROR_NOT_EXISTS;
    }
}

size_t sysfs::sysfs_file_system::write(const path&, const char*, size_t, size_t, size_t&){
    return std::ERROR_PERMISSION_DENIED;
}

size_t sysfs::sysfs_file_system::clear(const path&, size_t, size_t, size_t&){
    return std::ERROR_PERMISSION_DENIED;
}

size_t sysfs::sysfs_file_system::truncate(const path&, size_t){
    return std::ERROR_PERMISSION_DENIED;
}

size_t sysfs::sysfs_file_system::ls(const path& file_path, std::vector<vfs::file>& contents){
    auto& root_folder = find_root_folder(mount_point);

    if(file_path.is_root()){
        return ::ls(root_folder, contents);
    } else {
        if(exists_folder(root_folder, file_path, 1, file_path.size())){
            auto& folder = find_folder(root_folder, file_path, 1, file_path.size());

            return ::ls(folder, contents);
        }

        return std::ERROR_NOT_EXISTS;
    }
}

size_t sysfs::sysfs_file_system::touch(const path& ){
    return std::ERROR_PERMISSION_DENIED;
}

size_t sysfs::sysfs_file_system::mkdir(const path& ){
    return std::ERROR_PERMISSION_DENIED;
}

size_t sysfs::sysfs_file_system::rm(const path& ){
    return std::ERROR_PERMISSION_DENIED;
}

size_t sysfs::sysfs_file_system::statfs(vfs::statfs_info& file){
    file.total_size = 0;
    file.free_size = 0;

    return 0;
}

void sysfs::set_constant_value(const path& mount_point, const path& file_path, const std::string& value){
    auto& root_folder = find_root_folder(mount_point);

    if(file_path.size() == 2){
        ::set_value(root_folder, file_path.base_name(), value);
    } else {
        auto& folder = find_folder(root_folder, file_path, 1, file_path.size() - 1);
        ::set_value(folder, file_path.base_name(), value);
    }
}

void sysfs::set_dynamic_value(const path& mount_point, const path& file_path, dynamic_fun_t fun){
    auto& root_folder = find_root_folder(mount_point);

    if(file_path.size() == 2){
        ::set_value(root_folder, file_path.base_name(), fun);
    } else {
        auto& folder = find_folder(root_folder, file_path, 1, file_path.size() - 1);
        ::set_value(folder, file_path.base_name(), fun);
    }
}

void sysfs::delete_value(const path& mount_point, const path& file_path){
    auto& root_folder = find_root_folder(mount_point);

    if(file_path.size() == 2){
        ::delete_value(root_folder, file_path.base_name());
    } else {
        auto& folder = find_folder(root_folder, file_path, 1, file_path.size() - 1);

        ::delete_value(folder, file_path.base_name());
    }
}

void sysfs::delete_folder(const path& mount_point, const path& file_path){
    auto& root_folder = find_root_folder(mount_point);

    if(file_path.size() == 2){
        ::delete_folder(root_folder, file_path.base_name());
    } else {
        auto& folder = find_folder(root_folder, file_path, 1, file_path.size() - 1);

        ::delete_folder(folder, file_path.base_name());
    }
}
<commit_msg>Reformat<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2013-2016.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include <types.hpp>
#include <unique_ptr.hpp>
#include <algorithms.hpp>

#include <tlib/errors.hpp>

#include "fs/sysfs.hpp"

#include "console.hpp"
#include "assert.hpp"

namespace {

struct sys_value {
    std::string name;
    std::string _value;
    sysfs::dynamic_fun_t fun = nullptr;

    sys_value() {}
    sys_value(std::string name, std::string value)
            : name(name), _value(value) {
        //Nothing else to init
    }

    sys_value(std::string name, sysfs::dynamic_fun_t fun)
            : name(name), fun(fun) {
        //Nothing else to init
    }

    std::string value() const {
        if (fun) {
            return fun();
        } else {
            return _value;
        }
    }
};

struct sys_folder {
    std::string name;
    std::vector<sys_folder> folders;
    std::vector<sys_value> values;

    sys_folder() {}

    sys_folder(std::string name)
            : name(name) {
        //Nothing else to init
    }
};

std::vector<sys_folder> root_folders;

sys_folder& find_root_folder(const path& mount_point) {
    thor_assert(mount_point.is_sub_root(), "Unsupported mount point");

    for (auto& sys_folder : root_folders) {
        if (sys_folder.name == mount_point.sub_root_name()) {
            return sys_folder;
        }
    }

    root_folders.emplace_back(mount_point.sub_root_name());

    return root_folders.back();
}

sys_folder& find_folder(sys_folder& root, const path& file_path, size_t i, size_t last){
    auto& name = file_path[i];

    for (auto& folder : root.folders) {
        if (folder.name == name) {
            if (i == last - 1) {
                return folder;
            } else {
                return find_folder(folder, file_path, i + 1, last);
            }
        }
    }

    root.folders.emplace_back(name);

    if (i == last - 1) {
        return root.folders.back();
    } else {
        return find_folder(root.folders.back(), file_path, i + 1, last);
    }
}

bool exists_folder(sys_folder& root, const path& file_path, size_t i, size_t last) {
    auto& name = file_path[i];

    for (auto& folder : root.folders) {
        if (folder.name == name) {
            if (i == last - 1) {
                return true;
            } else {
                return exists_folder(folder, file_path, i + 1, last);
            }
        }
    }

    return false;
}

size_t get_file(const sys_folder& folder, const path& file_path, vfs::file& f) {
    for (auto& file : folder.folders) {
        if (file.name == file_path.base_name()) {
            f.file_name = file.name;
            f.directory = true;
            f.hidden    = false;
            f.system    = false;
            f.size      = 0;

            return 0;
        }
    }

    for (auto& file : folder.values) {
        if (file.name == file_path.base_name()) {
            f.file_name = file.name;
            f.directory = false;
            f.hidden    = false;
            f.system    = false;
            f.size      = file.value().size();

            return 0;
        }
    }

    return std::ERROR_NOT_EXISTS;
}

size_t ls(const sys_folder& folder, std::vector<vfs::file>& contents) {
    for (auto& file : folder.folders) {
        vfs::file f;

        f.file_name = file.name;
        f.directory = true;
        f.hidden    = false;
        f.system    = false;
        f.size      = 0;

        contents.push_back(f);
    }

    for (auto& file : folder.values) {
        vfs::file f;

        f.file_name = file.name;
        f.directory = false;
        f.hidden    = false;
        f.system    = false;
        f.size      = file.value().size();

        contents.push_back(f);
    }

    return 0;
}

size_t read(const sys_folder& folder, const path& file_path, char* buffer, size_t count, size_t offset, size_t& read) {
    for (auto& file : folder.values) {
        if (file.name == file_path.base_name()) {
            auto value = file.value();

            if (offset > value.size()) {
                return std::ERROR_INVALID_OFFSET;
            }

            read = std::min(count, value.size() - offset);
            std::copy_n(value.c_str() + offset, read, buffer);

            return 0;
        }
    }

    for (auto& file : folder.folders) {
        if (file.name == file_path.base_name()) {
            return std::ERROR_DIRECTORY;
        }
    }

    return std::ERROR_NOT_EXISTS;
}

void set_value(sys_folder& folder, const std::string& name, const std::string& value) {
    for (auto& v : folder.values) {
        if (v.name == name) {
            v._value = value;
            return;
        }
    }

    folder.values.emplace_back(name, value);
}

void set_value(sys_folder& folder, const std::string& name, sysfs::dynamic_fun_t fun) {
    for (auto& v : folder.values) {
        if (v.name == name) {
            v.fun = fun;
            return;
        }
    }

    folder.values.emplace_back(name, fun);
}

void delete_value(sys_folder& folder, const std::string& name) {
    for (size_t i = 0; i < folder.values.size(); ++i) {
        auto& v = folder.values[i];

        if (v.name == name) {
            folder.values.erase(i);
            break;
        }
    }
}

void delete_folder(sys_folder& folder, const std::string& name) {
    for (size_t i = 0; i < folder.folders.size(); ++i) {
        auto& v = folder.folders[i];

        if (v.name == name) {
            folder.folders.erase(i);
            break;
        }
    }
}

} //end of anonymous namespace

sysfs::sysfs_file_system::sysfs_file_system(path mp)
        : mount_point(mp) {
    //Nothing to init
}

sysfs::sysfs_file_system::~sysfs_file_system() {
    //Nothing to delete
}

size_t sysfs::sysfs_file_system::get_file(const path& file_path, vfs::file& f) {
    auto& root_folder = find_root_folder(mount_point);

    if (file_path.is_root()) {
        f.file_name = "/";
        f.directory = true;
        f.hidden    = false;
        f.system    = false;
        f.size      = 0;

        return 0;
    } else if (file_path.size() == 2) {
        return ::get_file(root_folder, file_path, f);
    } else {
        if (exists_folder(root_folder, file_path, 1, file_path.size() - 1)) {
            auto& folder = find_folder(root_folder, file_path, 1, file_path.size() - 1);

            return ::get_file(folder, file_path, f);
        }

        return std::ERROR_NOT_EXISTS;
    }
}

size_t sysfs::sysfs_file_system::read(const path& file_path, char* buffer, size_t count, size_t offset, size_t& read) {
    auto& root_folder = find_root_folder(mount_point);

    if (file_path.is_root()) {
        return std::ERROR_DIRECTORY;
    } else if (file_path.size() == 2) {
        return ::read(root_folder, file_path, buffer, count, offset, read);
    } else {
        if (exists_folder(root_folder, file_path, 1, file_path.size() - 1)) {
            auto& folder = find_folder(root_folder, file_path, 1, file_path.size() - 1);

            return ::read(folder, file_path, buffer, count, offset, read);
        }

        return std::ERROR_NOT_EXISTS;
    }
}

size_t sysfs::sysfs_file_system::write(const path&, const char*, size_t, size_t, size_t&) {
    return std::ERROR_PERMISSION_DENIED;
}

size_t sysfs::sysfs_file_system::clear(const path&, size_t, size_t, size_t&) {
    return std::ERROR_PERMISSION_DENIED;
}

size_t sysfs::sysfs_file_system::truncate(const path&, size_t) {
    return std::ERROR_PERMISSION_DENIED;
}

size_t sysfs::sysfs_file_system::ls(const path& file_path, std::vector<vfs::file>& contents) {
    auto& root_folder = find_root_folder(mount_point);

    if (file_path.is_root()) {
        return ::ls(root_folder, contents);
    } else {
        if (exists_folder(root_folder, file_path, 1, file_path.size())) {
            auto& folder = find_folder(root_folder, file_path, 1, file_path.size());

            return ::ls(folder, contents);
        }

        return std::ERROR_NOT_EXISTS;
    }
}

size_t sysfs::sysfs_file_system::touch(const path&) {
    return std::ERROR_PERMISSION_DENIED;
}

size_t sysfs::sysfs_file_system::mkdir(const path&) {
    return std::ERROR_PERMISSION_DENIED;
}

size_t sysfs::sysfs_file_system::rm(const path&) {
    return std::ERROR_PERMISSION_DENIED;
}

size_t sysfs::sysfs_file_system::statfs(vfs::statfs_info& file) {
    file.total_size = 0;
    file.free_size  = 0;

    return 0;
}

void sysfs::set_constant_value(const path& mount_point, const path& file_path, const std::string& value) {
    auto& root_folder = find_root_folder(mount_point);

    if (file_path.size() == 2) {
        ::set_value(root_folder, file_path.base_name(), value);
    } else {
        auto& folder = find_folder(root_folder, file_path, 1, file_path.size() - 1);
        ::set_value(folder, file_path.base_name(), value);
    }
}

void sysfs::set_dynamic_value(const path& mount_point, const path& file_path, dynamic_fun_t fun) {
    auto& root_folder = find_root_folder(mount_point);

    if (file_path.size() == 2) {
        ::set_value(root_folder, file_path.base_name(), fun);
    } else {
        auto& folder = find_folder(root_folder, file_path, 1, file_path.size() - 1);
        ::set_value(folder, file_path.base_name(), fun);
    }
}

void sysfs::delete_value(const path& mount_point, const path& file_path) {
    auto& root_folder = find_root_folder(mount_point);

    if (file_path.size() == 2) {
        ::delete_value(root_folder, file_path.base_name());
    } else {
        auto& folder = find_folder(root_folder, file_path, 1, file_path.size() - 1);

        ::delete_value(folder, file_path.base_name());
    }
}

void sysfs::delete_folder(const path& mount_point, const path& file_path) {
    auto& root_folder = find_root_folder(mount_point);

    if (file_path.size() == 2) {
        ::delete_folder(root_folder, file_path.base_name());
    } else {
        auto& folder = find_folder(root_folder, file_path, 1, file_path.size() - 1);

        ::delete_folder(folder, file_path.base_name());
    }
}
<|endoftext|>


<commit_before>#ifndef __STAN__MATH__MATRIX__COL_HPP__
#define __STAN__MATH__MATRIX__COL_HPP__

#include <stan/math/matrix.hpp>

namespace stan {
  namespace math {

    /**
     * Return the specified column of the specified matrix
     * using start-at-1 indexing.
     *
     * This is equivalent to calling m.col(i - 1) and
     * assigning the resulting template expression to a column vector.
     *
     * @param m Matrix.
     * @param j Column index (count from 1).
     * @return Specified column of the matrix.
     */
    template <typename T>
    inline
    Eigen::Matrix<T,Eigen::Dynamic,1>
    col(const Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic>& m,
        size_t j) {
      validate_column_index(m,j,"col");
      return m.col(j - 1);
    }

  }
}
#endif
<commit_msg>moving validate_column_index out of stan/math/matrix.hpp<commit_after>#ifndef __STAN__MATH__MATRIX__COL_HPP__
#define __STAN__MATH__MATRIX__COL_HPP__

#include <stan/math/matrix.hpp>
#include <stan/math/matrix/validate_column_index.hpp>

namespace stan {
  namespace math {

    /**
     * Return the specified column of the specified matrix
     * using start-at-1 indexing.
     *
     * This is equivalent to calling m.col(i - 1) and
     * assigning the resulting template expression to a column vector.
     *
     * @param m Matrix.
     * @param j Column index (count from 1).
     * @return Specified column of the matrix.
     */
    template <typename T>
    inline
    Eigen::Matrix<T,Eigen::Dynamic,1>
    col(const Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic>& m,
        size_t j) {
      validate_column_index(m,j,"col");
      return m.col(j - 1);
    }

  }
}
#endif
<|endoftext|>


<commit_before>// Xerus - A General Purpose Tensor Library
// Copyright (C) 2014-2016 Benjamin Huber and Sebastian Wolf.
//
// Xerus is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License,
// or (at your option) any later version.
//
// Xerus is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with Xerus. If not, see <http://www.gnu.org/licenses/>.
//
// For further information on Xerus visit https://libXerus.org
// or contact us at contact@libXerus.org.

/**
 * @file
 * @brief Implementation of the log-buffer functionality and declaration of global logging objects.
 */

#include <time.h>

#ifdef LOG_BUFFER_
    #include <fstream>
#endif

#include <xerus/misc/namedLogger.h>

namespace xerus {
    namespace misc {
        namespace internal {
            //Look if Log shall be streamed into a file
			std::ofstream fileStream ( "error.log" , std::ofstream::app | std::ofstream::out);

                std::mutex namedLoggerMutex;
                std::string logFilePrefix;
                bool silenced = false;
				std::chrono::system_clock::time_point programStartTime;
				static void __attribute__((constructor)) initTime() {
					programStartTime = std::chrono::system_clock::now();
				}

				namespace buffer {
					std::stringstream current;
					std::stringstream old;

					void checkSwitch() {
						if (current.str().size() > 1024*1024) {
							old = std::move(current);
							current = std::stringstream();
						}
					}

					void dump_log(std::string _comment)  {
						std::string name = std::string("errors/") + logFilePrefix + std::to_string(std::time(nullptr)) + ".txt";
						std::ofstream out(name, std::ofstream::out);
						out << "Error: " << _comment << std::endl << std::endl;

						// Get callstack
						out << "-------------------------------------------------------------------------------" << std::endl
							<< "  Callstack : " << std::endl
							<< "-------------------------------------------------------------------------------" << std::endl
							<< get_call_stack() << std::endl;

						// Output namedLogger
						current.flush();
						old.flush();
						out << "-------------------------------------------------------------------------------" << std::endl
							<< "  last " << (current.str().size() + old.str().size()) << " bytes of log:" << std::endl
							<< "-------------------------------------------------------------------------------" << std::endl
							<< current.str() << old.str() << "horst" << std::endl;
						out.close();
					}
				}
        }
    }
}
<commit_msg>closes #165 swapping log buffers without move semantics for gcc < 5.0<commit_after>// Xerus - A General Purpose Tensor Library
// Copyright (C) 2014-2016 Benjamin Huber and Sebastian Wolf.
//
// Xerus is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License,
// or (at your option) any later version.
//
// Xerus is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with Xerus. If not, see <http://www.gnu.org/licenses/>.
//
// For further information on Xerus visit https://libXerus.org
// or contact us at contact@libXerus.org.

/**
 * @file
 * @brief Implementation of the log-buffer functionality and declaration of global logging objects.
 */

#include <time.h>

#ifdef LOG_BUFFER_
    #include <fstream>
#endif

#include <xerus/misc/namedLogger.h>

namespace xerus {
    namespace misc {
        namespace internal {
            //Look if Log shall be streamed into a file
			std::ofstream fileStream ( "error.log" , std::ofstream::app | std::ofstream::out);

                std::mutex namedLoggerMutex;
                std::string logFilePrefix;
                bool silenced = false;
				std::chrono::system_clock::time_point programStartTime;
				static void __attribute__((constructor)) initTime() {
					programStartTime = std::chrono::system_clock::now();
				}

				namespace buffer {
					std::stringstream current;
					std::stringstream old;

					void checkSwitch() {
						if (current.str().size() > 1024*1024) {
							#if defined(__GNUC__) && __GNUC__ < 5
								old.clear();
								old.str(current.str());
								current.clear();
							#else
								old = std::move(current);
								current.clear();
							#endif
						}
					}

					void dump_log(std::string _comment)  {
						std::string name = std::string("errors/") + logFilePrefix + std::to_string(std::time(nullptr)) + ".txt";
						std::ofstream out(name, std::ofstream::out);
						out << "Error: " << _comment << std::endl << std::endl;

						// Get callstack
						out << "-------------------------------------------------------------------------------" << std::endl
							<< "  Callstack : " << std::endl
							<< "-------------------------------------------------------------------------------" << std::endl
							<< get_call_stack() << std::endl;

						// Output namedLogger
						current.flush();
						old.flush();
						out << "-------------------------------------------------------------------------------" << std::endl
							<< "  last " << (current.str().size() + old.str().size()) << " bytes of log:" << std::endl
							<< "-------------------------------------------------------------------------------" << std::endl
							<< current.str() << old.str() << "horst" << std::endl;
						out.close();
					}
				}
        }
    }
}
<|endoftext|>