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

#include "formatter.hpp"
#include "trace_model.hpp"

namespace Trace {

Call::~Call() {
    for (unsigned i = 0; i < args.size(); ++i) {
        delete args[i];
    }

    if (ret) {
        delete ret;
    }
}

Struct::~Struct() {
    for (std::vector<Value *>::iterator it = members.begin(); it != members.end(); ++it) {
        delete *it;
    }
}

Array::~Array() {
    for (std::vector<Value *>::iterator it = values.begin(); it != values.end(); ++it) {
        delete *it;
    }
}

void Null::visit(Visitor &visitor) { visitor.visit(this); }
void Bool::visit(Visitor &visitor) { visitor.visit(this); }
void SInt::visit(Visitor &visitor) { visitor.visit(this); }
void UInt::visit(Visitor &visitor) { visitor.visit(this); }
void Float::visit(Visitor &visitor) { visitor.visit(this); }
void String::visit(Visitor &visitor) { visitor.visit(this); }
void Enum::visit(Visitor &visitor) { visitor.visit(this); }
void Bitmask::visit(Visitor &visitor) { visitor.visit(this); }
void Struct::visit(Visitor &visitor) { visitor.visit(this); }
void Array::visit(Visitor &visitor) { visitor.visit(this); }
void Blob::visit(Visitor &visitor) { visitor.visit(this); }
void Pointer::visit(Visitor &visitor) { visitor.visit(this); }

class Dumper : public Visitor
{
protected:
    std::ostream &os;
    Formatter::Formatter *formatter;
    Formatter::Attribute *normal;
    Formatter::Attribute *bold;
    Formatter::Attribute *italic;
    Formatter::Attribute *red;
    Formatter::Attribute *pointer;
    Formatter::Attribute *literal;

public:
    Dumper(std::ostream &_os) : os(_os) {
        formatter = Formatter::defaultFormatter();
        normal = formatter->normal();
        bold = formatter->bold();
        italic = formatter->italic();
        red = formatter->color(Formatter::RED);
        pointer = formatter->color(Formatter::GREEN);
        literal = formatter->color(Formatter::BLUE);
    }

    ~Dumper() {
        delete normal;
        delete bold;
        delete italic;
        delete red;
        delete pointer;
        delete literal;
        delete formatter;
    }

    void visit(Null *) {
        os << "NULL";
    }

    void visit(Bool *node) {
        os << literal << (node->value ? "true" : "false") << normal;
    }

    void visit(SInt *node) {
        os << literal << node->value << normal;
    }

    void visit(UInt *node) {
        os << literal << node->value << normal;
    }

    void visit(Float *node) {
        os << literal << node->value << normal;
    }

    void visit(String *node) {
        os << literal << '"' << node->value << '"' << normal;
    }

    void visit(Enum *node) {
        os << literal << node->sig->first << normal;
    }

    void visit(Bitmask *bitmask) {
        unsigned long long value = bitmask->value;
        const Bitmask::Signature *sig = bitmask->sig;
        bool first = true;
        for (Bitmask::Signature::const_iterator it = sig->begin(); value != 0 && it != sig->end(); ++it) {
            assert(it->second);
            if ((value & it->second) == it->second) {
                if (!first) {
                    os << " | ";
                }
                os << literal << it->first << normal;
                value &= ~it->second;
                first = false;
            }
        }
        if (value || first) {
            if (!first) {
                os << " | ";
            }
            os << literal << "0x" << std::hex << value << std::dec << normal;
        }
    }

    void visit(Struct *s) {
        const char *sep = "";
        os << "{";
        for (unsigned i = 0; i < s->members.size(); ++i) {
            os << sep << italic << s->sig->member_names[i] << normal << " = ";
            _visit(s->members[i]);
            sep = ", ";
        }
        os << "}";
    }

    void visit(Array *array) {
        if (array->values.size() == 1) {
            os << "&";
            _visit(array->values[0]);
        }
        else {
            const char *sep = "";
            os << "{";
            for (std::vector<Value *>::iterator it = array->values.begin(); it != array->values.end(); ++it) {
                os << sep;
                _visit(*it);
                sep = ", ";
            }
            os << "}";
        }
    }

    void visit(Blob *blob) {
        os << pointer << "blob(" << blob->size << ")" << normal;
    }

    void visit(Pointer *p) {
        os << pointer << "0x" << std::hex << p->value << std::dec << normal;
    }

    void visit(Call *call) {
        const char *sep = "";
        os << bold << call->sig->name << normal << "(";
        for (unsigned i = 0; i < call->args.size(); ++i) {
            os << sep << italic << call->sig->arg_names[i] << normal << " = ";
            _visit(call->args[i]);
            sep = ", ";
        }
        os << ")";
        if (call->ret) {
            os << " = ";
            _visit(call->ret);
        }
        os << "\n";
    }
};

std::ostream & operator <<(std::ostream &os, Value *value) {
    Dumper d(os);
    if (value) {
        value->visit(d);
    }
    return os;
}

static inline const Value *unwrap(const Value *node) {
    const Enum *c = dynamic_cast<const Enum *>(node);
    if (c)
        return c->sig->second;
    return node;
}

Value::operator bool(void) const {
    const Bool *b = dynamic_cast<const Bool *>(unwrap(this));
    if (b)
        return b->value;
    assert(0);
    return false;
}

Value::operator signed long long(void) const {
    const SInt *sint = dynamic_cast<const SInt *>(unwrap(this));
    if (sint)
        return sint->value;
    const UInt *uint = dynamic_cast<const UInt *>(unwrap(this));
    if (uint)
        return uint->value;
    assert(0);
    return 0;
}

Value::operator unsigned long long(void) const {
    const UInt *uint = dynamic_cast<const UInt *>(unwrap(this));
    if (uint)
        return uint->value;
    assert(0);
    return 0;
}

Value::operator double(void) const {
    const Float *fl = dynamic_cast<const Float *>(unwrap(this));
    assert(fl);
    return fl->value;
}

static Null null;

const Value & Value::operator[](size_t index) const {
    const Array *array = dynamic_cast<const Array *>(unwrap(this));
    if (array) {
        if (index < array->values.size()) {
            return *array->values[index];
        }
    }
    return null;
}

void * Value::blob(void) const {
    const Blob *blob = dynamic_cast<const Blob *>(unwrap(this));
    if (blob)
        return blob->buf;
    const Null *null = dynamic_cast<const Null *>(unwrap(this));
    if (null)
        return NULL;
    assert(0);
    return NULL;
}

const char * Value::string(void) const {
    const String *string = dynamic_cast<const String *>(unwrap(this));
    if (string)
        return string->value.c_str();
    const Null *null = dynamic_cast<const Null *>(unwrap(this));
    if (null)
        return NULL;
    assert(0);
    return NULL;
}

std::ostream & operator <<(std::ostream &os, Call &call) {
    Dumper d(os);
    d.visit(&call);
    return os;
}

} /* namespace Trace */
<commit_msg>Also dump call no.<commit_after>/**************************************************************************
 *
 * Copyright 2010 VMware, Inc.
 * All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 **************************************************************************/

#include "formatter.hpp"
#include "trace_model.hpp"

namespace Trace {

Call::~Call() {
    for (unsigned i = 0; i < args.size(); ++i) {
        delete args[i];
    }

    if (ret) {
        delete ret;
    }
}

Struct::~Struct() {
    for (std::vector<Value *>::iterator it = members.begin(); it != members.end(); ++it) {
        delete *it;
    }
}

Array::~Array() {
    for (std::vector<Value *>::iterator it = values.begin(); it != values.end(); ++it) {
        delete *it;
    }
}

void Null::visit(Visitor &visitor) { visitor.visit(this); }
void Bool::visit(Visitor &visitor) { visitor.visit(this); }
void SInt::visit(Visitor &visitor) { visitor.visit(this); }
void UInt::visit(Visitor &visitor) { visitor.visit(this); }
void Float::visit(Visitor &visitor) { visitor.visit(this); }
void String::visit(Visitor &visitor) { visitor.visit(this); }
void Enum::visit(Visitor &visitor) { visitor.visit(this); }
void Bitmask::visit(Visitor &visitor) { visitor.visit(this); }
void Struct::visit(Visitor &visitor) { visitor.visit(this); }
void Array::visit(Visitor &visitor) { visitor.visit(this); }
void Blob::visit(Visitor &visitor) { visitor.visit(this); }
void Pointer::visit(Visitor &visitor) { visitor.visit(this); }

class Dumper : public Visitor
{
protected:
    std::ostream &os;
    Formatter::Formatter *formatter;
    Formatter::Attribute *normal;
    Formatter::Attribute *bold;
    Formatter::Attribute *italic;
    Formatter::Attribute *red;
    Formatter::Attribute *pointer;
    Formatter::Attribute *literal;

public:
    Dumper(std::ostream &_os) : os(_os) {
        formatter = Formatter::defaultFormatter();
        normal = formatter->normal();
        bold = formatter->bold();
        italic = formatter->italic();
        red = formatter->color(Formatter::RED);
        pointer = formatter->color(Formatter::GREEN);
        literal = formatter->color(Formatter::BLUE);
    }

    ~Dumper() {
        delete normal;
        delete bold;
        delete italic;
        delete red;
        delete pointer;
        delete literal;
        delete formatter;
    }

    void visit(Null *) {
        os << "NULL";
    }

    void visit(Bool *node) {
        os << literal << (node->value ? "true" : "false") << normal;
    }

    void visit(SInt *node) {
        os << literal << node->value << normal;
    }

    void visit(UInt *node) {
        os << literal << node->value << normal;
    }

    void visit(Float *node) {
        os << literal << node->value << normal;
    }

    void visit(String *node) {
        os << literal << '"' << node->value << '"' << normal;
    }

    void visit(Enum *node) {
        os << literal << node->sig->first << normal;
    }

    void visit(Bitmask *bitmask) {
        unsigned long long value = bitmask->value;
        const Bitmask::Signature *sig = bitmask->sig;
        bool first = true;
        for (Bitmask::Signature::const_iterator it = sig->begin(); value != 0 && it != sig->end(); ++it) {
            assert(it->second);
            if ((value & it->second) == it->second) {
                if (!first) {
                    os << " | ";
                }
                os << literal << it->first << normal;
                value &= ~it->second;
                first = false;
            }
        }
        if (value || first) {
            if (!first) {
                os << " | ";
            }
            os << literal << "0x" << std::hex << value << std::dec << normal;
        }
    }

    void visit(Struct *s) {
        const char *sep = "";
        os << "{";
        for (unsigned i = 0; i < s->members.size(); ++i) {
            os << sep << italic << s->sig->member_names[i] << normal << " = ";
            _visit(s->members[i]);
            sep = ", ";
        }
        os << "}";
    }

    void visit(Array *array) {
        if (array->values.size() == 1) {
            os << "&";
            _visit(array->values[0]);
        }
        else {
            const char *sep = "";
            os << "{";
            for (std::vector<Value *>::iterator it = array->values.begin(); it != array->values.end(); ++it) {
                os << sep;
                _visit(*it);
                sep = ", ";
            }
            os << "}";
        }
    }

    void visit(Blob *blob) {
        os << pointer << "blob(" << blob->size << ")" << normal;
    }

    void visit(Pointer *p) {
        os << pointer << "0x" << std::hex << p->value << std::dec << normal;
    }

    void visit(Call *call) {
        const char *sep = "";
        os << bold << call->sig->name << normal << "(";
        for (unsigned i = 0; i < call->args.size(); ++i) {
            os << sep << italic << call->sig->arg_names[i] << normal << " = ";
            _visit(call->args[i]);
            sep = ", ";
        }
        os << ")";
        if (call->ret) {
            os << " = ";
            _visit(call->ret);
        }
        os << "\n";
    }
};

std::ostream & operator <<(std::ostream &os, Value *value) {
    Dumper d(os);
    if (value) {
        value->visit(d);
    }
    return os;
}

static inline const Value *unwrap(const Value *node) {
    const Enum *c = dynamic_cast<const Enum *>(node);
    if (c)
        return c->sig->second;
    return node;
}

Value::operator bool(void) const {
    const Bool *b = dynamic_cast<const Bool *>(unwrap(this));
    if (b)
        return b->value;
    assert(0);
    return false;
}

Value::operator signed long long(void) const {
    const SInt *sint = dynamic_cast<const SInt *>(unwrap(this));
    if (sint)
        return sint->value;
    const UInt *uint = dynamic_cast<const UInt *>(unwrap(this));
    if (uint)
        return uint->value;
    assert(0);
    return 0;
}

Value::operator unsigned long long(void) const {
    const UInt *uint = dynamic_cast<const UInt *>(unwrap(this));
    if (uint)
        return uint->value;
    assert(0);
    return 0;
}

Value::operator double(void) const {
    const Float *fl = dynamic_cast<const Float *>(unwrap(this));
    assert(fl);
    return fl->value;
}

static Null null;

const Value & Value::operator[](size_t index) const {
    const Array *array = dynamic_cast<const Array *>(unwrap(this));
    if (array) {
        if (index < array->values.size()) {
            return *array->values[index];
        }
    }
    return null;
}

void * Value::blob(void) const {
    const Blob *blob = dynamic_cast<const Blob *>(unwrap(this));
    if (blob)
        return blob->buf;
    const Null *null = dynamic_cast<const Null *>(unwrap(this));
    if (null)
        return NULL;
    assert(0);
    return NULL;
}

const char * Value::string(void) const {
    const String *string = dynamic_cast<const String *>(unwrap(this));
    if (string)
        return string->value.c_str();
    const Null *null = dynamic_cast<const Null *>(unwrap(this));
    if (null)
        return NULL;
    assert(0);
    return NULL;
}

std::ostream & operator <<(std::ostream &os, Call &call) {
    Dumper d(os);
    os << call.no << " ";
    d.visit(&call);
    return os;
}

} /* namespace Trace */
<|endoftext|>


<commit_before>#include <QDebug>
#include <QFile>
#include <QKeyEvent>
#include <QLineEdit>
#include <QList>
#include <QMessageBox>
#include <QPoint>
#include <QSettings>
#include <QSize>
#include <QVector>

#include <stdexcept>
#include <typeinfo>

#include "BracketedDelegate.hh"
#include "BracketedColorDelegate.hh"
#include "BracketedKeywordInContextDelegate.hh"
#include "BracketedVisibilityDelegate.hh"
#include "BracketedWindow.hh"
#include "DactMacrosModel.hh"
#include "FilterModel.hh"
#include "XPathValidator.hh"
#include "XSLTransformer.hh"
#include "ValidityColor.hh"
#include "ui_BracketedWindow.h"

namespace ac = alpinocorpus;

BracketedWindow::BracketedWindow(QSharedPointer<ac::CorpusReader> corpusReader,
        QSharedPointer<DactMacrosModel> macrosModel, QWidget *parent, Qt::WindowFlags f) :
    QWidget(parent, f),
    d_ui(QSharedPointer<Ui::BracketedWindow>(new Ui::BracketedWindow)),
    d_macrosModel(macrosModel),
    d_xpathValidator(new XPathValidator(d_macrosModel))
{
    d_ui->setupUi(this);

    switchCorpus(corpusReader);

    initListDelegates();
    createActions();
    readSettings();
}

void BracketedWindow::switchCorpus(QSharedPointer<ac::CorpusReader> corpusReader)
{
    d_corpusReader = corpusReader;
    setModel(new FilterModel(corpusReader));
}

void BracketedWindow::setFilter(QString const &filter)
{
    d_ui->filterLineEdit->setText(filter);

    // Don't try to filter with an invalid xpath expression
    if (!d_ui->filterLineEdit->hasAcceptableInput())
        d_filter = QString();
    else
        d_filter = filter.trimmed();
}

void BracketedWindow::setModel(FilterModel *model)
{
    d_model = QSharedPointer<FilterModel>(model);
    d_ui->resultsList->setModel(d_model.data());

    /*
    connect(d_model.data(), SIGNAL(queryEntryFound(QString)),
        this, SLOT(updateResultsTotalCount()));
    */

    connect(d_model.data(), SIGNAL(queryStarted(int)),
        SLOT(progressStarted(int)));

    connect(d_model.data(), SIGNAL(queryStopped(int, int)),
        SLOT(progressStopped(int, int)));
}

void BracketedWindow::startQuery()
{
    setFilter(d_ui->filterLineEdit->text());

    d_model->runQuery(d_macrosModel->expand(d_filter));
}

void BracketedWindow::stopQuery()
{
    d_model->cancelQuery();
}

void BracketedWindow::applyValidityColor(QString const &)
{
    ::applyValidityColor(sender());
}

void BracketedWindow::createActions()
{
    /*
    QObject::connect(d_ui->resultsListWidget,
        SIGNAL(currentItemChanged(QListWidgetItem *,QListWidgetItem *)),
        this,
        SLOT(entrySelected(QListWidgetItem*,QListWidgetItem*)));
    */

    QObject::connect(d_ui->resultsList,
        // itemActivated is triggered by a single click on some systems
        // where this is the configured behavior: it can be annoying.
        // But it also enables using [enter] to raise the main window
        // which is the expected/preferred behavior.
        SIGNAL(activated(QModelIndex const &)),
        this,
        SLOT(entryActivated(QModelIndex const &)));

    d_ui->filterLineEdit->setValidator(d_xpathValidator.data());
    QObject::connect(d_ui->filterLineEdit, SIGNAL(textChanged(QString const &)),
        this, SLOT(applyValidityColor(QString const &)));

    QObject::connect(d_ui->filterLineEdit, SIGNAL(returnPressed()),
        this, SLOT(startQuery()));

    QObject::connect(d_ui->listDelegateComboBox, SIGNAL(currentIndexChanged(int)),
        this, SLOT(listDelegateChanged(int)));
}

/*
void BracketedWindow::entrySelected(QListWidgetItem *current, QListWidgetItem *)
{
    if (current == 0)
        return;

    emit currentEntryChanged(current->data(Qt::UserRole).toString());

    // Raises this window again when using cursor keys after using
    // [enter] to raise the main window.
    raise();
}
*/

void BracketedWindow::entryActivated(QModelIndex const &index)
{
    emit entryActivated(index.data(Qt::UserRole).toString());
}

void BracketedWindow::addListDelegate(QString const &name, DelegateFactory factory)
{
    d_ui->listDelegateComboBox->addItem(name, d_listDelegateFactories.size());
    d_listDelegateFactories.append(factory);
}

void BracketedWindow::listDelegateChanged(int index)
{
    int delegateIndex = d_ui->listDelegateComboBox->itemData(index, Qt::UserRole).toInt();

    if (delegateIndex >= d_listDelegateFactories.size())
    {
        qWarning() << QString("Trying to select a list delegate (%1) beyond the boundary "
                              "of the d_listDelegateFactories list (%2)")
                             .arg(delegateIndex).arg(d_listDelegateFactories.size());
        return;
    }

    QAbstractItemDelegate* prevItemDelegate = d_ui->resultsList->itemDelegate();
    d_ui->resultsList->setItemDelegate(d_listDelegateFactories[delegateIndex](d_corpusReader));
    delete prevItemDelegate;
}

void BracketedWindow::initListDelegates()
{
    addListDelegate("Complete sentence", &BracketedWindow::colorDelegateFactory);
    addListDelegate("Only matches", &BracketedWindow::visibilityDelegateFactory);
    addListDelegate("Keyword in Context", &BracketedWindow::keywordInContextDelegateFactory);
}

void BracketedWindow::keyPressEvent(QKeyEvent *event)
{
    // When pressing Esc, stop with what you where doing
    if (event->key() == Qt::Key_Escape)
    {
        d_model->cancelQuery();
        event->accept();
    }
    // Cmd + w closes the window in OS X (and in some programs on Windows as well)
    else if (event->key() == Qt::Key_W && event->modifiers() == Qt::ControlModifier)
    {
        hide();
        event->accept();
    }
    else
        QWidget::keyPressEvent(event);
}

void BracketedWindow::progressStarted(int totalEntries)
{
    d_ui->filterProgressBar->setMinimum(0);
    d_ui->filterProgressBar->setMaximum(totalEntries);
    d_ui->filterProgressBar->setValue(0);
    d_ui->filterProgressBar->setVisible(true);
}

void BracketedWindow::progressChanged(int processedEntries, int totalEntries)
{
    d_ui->filterProgressBar->setValue(processedEntries);
}

void BracketedWindow::progressStopped(int processedEntries, int totalEntries)
{
    d_ui->filterProgressBar->setVisible(false);
}

void BracketedWindow::closeEvent(QCloseEvent *event)
{
    writeSettings();
    event->accept();
}

void BracketedWindow::readSettings()
{
    QSettings settings;

    // Window geometry.
    QPoint pos = settings.value("filter_pos", QPoint(200, 200)).toPoint();
    QSize size = settings.value("filter_size", QSize(350, 400)).toSize();
    resize(size);
    move(pos);

    // restore last selected display method
    int delegateIndex = settings.value("filter_list_delegate", 0).toInt();
    listDelegateChanged(delegateIndex);
    d_ui->listDelegateComboBox->setCurrentIndex(delegateIndex);
}

void BracketedWindow::writeSettings()
{
    QSettings settings;

    // Window geometry
    settings.setValue("filter_pos", pos());
    settings.setValue("filter_size", size());

    // display method
    settings.setValue("filter_list_delegate", d_ui->listDelegateComboBox->currentIndex());
}

QStyledItemDelegate* BracketedWindow::colorDelegateFactory(CorpusReaderPtr reader)
{
    return new BracketedColorDelegate(reader);
}

QStyledItemDelegate* BracketedWindow::visibilityDelegateFactory(CorpusReaderPtr reader)
{
    return new BracketedVisibilityDelegate(reader);
}

QStyledItemDelegate* BracketedWindow::keywordInContextDelegateFactory(CorpusReaderPtr reader)
{
    return new BracketedKeywordInContextDelegate(reader);
}<commit_msg>BracketedWindow: update validator when switching corpora.<commit_after>#include <QDebug>
#include <QFile>
#include <QKeyEvent>
#include <QLineEdit>
#include <QList>
#include <QMessageBox>
#include <QPoint>
#include <QSettings>
#include <QSize>
#include <QVector>

#include <stdexcept>
#include <typeinfo>

#include "BracketedDelegate.hh"
#include "BracketedColorDelegate.hh"
#include "BracketedKeywordInContextDelegate.hh"
#include "BracketedVisibilityDelegate.hh"
#include "BracketedWindow.hh"
#include "DactMacrosModel.hh"
#include "FilterModel.hh"
#include "XPathValidator.hh"
#include "XSLTransformer.hh"
#include "ValidityColor.hh"
#include "ui_BracketedWindow.h"

namespace ac = alpinocorpus;

BracketedWindow::BracketedWindow(QSharedPointer<ac::CorpusReader> corpusReader,
        QSharedPointer<DactMacrosModel> macrosModel, QWidget *parent, Qt::WindowFlags f) :
    QWidget(parent, f),
    d_ui(QSharedPointer<Ui::BracketedWindow>(new Ui::BracketedWindow)),
    d_macrosModel(macrosModel),
    d_xpathValidator(QSharedPointer<XPathValidator>(new XPathValidator(d_macrosModel, 0, corpusReader)))
{
    d_ui->setupUi(this);

    switchCorpus(corpusReader);

    initListDelegates();
    createActions();
    readSettings();
}

void BracketedWindow::switchCorpus(QSharedPointer<ac::CorpusReader> corpusReader)
{
    d_corpusReader = corpusReader;
    d_xpathValidator->setCorpusReader(d_corpusReader);
    setModel(new FilterModel(corpusReader));
}

void BracketedWindow::setFilter(QString const &filter)
{
    d_ui->filterLineEdit->setText(filter);

    // Don't try to filter with an invalid xpath expression
    if (!d_ui->filterLineEdit->hasAcceptableInput())
        d_filter = QString();
    else
        d_filter = filter.trimmed();
}

void BracketedWindow::setModel(FilterModel *model)
{
    d_model = QSharedPointer<FilterModel>(model);
    d_ui->resultsList->setModel(d_model.data());

    /*
    connect(d_model.data(), SIGNAL(queryEntryFound(QString)),
        this, SLOT(updateResultsTotalCount()));
    */

    connect(d_model.data(), SIGNAL(queryStarted(int)),
        SLOT(progressStarted(int)));

    connect(d_model.data(), SIGNAL(queryStopped(int, int)),
        SLOT(progressStopped(int, int)));
}

void BracketedWindow::startQuery()
{
    setFilter(d_ui->filterLineEdit->text());

    d_model->runQuery(d_macrosModel->expand(d_filter));
}

void BracketedWindow::stopQuery()
{
    d_model->cancelQuery();
}

void BracketedWindow::applyValidityColor(QString const &)
{
    ::applyValidityColor(sender());
}

void BracketedWindow::createActions()
{
    /*
    QObject::connect(d_ui->resultsListWidget,
        SIGNAL(currentItemChanged(QListWidgetItem *,QListWidgetItem *)),
        this,
        SLOT(entrySelected(QListWidgetItem*,QListWidgetItem*)));
    */

    QObject::connect(d_ui->resultsList,
        // itemActivated is triggered by a single click on some systems
        // where this is the configured behavior: it can be annoying.
        // But it also enables using [enter] to raise the main window
        // which is the expected/preferred behavior.
        SIGNAL(activated(QModelIndex const &)),
        this,
        SLOT(entryActivated(QModelIndex const &)));

    d_ui->filterLineEdit->setValidator(d_xpathValidator.data());
    QObject::connect(d_ui->filterLineEdit, SIGNAL(textChanged(QString const &)),
        this, SLOT(applyValidityColor(QString const &)));

    QObject::connect(d_ui->filterLineEdit, SIGNAL(returnPressed()),
        this, SLOT(startQuery()));

    QObject::connect(d_ui->listDelegateComboBox, SIGNAL(currentIndexChanged(int)),
        this, SLOT(listDelegateChanged(int)));
}

/*
void BracketedWindow::entrySelected(QListWidgetItem *current, QListWidgetItem *)
{
    if (current == 0)
        return;

    emit currentEntryChanged(current->data(Qt::UserRole).toString());

    // Raises this window again when using cursor keys after using
    // [enter] to raise the main window.
    raise();
}
*/

void BracketedWindow::entryActivated(QModelIndex const &index)
{
    emit entryActivated(index.data(Qt::UserRole).toString());
}

void BracketedWindow::addListDelegate(QString const &name, DelegateFactory factory)
{
    d_ui->listDelegateComboBox->addItem(name, d_listDelegateFactories.size());
    d_listDelegateFactories.append(factory);
}

void BracketedWindow::listDelegateChanged(int index)
{
    int delegateIndex = d_ui->listDelegateComboBox->itemData(index, Qt::UserRole).toInt();

    if (delegateIndex >= d_listDelegateFactories.size())
    {
        qWarning() << QString("Trying to select a list delegate (%1) beyond the boundary "
                              "of the d_listDelegateFactories list (%2)")
                             .arg(delegateIndex).arg(d_listDelegateFactories.size());
        return;
    }

    QAbstractItemDelegate* prevItemDelegate = d_ui->resultsList->itemDelegate();
    d_ui->resultsList->setItemDelegate(d_listDelegateFactories[delegateIndex](d_corpusReader));
    delete prevItemDelegate;
}

void BracketedWindow::initListDelegates()
{
    addListDelegate("Complete sentence", &BracketedWindow::colorDelegateFactory);
    addListDelegate("Only matches", &BracketedWindow::visibilityDelegateFactory);
    addListDelegate("Keyword in Context", &BracketedWindow::keywordInContextDelegateFactory);
}

void BracketedWindow::keyPressEvent(QKeyEvent *event)
{
    // When pressing Esc, stop with what you where doing
    if (event->key() == Qt::Key_Escape)
    {
        d_model->cancelQuery();
        event->accept();
    }
    // Cmd + w closes the window in OS X (and in some programs on Windows as well)
    else if (event->key() == Qt::Key_W && event->modifiers() == Qt::ControlModifier)
    {
        hide();
        event->accept();
    }
    else
        QWidget::keyPressEvent(event);
}

void BracketedWindow::progressStarted(int totalEntries)
{
    d_ui->filterProgressBar->setMinimum(0);
    d_ui->filterProgressBar->setMaximum(totalEntries);
    d_ui->filterProgressBar->setValue(0);
    d_ui->filterProgressBar->setVisible(true);
}

void BracketedWindow::progressChanged(int processedEntries, int totalEntries)
{
    d_ui->filterProgressBar->setValue(processedEntries);
}

void BracketedWindow::progressStopped(int processedEntries, int totalEntries)
{
    d_ui->filterProgressBar->setVisible(false);
}

void BracketedWindow::closeEvent(QCloseEvent *event)
{
    writeSettings();
    event->accept();
}

void BracketedWindow::readSettings()
{
    QSettings settings;

    // Window geometry.
    QPoint pos = settings.value("filter_pos", QPoint(200, 200)).toPoint();
    QSize size = settings.value("filter_size", QSize(350, 400)).toSize();
    resize(size);
    move(pos);

    // restore last selected display method
    int delegateIndex = settings.value("filter_list_delegate", 0).toInt();
    listDelegateChanged(delegateIndex);
    d_ui->listDelegateComboBox->setCurrentIndex(delegateIndex);
}

void BracketedWindow::writeSettings()
{
    QSettings settings;

    // Window geometry
    settings.setValue("filter_pos", pos());
    settings.setValue("filter_size", size());

    // display method
    settings.setValue("filter_list_delegate", d_ui->listDelegateComboBox->currentIndex());
}

QStyledItemDelegate* BracketedWindow::colorDelegateFactory(CorpusReaderPtr reader)
{
    return new BracketedColorDelegate(reader);
}

QStyledItemDelegate* BracketedWindow::visibilityDelegateFactory(CorpusReaderPtr reader)
{
    return new BracketedVisibilityDelegate(reader);
}

QStyledItemDelegate* BracketedWindow::keywordInContextDelegateFactory(CorpusReaderPtr reader)
{
    return new BracketedKeywordInContextDelegate(reader);
}<|endoftext|>


<commit_before>#pragma once
// helper header for providing wrappers for thread sanitizer on different compilers.

// due to a bug in TSAN, using Event::wait() version with timeout or deadline results in false-positives.
//   * gcc:   https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101978
//   * clang: https://github.com/google/sanitizers/issues/1259
// to avoid it these some tests need to be disabled when running under TSAN, for affected compilers

#if __clang__major__ <= 11
// clang detection:
// - https://github.com/google/sanitizers/wiki/ThreadSanitizerCppManual
// - https://clang.llvm.org/docs/ThreadSanitizer.html
#if defined(__has_feature)
#if __has_feature(thread_sanitizer)
#define BUT_THREAD_SANITIZER_ENABLED
#endif
#endif
#endif // clang

#if __GNUC__ <= 10
// gcc detection:
// - https://stackoverflow.com/questions/57499943/how-to-detect-thread-sanitizer-for-gcc-5
#ifdef __SANITIZE_THREAD__
#define BUT_THREAD_SANITIZER_ENABLED
#endif
#endif // gcc
<commit_msg>BUT_THREAD_SANITIZER_ENABLED is now ALWASY set, but 1 or 0 indicates if TSAN is enabled or not. this way it's harder to accidentalyl break sth<commit_after>#pragma once
// helper header for providing wrappers for thread sanitizer on different compilers.

// due to a bug in TSAN, using Event::wait() version with timeout or deadline results in false-positives.
//   * gcc:   https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101978
//   * clang: https://github.com/google/sanitizers/issues/1259
// to avoid it these some tests need to be disabled when running under TSAN, for affected compilers

#if __clang__major__ <= 11
// clang detection:
// - https://github.com/google/sanitizers/wiki/ThreadSanitizerCppManual
// - https://clang.llvm.org/docs/ThreadSanitizer.html
#if defined(__has_feature)
#if __has_feature(thread_sanitizer)
#define BUT_THREAD_SANITIZER_ENABLED 1
#endif
#endif

#ifndef BUT_THREAD_SANITIZER_ENABLED
#define BUT_THREAD_SANITIZER_ENABLED 0
#endif
#endif // clang

#if __GNUC__ <= 10
// gcc detection:
// - https://stackoverflow.com/questions/57499943/how-to-detect-thread-sanitizer-for-gcc-5
#ifdef __SANITIZE_THREAD__
#define BUT_THREAD_SANITIZER_ENABLED 1
#endif

#ifndef BUT_THREAD_SANITIZER_ENABLED
#define BUT_THREAD_SANITIZER_ENABLED 0
#endif
#endif // gcc

// undefined compiler
#ifndef BUT_THREAD_SANITIZER_ENABLED
#warning your compiler is not recognized and BUT_THREAD_SANITIZER_ENABLED is not set
#endif
<|endoftext|>


<commit_before>#include"../header/CThreadPoolItem.h"
#include<atomic>	//atomic<bool>
#include<utility>	//move
#include"../../lib/header/thread/CSemaphore.h"
#include"../../lib/header/thread/CSmartThread.h"
using namespace std;

namespace nThread
{
	struct IThreadPoolItemExecutorBase	//I give up to use Non-Virtual Interface Idiom here
										//because this is a abstract base struct
	{
		virtual void exec()=0;
		virtual bool is_running() const noexcept=0;
		inline bool joinable() const noexcept
		{
			return joinable_();
		}
		virtual void join()=0;
		virtual ~IThreadPoolItemExecutorBase()=0;
	protected:
		virtual bool joinable_() const noexcept
		{
			return false;
		}
	};

	class CThreadPoolItemExecutorDetach:public IThreadPoolItemExecutorBase
	{
		CThreadPoolCommunBase *commun_;
		CSemaphore complete_;
		function<void()> func_;
	public:
		CThreadPoolItemExecutorDetach(CThreadPoolCommunBase *,function<void()> &&);
		void exec() override;
		bool is_running() const noexcept override	//only the destructor of CThreadPoolItem will call this
		{
			return !complete_.count();
		}
		void join() override	//only the destructor of CThreadPoolItem will call this
		{
			complete_.wait();
		}
	};

	class CThreadPoolItemExecutorJoin:public IThreadPoolItemExecutorBase
	{
		CThreadPoolCommunBase *commun_;
		CSemaphore complete_;
		function<void()> func_;
		atomic<bool> running_;
	protected:
		bool joinable_() const noexcept override
		{
			return true;
		}
	public:
		CThreadPoolItemExecutorJoin(CThreadPoolCommunBase *,function<void()> &&);
		void exec() override;
		bool is_running() const noexcept override
		{
			return running_;
		}
		void join() override;
	};

	struct CThreadPoolItem::Impl
	{
		unique_ptr<CThreadPoolCommunBase> commun;	//communicate with CThreadPool
		bool destructor;
		unique_ptr<IThreadPoolItemExecutorBase> exec;
		CSemaphore wait;
		CSmartThread thr;	//first destroying, no other data member could put under this one
		Impl();
		void assign(function<void()> &&);
		void assign_and_detach(function<void()> &&);
		void loop();
		inline void waiting()
		{
			wait.wait();
		}
		inline void wake()
		{
			wait.signal();
		}
		~Impl();
	};

	IThreadPoolItemExecutorBase::~IThreadPoolItemExecutorBase(){}

	CThreadPoolItemExecutorDetach::CThreadPoolItemExecutorDetach(CThreadPoolCommunBase *commun,function<void()> &&func)
		:commun_{commun},complete_{0},func_{move(func)}{}

	void CThreadPoolItemExecutorDetach::exec()
	{
		func_();
		complete_.signal();
		commun_->communPoolDetach();
	}

	CThreadPoolItemExecutorJoin::CThreadPoolItemExecutorJoin(CThreadPoolCommunBase *commun,function<void()> &&func)
		:commun_{commun},complete_{0},func_{move(func)},running_{true}{}

	void CThreadPoolItemExecutorJoin::exec()
	{
		func_();
		commun_->communPoolFinish();
		complete_.signal();
	}

	void CThreadPoolItemExecutorJoin::join()
	{
		complete_.wait();
		running_=false;
		commun_->communPoolJoin();
	}

	CThreadPoolItem::Impl::Impl()
		:destructor{false},wait{0},thr{&CThreadPoolItem::Impl::loop,this}{}

	void CThreadPoolItem::Impl::assign(function<void()> &&func)
	{
		exec=make_unique<CThreadPoolItemExecutorJoin>(commun.get(),move(func));
		wake();
	}

	void CThreadPoolItem::Impl::assign_and_detach(function<void()> &&func)
	{
		exec=make_unique<CThreadPoolItemExecutorDetach>(commun.get(),move(func));
		wake();
	}

	void CThreadPoolItem::Impl::loop()
	{
		while(waiting(),!destructor)
			exec->exec();
	}

	CThreadPoolItem::Impl::~Impl()
	{
		if(exec&&exec->is_running())
			exec->join();
		destructor=true;
		wake();
	}

	CThreadPoolItem::CThreadPoolItem()
		:impl_{}{}

	void CThreadPoolItem::assign(function<void()> &&func)
	{
		impl_.get().assign(move(func));
	}

	void CThreadPoolItem::assign_and_detach(function<void()> &&func)
	{
		impl_.get().assign_and_detach(move(func));
	}

	void CThreadPoolItem::join()
	{
		impl_.get().exec->join();
	}

	bool CThreadPoolItem::joinable() const noexcept
	{
		return impl_.get().exec->joinable();
	}

	void CThreadPoolItem::setCommun(unique_ptr<CThreadPoolCommunBase> &&commun)
	{
		impl_.get().commun=move(commun);
	}

	CThreadPoolItem::~CThreadPoolItem(){}
}<commit_msg>fix include header<commit_after>#include"../header/CThreadPoolItem.h"
#include<atomic>	//atomic<bool>
#include<utility>	//move
#include"../../lib/header/thread/CSemaphore.h"
#include"../../lib/header/thread/CSmartThread.h"
#include"../header/CThreadPoolCommun.h"
using namespace std;

namespace nThread
{
	struct IThreadPoolItemExecutorBase	//I give up to use Non-Virtual Interface Idiom here
										//because this is a abstract base struct
	{
		virtual void exec()=0;
		virtual bool is_running() const noexcept=0;
		inline bool joinable() const noexcept
		{
			return joinable_();
		}
		virtual void join()=0;
		virtual ~IThreadPoolItemExecutorBase()=0;
	protected:
		virtual bool joinable_() const noexcept
		{
			return false;
		}
	};

	class CThreadPoolItemExecutorDetach:public IThreadPoolItemExecutorBase
	{
		CThreadPoolCommunBase *commun_;
		CSemaphore complete_;
		function<void()> func_;
	public:
		CThreadPoolItemExecutorDetach(CThreadPoolCommunBase *,function<void()> &&);
		void exec() override;
		bool is_running() const noexcept override	//only the destructor of CThreadPoolItem will call this
		{
			return !complete_.count();
		}
		void join() override	//only the destructor of CThreadPoolItem will call this
		{
			complete_.wait();
		}
	};

	class CThreadPoolItemExecutorJoin:public IThreadPoolItemExecutorBase
	{
		CThreadPoolCommunBase *commun_;
		CSemaphore complete_;
		function<void()> func_;
		atomic<bool> running_;
	protected:
		bool joinable_() const noexcept override
		{
			return true;
		}
	public:
		CThreadPoolItemExecutorJoin(CThreadPoolCommunBase *,function<void()> &&);
		void exec() override;
		bool is_running() const noexcept override
		{
			return running_;
		}
		void join() override;
	};

	struct CThreadPoolItem::Impl
	{
		unique_ptr<CThreadPoolCommunBase> commun;	//communicate with CThreadPool
		bool destructor;
		unique_ptr<IThreadPoolItemExecutorBase> exec;
		CSemaphore wait;
		CSmartThread thr;	//first destroying, no other data member could put under this one
		Impl();
		void assign(function<void()> &&);
		void assign_and_detach(function<void()> &&);
		void loop();
		inline void waiting()
		{
			wait.wait();
		}
		inline void wake()
		{
			wait.signal();
		}
		~Impl();
	};

	IThreadPoolItemExecutorBase::~IThreadPoolItemExecutorBase(){}

	CThreadPoolItemExecutorDetach::CThreadPoolItemExecutorDetach(CThreadPoolCommunBase *commun,function<void()> &&func)
		:commun_{commun},complete_{0},func_{move(func)}{}

	void CThreadPoolItemExecutorDetach::exec()
	{
		func_();
		complete_.signal();
		commun_->communPoolDetach();
	}

	CThreadPoolItemExecutorJoin::CThreadPoolItemExecutorJoin(CThreadPoolCommunBase *commun,function<void()> &&func)
		:commun_{commun},complete_{0},func_{move(func)},running_{true}{}

	void CThreadPoolItemExecutorJoin::exec()
	{
		func_();
		commun_->communPoolFinish();
		complete_.signal();
	}

	void CThreadPoolItemExecutorJoin::join()
	{
		complete_.wait();
		running_=false;
		commun_->communPoolJoin();
	}

	CThreadPoolItem::Impl::Impl()
		:destructor{false},wait{0},thr{&CThreadPoolItem::Impl::loop,this}{}

	void CThreadPoolItem::Impl::assign(function<void()> &&func)
	{
		exec=make_unique<CThreadPoolItemExecutorJoin>(commun.get(),move(func));
		wake();
	}

	void CThreadPoolItem::Impl::assign_and_detach(function<void()> &&func)
	{
		exec=make_unique<CThreadPoolItemExecutorDetach>(commun.get(),move(func));
		wake();
	}

	void CThreadPoolItem::Impl::loop()
	{
		while(waiting(),!destructor)
			exec->exec();
	}

	CThreadPoolItem::Impl::~Impl()
	{
		if(exec&&exec->is_running())
			exec->join();
		destructor=true;
		wake();
	}

	CThreadPoolItem::CThreadPoolItem()
		:impl_{}{}

	void CThreadPoolItem::assign(function<void()> &&func)
	{
		impl_.get().assign(move(func));
	}

	void CThreadPoolItem::assign_and_detach(function<void()> &&func)
	{
		impl_.get().assign_and_detach(move(func));
	}

	void CThreadPoolItem::join()
	{
		impl_.get().exec->join();
	}

	bool CThreadPoolItem::joinable() const noexcept
	{
		return impl_.get().exec->joinable();
	}

	void CThreadPoolItem::setCommun(unique_ptr<CThreadPoolCommunBase> &&commun)
	{
		impl_.get().commun=move(commun);
	}

	CThreadPoolItem::~CThreadPoolItem(){}
}<|endoftext|>


<commit_before>#include <iostream>
#include "xml.h"
#include "multicron.h"
#include "inotify.h"
extern "C" {
#include <sys/inotify.h>
#include <string.h>
};
#include "commands.h"

#define ALLOC_STEP 5
InotifyEvent::InotifyEvent() {
	rfds=(int*)malloc(sizeof(int)*2);
#ifdef BSD
	rfds[0]=kqueue();
#else
	rfds[0]=inotify_init();
#endif
	if( rfds[0] < 0 )
		throw "Couldn't create inotify fd";
	rfds[1]=-1;
	wfds=NULL;
	efds=NULL;

	name=strdup("inotify");
	inotify_files=(inotify_file*)malloc(sizeof(inotify_file)*ALLOC_STEP);
	memset(inotify_files, 0, sizeof(inotify_file)*ALLOC_STEP);
	n=0;
}

InotifyEvent::~InotifyEvent() {
	int i;
	for(i=0;inotify_files[i].filename;i++)
		free(inotify_files[i].filename);
	free(inotify_files);
	if(rfds) {
		if(rfds[0]>0)
			close(rfds[0]);
		free(rfds);
	}
	if(name)
		free(name);
}

void InotifyEvent::RefreshConfig(xmlNode config) {
	int inotify=rfds[0];
	while(!!config) {
		char *file=strdup(config["folder"]());
		if( file[strlen(file)-1]=='/')
			file[strlen(file)-1]=0;
		int ret;
		struct stat buf;
		if(lstat(file, &buf)) {
			free(file);
			return;
		}
		if(!S_ISDIR(buf.st_mode)) {
			//Maybe say to the user he is a f***ing noob ?
			free(file);
			return;
		}

#ifdef BSD
		int f;
		f=open(file, O_RDONLY|O_DIRECTORY);
		struct kevent change;
		EV_SET(&change, f, EVFILT_VNODE,
				//ONESHOT or not ?
			EV_ADD | EV_ENABLE | EV_ONESHOT,
			NOTE_DELETE | NOTE_EXTEND | NOTE_WRITE | NOTE_ATTRIB,
			0, n);
		if(kevent(KQUEUE_FD, &change, 1, NULL, 0, 0)<0) {
			perror("kevent");
			return;
		}
#else
		ret=inotify_add_watch(inotify, file, IN_CREATE|IN_CLOSE_WRITE|IN_MOVED_TO|IN_DELETE|IN_MOVED_FROM);
		if(ret==-1) {
			printf("%s\n", file);
			free(file);
			perror("Mise en place de la surveillance du fichier");
			exit(0);
		}
#endif
		++n;
		if((n%ALLOC_STEP)==0)
			inotify_files=(inotify_file*)realloc(inotify_files, (ret+ALLOC_STEP)*sizeof(char*));
#ifdef BSD
		inotify_files[n-1].fd=f;
		inotify_files[n-1].wd=f;
		inotify_files[n-1].filename=file;
		time(&(inotify_files[n-1].last));//Start watching from now.
#else
		inotify_files[n-1].wd=ret;
		inotify_files[n-1].filename=file;
#endif
		return;
	}
}

#ifdef BSD
void InotifyEvent::Callback(xmlNode config, int fd, EventManager::ETYPE event_type) {
	if(event_type==EventManager::TIMEOUT)
		return;
	struct kevent ev;
	int ret;
	ret=kevent(KQUEUE_FD, NULL, 0, &ev, 1, NULL);
	if(ret<0) {
		perror("kevent");
		return;
	}

	inotify_file *file=inotify_files[ev.udata];
	while(!!node) {
		char *folder=strdup(node["folder"]());
		if(folder[strlen(folder)-1]=='/')
			folder[strlen(folder)-1]=0;
		struct context ctx;
		memset(&ctx, 0, sizeof(ctx));
		ctx.pid=0;
		if(strcmp(folder, file.filename)!=0) {
			free(folder);
			++node;
			continue;
		}
		if(!node["file"]()) {
			time(&(file.last));
			Cmds::Call(node, ctx);
			free(folder);
			++node;
			continue;
		}
		DIR *dir=opendir(folder);
		struct dirent *file_info=NULL;
		struct stat stat_buf;
		//Does asprintf exists on BSD ?
		char path[1024];
		while((file_info=readdir(dir))!=NULL) {
			if(!regexp_match(node["file"](), file_info->d_name))
				continue;
			bzero(&path, sizeof(path));
			snprintf(path, sizeof(path), "%s/%s", folder, file_info->d_name);
			path[sizeof(path)-1]=0;
			stat(path, &stat_buf);
			if(path.st_mtime<=file.last && path.st_ctime<=file.last)
				continue;
			//Ok, file is newer than last check.
			ctx.file=path;
			Cmds::Call(node, ctx);
		}
		time(&(file.last));
		free(folder);
		++node;
	}
}
#else
void InotifyEvent::Callback(xmlNode config, int fd, EventManager::ETYPE event_type) {
	if(event_type==EventManager::TIMEOUT)
		return;
	char buffer[4096];
	int ret;
	int i=0;

	ret=read(this->rfds[0], buffer, 4096);
	if(ret<0)
		perror("read");
	if(ret==0)
		sleep(5);
	char *path=NULL;
	while(i<ret) {
		const char *name = NULL;
		struct inotify_event *event;
		event = (struct inotify_event *) &buffer[i];
		if (event->len)
			name = &buffer[i] + sizeof (struct inotify_event);
		if(path) {
			free(path);
			path=NULL;
		}

		i += sizeof (struct inotify_event) + event->len;
		if(event->mask!=IN_CREATE && event->mask!=IN_MOVED_TO && event->mask!=IN_CLOSE_WRITE)
			continue;

		int j;
		for(j=0;inotify_files[j].filename;j++) {
			if(inotify_files[j].wd==event->wd)
				break;
		}
		if(!inotify_files[j].filename) {
			printf("Couldn't find recorded watch descriptor!\n");
			continue;
		}
		asprintf(&path, "%s/%s", inotify_files[j].filename, name);

		xmlNode node(config);
		char *filename=inotify_files[j].filename;
		while(!!node) {
			char *folder=strdup(node["folder"]());
			if(folder[strlen(folder)-1]=='/')
				folder[strlen(folder)-1]=0;
			struct context ctx;
			memset(&ctx, 0, sizeof(ctx));
			ctx.pid=0;
			ctx.file=path;
			if(strcmp(folder, filename)==0) {
				if(!node["file"]())
					Cmds::Call(node, ctx);
				else if(regexp_match(node["file"](), name))
					Cmds::Call(node, ctx);
			}
			free(folder);
			++node;
		}
	}
	if(path)
		free(path);
}
#endif
<commit_msg>Maybe get kqueue support build ?<commit_after>#include <iostream>
#include "xml.h"
#include "multicron.h"
#include "inotify.h"
#ifndef BSD
	extern "C" {
	#include <sys/inotify.h>
	};
#else
	#include <sys/event.h>
	#include <sys/time.h>
	#include <sys/types.h>
	#include <fcntl.h>
	#include <stdio.h>
	#include <stdlib.h>
	#include <unistd.h>
#endif
#include <string.h>
#include "commands.h"

#define ALLOC_STEP 5
InotifyEvent::InotifyEvent() {
	rfds=(int*)malloc(sizeof(int)*2);
#ifdef BSD
	rfds[0]=kqueue();
#else
	rfds[0]=inotify_init();
#endif
	if( rfds[0] < 0 )
		throw "Couldn't create inotify fd";
	rfds[1]=-1;
	wfds=NULL;
	efds=NULL;

	name=strdup("inotify");
	inotify_files=(inotify_file*)malloc(sizeof(inotify_file)*ALLOC_STEP);
	memset(inotify_files, 0, sizeof(inotify_file)*ALLOC_STEP);
	n=0;
}

InotifyEvent::~InotifyEvent() {
	int i;
	for(i=0;inotify_files[i].filename;i++)
		free(inotify_files[i].filename);
	free(inotify_files);
	if(rfds) {
		if(rfds[0]>0)
			close(rfds[0]);
		free(rfds);
	}
	if(name)
		free(name);
}

void InotifyEvent::RefreshConfig(xmlNode config) {
	int inotify=rfds[0];
	while(!!config) {
		char *file=strdup(config["folder"]());
		if( file[strlen(file)-1]=='/')
			file[strlen(file)-1]=0;
		int ret;
		struct stat buf;
		if(lstat(file, &buf)) {
			free(file);
			return;
		}
		if(!S_ISDIR(buf.st_mode)) {
			//Maybe say to the user he is a f***ing noob ?
			free(file);
			return;
		}

#ifdef BSD
		int f;
		f=open(file, O_RDONLY|O_DIRECTORY);
		struct kevent change;
		EV_SET(&change, f, EVFILT_VNODE,
				//ONESHOT or not ?
			EV_ADD | EV_ENABLE | EV_ONESHOT,
			NOTE_DELETE | NOTE_EXTEND | NOTE_WRITE | NOTE_ATTRIB,
			0, n);
		if(kevent(rfds[0], &change, 1, NULL, 0, 0)<0) {
			perror("kevent");
			return;
		}
#else
		ret=inotify_add_watch(inotify, file, IN_CREATE|IN_CLOSE_WRITE|IN_MOVED_TO|IN_DELETE|IN_MOVED_FROM);
		if(ret==-1) {
			printf("%s\n", file);
			free(file);
			perror("Mise en place de la surveillance du fichier");
			exit(0);
		}
#endif
		++n;
		if((n%ALLOC_STEP)==0)
			inotify_files=(inotify_file*)realloc(inotify_files, (ret+ALLOC_STEP)*sizeof(char*));
#ifdef BSD
		inotify_files[n-1].fd=f;
		inotify_files[n-1].wd=f;
		inotify_files[n-1].filename=file;
		time(&(inotify_files[n-1].last));//Start watching from now.
#else
		inotify_files[n-1].wd=ret;
		inotify_files[n-1].filename=file;
#endif
		return;
	}
}

#ifdef BSD
void InotifyEvent::Callback(xmlNode config, int fd, EventManager::ETYPE event_type) {
	if(event_type==EventManager::TIMEOUT)
		return;
	struct kevent ev;
	int ret;
	ret=kevent(rfds[0], NULL, 0, &ev, 1, NULL);
	if(ret<0) {
		perror("kevent");
		return;
	}

	inotify_file *file=inotify_files[ev.udata];
	while(!!node) {
		char *folder=strdup(node["folder"]());
		if(folder[strlen(folder)-1]=='/')
			folder[strlen(folder)-1]=0;
		struct context ctx;
		memset(&ctx, 0, sizeof(ctx));
		ctx.pid=0;
		if(strcmp(folder, file->filename)!=0) {
			free(folder);
			++node;
			continue;
		}
		if(!node["file"]()) {
			time(&(file->last));
			Cmds::Call(node, ctx);
			free(folder);
			++node;
			continue;
		}
		DIR *dir=opendir(folder);
		struct dirent *file_info=NULL;
		struct stat stat_buf;
		//Does asprintf exists on BSD ?
		char path[1024];
		while((file_info=readdir(dir))!=NULL) {
			if(!regexp_match(node["file"](), file_info->d_name))
				continue;
			bzero(&path, sizeof(path));
			snprintf(path, sizeof(path), "%s/%s", folder, file_info->d_name);
			path[sizeof(path)-1]=0;
			stat(path, &stat_buf);
			if(stat_buf.st_mtime<=file->last && stat_buf.st_ctime<=file->last)
				continue;
			//Ok, file is newer than last check.
			ctx.file=path;
			Cmds::Call(node, ctx);
		}
		time(&(file->last));
		free(folder);
		++node;
	}
}
#else
void InotifyEvent::Callback(xmlNode config, int fd, EventManager::ETYPE event_type) {
	if(event_type==EventManager::TIMEOUT)
		return;
	char buffer[4096];
	int ret;
	int i=0;

	ret=read(this->rfds[0], buffer, 4096);
	if(ret<0)
		perror("read");
	if(ret==0)
		sleep(5);
	char *path=NULL;
	while(i<ret) {
		const char *name = NULL;
		struct inotify_event *event;
		event = (struct inotify_event *) &buffer[i];
		if (event->len)
			name = &buffer[i] + sizeof (struct inotify_event);
		if(path) {
			free(path);
			path=NULL;
		}

		i += sizeof (struct inotify_event) + event->len;
		if(event->mask!=IN_CREATE && event->mask!=IN_MOVED_TO && event->mask!=IN_CLOSE_WRITE)
			continue;

		int j;
		for(j=0;inotify_files[j].filename;j++) {
			if(inotify_files[j].wd==event->wd)
				break;
		}
		if(!inotify_files[j].filename) {
			printf("Couldn't find recorded watch descriptor!\n");
			continue;
		}
		asprintf(&path, "%s/%s", inotify_files[j].filename, name);

		xmlNode node(config);
		char *filename=inotify_files[j].filename;
		while(!!node) {
			char *folder=strdup(node["folder"]());
			if(folder[strlen(folder)-1]=='/')
				folder[strlen(folder)-1]=0;
			struct context ctx;
			memset(&ctx, 0, sizeof(ctx));
			ctx.pid=0;
			ctx.file=path;
			if(strcmp(folder, filename)==0) {
				if(!node["file"]())
					Cmds::Call(node, ctx);
				else if(regexp_match(node["file"](), name))
					Cmds::Call(node, ctx);
			}
			free(folder);
			++node;
		}
	}
	if(path)
		free(path);
}
#endif
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2015 Damien Tardy-Panis
 *
 * This file is subject to the terms and conditions defined in
 * file 'LICENSE', which is part of this source code package.
 **/

#include "Garfield.h"

#include <QDebug>

Garfield::Garfield(QObject *parent) :
    Comic(parent)
{
    m_info.id             = QString("garfield");
    m_info.name           = QString("Garfield");
    m_info.color          = QColor(242, 186, 31);
    m_info.authors        = QStringList("Jim Davis");
    m_info.homepage       = QUrl("http://garfield.com/");
    m_info.country        = QLocale::UnitedStates;
    m_info.language       = QLocale::English;
    m_info.startDate      = QDate::fromString("1978-06-19", Qt::ISODate);
    m_info.endDate        = QDate::currentDate();
    m_info.stripSourceUrl = QUrl("http://garfield.com/");
}

QUrl Garfield::extractStripImageUrl(QByteArray data)
{
    return regexExtractStripImageUrl(data, "<img[^>]*src=\"(.*/strips/[^\"]*)\"");
}
<commit_msg>fix Garfield comic<commit_after>/**
 * Copyright (c) 2015 Damien Tardy-Panis
 *
 * This file is subject to the terms and conditions defined in
 * file 'LICENSE', which is part of this source code package.
 **/

#include "Garfield.h"

#include <QDebug>

Garfield::Garfield(QObject *parent) :
    Comic(parent)
{
    m_info.id             = QString("garfield");
    m_info.name           = QString("Garfield");
    m_info.color          = QColor(242, 186, 31);
    m_info.authors        = QStringList("Jim Davis");
    m_info.homepage       = QUrl("http://garfield.com/");
    m_info.country        = QLocale::UnitedStates;
    m_info.language       = QLocale::English;
    m_info.startDate      = QDate::fromString("1978-06-19", Qt::ISODate);
    m_info.endDate        = QDate::currentDate();
    m_info.stripSourceUrl = QUrl("http://garfield.com/");
}

QUrl Garfield::extractStripImageUrl(QByteArray data)
{
    return regexExtractStripImageUrl(data, "<img[^>]*src=\"(.*/comics/[^\"]*)\"");
}
<|endoftext|>


<commit_before>/**
 * From Section 5.5.1
 *
 * An example of the caller dealing with run-time errors
 */

/**
 * Error-prone Functions
 */

#include <iostream>
#include <cstdlib>
#include <string>

using namespace std;

// forces a program to terminate
void error(string errmsg)
{
    cout << errmsg  << endl;
    exit(1);
}

int area(int a, int b)
{
    // protecting the  call of area(a,b)
    if (a <= 0 || b <= 0) error("error: non-positive argument");

    // area is logical to calculate
    return a * b;
}

int framed_area(int a, int b) // calculate area within a "frame"
{
    if (a <= 2 || b <= 2) error("error: non-positive argument");

    return area(a-2,b-2);
}

int main(void)
{
    int x = -1;
    int y = 2;
    int z = 4;

    int area1 = area(x,y);
    int area2 = framed_area(1,z);
    int area3 = framed_area(y,z);

    double ratio = (double) (area1 / area3);

    return 0;
}
<commit_msg>Caller Error Excercise<commit_after>/**
 * From Section 5.5.1
 *
 * An example of the caller dealing with run-time errors
 */

/**
 * Error-prone Functions
 */

#include <iostream>
#include <cstdlib>
#include <string>

using namespace std;

// forces a program to terminate
void error(string errmsg)
{
    cout << errmsg  << endl;
    exit(1);
}

int area(int a, int b)
{
    // area is logical to calculate
    return a * b;
}

int framed_area(int a, int b) // calculate area within a "frame"
{
    return area(a-2,b-2);
}

int main(void)
{
    /**
     * In this paradigm, the two functions area() and framed_area()
     * are assumed to be immutable (e.g., in some library).
     *
     * In this example, we guard against invalid access in main().
     */
    int x = -1;
    int y = 2;
    int z = 4;

    // protecting the call of area()
    if (x <= 0 || y <= 0) error("error: non-positive argument");

    int area1 = area(x,y);

    // protecting the call of framed_area()
    if (1 <= 2 || z <= 2) error("error: non-positive argument");
    if (y <= 2 || z <= 2) error("error: non-positive argument");

    int area2 = framed_area(1,z);
    int area3 = framed_area(y,z);

    double ratio = (double) (area1 / area3);

    // suppress unused variable warnings from compiler
    (void)area1;
    (void)area2;
    (void)area3;
    (void)ratio;

    return 0;
}
<|endoftext|>


<commit_before>//===-- GraphWriter.cpp - Implements GraphWriter support routines ---------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements misc. GraphWriter support routines.
//
//===----------------------------------------------------------------------===//

#include "llvm/Support/GraphWriter.h"
#include "llvm/Config/config.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Program.h"
using namespace llvm;

static cl::opt<bool> ViewBackground("view-background", cl::Hidden,
  cl::desc("Execute graph viewer in the background. Creates tmp file litter."));

std::string llvm::DOT::EscapeString(const std::string &Label) {
  std::string Str(Label);
  for (unsigned i = 0; i != Str.length(); ++i)
  switch (Str[i]) {
    case '\n':
      Str.insert(Str.begin()+i, '\\');  // Escape character...
      ++i;
      Str[i] = 'n';
      break;
    case '\t':
      Str.insert(Str.begin()+i, ' ');  // Convert to two spaces
      ++i;
      Str[i] = ' ';
      break;
    case '\\':
      if (i+1 != Str.length())
        switch (Str[i+1]) {
          case 'l': continue; // don't disturb \l
          case '|': case '{': case '}':
            Str.erase(Str.begin()+i); continue;
          default: break;
        }
    case '{': case '}':
    case '<': case '>':
    case '|': case '"':
      Str.insert(Str.begin()+i, '\\');  // Escape character...
      ++i;  // don't infinite loop
      break;
  }
  return Str;
}

/// \brief Get a color string for this node number. Simply round-robin selects
/// from a reasonable number of colors.
StringRef llvm::DOT::getColorString(unsigned ColorNumber) {
  static const int NumColors = 20;
  static const char* Colors[NumColors] = {
    "aaaaaa", "aa0000", "00aa00", "aa5500", "0055ff", "aa00aa", "00aaaa",
    "555555", "ff5555", "55ff55", "ffff55", "5555ff", "ff55ff", "55ffff",
    "ffaaaa", "aaffaa", "ffffaa", "aaaaff", "ffaaff", "aaffff"};
  return Colors[ColorNumber % NumColors];
}

std::string llvm::createGraphFilename(const Twine &Name, int &FD) {
  FD = -1;
  SmallString<128> Filename;
  std::error_code EC = sys::fs::createTemporaryFile(Name, "dot", FD, Filename);
  if (EC) {
    errs() << "Error: " << EC.message() << "\n";
    return "";
  }

  errs() << "Writing '" << Filename << "'... ";
  return Filename.str();
}

// Execute the graph viewer. Return true if there were errors.
static bool ExecGraphViewer(StringRef ExecPath, std::vector<const char *> &args,
                            StringRef Filename, bool wait,
                            std::string &ErrMsg) {
  assert(args.back() == nullptr);
  if (wait) {
    if (sys::ExecuteAndWait(ExecPath, args.data(), nullptr, nullptr, 0, 0,
                            &ErrMsg)) {
      errs() << "Error: " << ErrMsg << "\n";
      return true;
    }
    sys::fs::remove(Filename);
    errs() << " done. \n";
  } else {
    sys::ExecuteNoWait(ExecPath, args.data(), nullptr, nullptr, 0, &ErrMsg);
    errs() << "Remember to erase graph file: " << Filename << "\n";
  }
  return false;
}

namespace {
struct GraphSession {
  std::string LogBuffer;
  bool TryFindProgram(StringRef Names, std::string &ProgramPath) {
    raw_string_ostream Log(LogBuffer);
    SmallVector<StringRef, 8> parts;
    Names.split(parts, "|");
    for (auto Name : parts) {
      if (ErrorOr<std::string> P = sys::findProgramByName(Name)) {
        ProgramPath = *P;
        return true;
      }
      Log << "  Tried '" << Name << "'\n";
    }
    return false;
  }
};
} // namespace

static const char *getProgramName(GraphProgram::Name program) {
  switch (program) {
  case GraphProgram::DOT:
    return "dot";
  case GraphProgram::FDP:
    return "fdp";
  case GraphProgram::NEATO:
    return "neato";
  case GraphProgram::TWOPI:
    return "twopi";
  case GraphProgram::CIRCO:
    return "circo";
  }
  llvm_unreachable("bad kind");
}

bool llvm::DisplayGraph(StringRef FilenameRef, bool wait,
                        GraphProgram::Name program) {
  std::string Filename = FilenameRef;
  std::string ErrMsg;
  std::string ViewerPath;
  GraphSession S;

#ifdef __APPLE__
  wait &= !ViewBackground;
  if (S.TryFindProgram("open", ViewerPath)) {
    std::vector<const char *> args;
    args.push_back(ViewerPath.c_str());
    if (wait)
      args.push_back("-W");
    args.push_back(Filename.c_str());
    args.push_back(nullptr);
    errs() << "Trying 'open' program... ";
    if (!ExecGraphViewer(ViewerPath, args, Filename, wait, ErrMsg))
      return false;
  }
#endif
  if (S.TryFindProgram("xdg-open", ViewerPath)) {
    std::vector<const char *> args;
    args.push_back(ViewerPath.c_str());
    args.push_back(Filename.c_str());
    args.push_back(nullptr);
    errs() << "Trying 'xdg-open' program... ";
    if (!ExecGraphViewer(ViewerPath, args, Filename, wait, ErrMsg))
      return false;
  }

  // Graphviz
  if (S.TryFindProgram("Graphviz", ViewerPath)) {
    std::vector<const char *> args;
    args.push_back(ViewerPath.c_str());
    args.push_back(Filename.c_str());
    args.push_back(nullptr);

    errs() << "Running 'Graphviz' program... ";
    return ExecGraphViewer(ViewerPath, args, Filename, wait, ErrMsg);
  }

  // xdot
  if (S.TryFindProgram("xdot|xdot.py", ViewerPath)) {
    std::vector<const char *> args;
    args.push_back(ViewerPath.c_str());
    args.push_back(Filename.c_str());

    args.push_back("-f");
    args.push_back(getProgramName(program));

    args.push_back(nullptr);

    errs() << "Running 'xdot.py' program... ";
    return ExecGraphViewer(ViewerPath, args, Filename, wait, ErrMsg);
  }

  enum PSViewerKind { PSV_None, PSV_OSXOpen, PSV_XDGOpen, PSV_Ghostview };
  PSViewerKind PSViewer = PSV_None;
#ifdef __APPLE__
  if (!PSViewer && S.TryFindProgram("open", ViewerPath))
    PSViewer = PSV_OSXOpen;
#endif
  if (!PSViewer && S.TryFindProgram("gv", ViewerPath))
    PSViewer = PSV_Ghostview;
  if (!PSViewer && S.TryFindProgram("xdg-open", ViewerPath))
    PSViewer = PSV_XDGOpen;

  // PostScript graph generator + PostScript viewer
  std::string GeneratorPath;
  if (PSViewer &&
      (S.TryFindProgram(getProgramName(program), GeneratorPath) ||
       S.TryFindProgram("dot|fdp|neato|twopi|circo", GeneratorPath))) {
    std::string PSFilename = Filename + ".ps";

    std::vector<const char *> args;
    args.push_back(GeneratorPath.c_str());
    args.push_back("-Tps");
    args.push_back("-Nfontname=Courier");
    args.push_back("-Gsize=7.5,10");
    args.push_back(Filename.c_str());
    args.push_back("-o");
    args.push_back(PSFilename.c_str());
    args.push_back(nullptr);

    errs() << "Running '" << GeneratorPath << "' program... ";

    if (ExecGraphViewer(GeneratorPath, args, Filename, wait, ErrMsg))
      return true;

    args.clear();
    args.push_back(ViewerPath.c_str());
    switch (PSViewer) {
    case PSV_OSXOpen:
      args.push_back("-W");
      args.push_back(PSFilename.c_str());
      break;
    case PSV_XDGOpen:
      wait = false;
      args.push_back(PSFilename.c_str());
      break;
    case PSV_Ghostview:
      args.push_back("--spartan");
      args.push_back(PSFilename.c_str());
      break;
    case PSV_None:
      llvm_unreachable("Invalid viewer");
    }
    args.push_back(nullptr);

    ErrMsg.clear();
    return ExecGraphViewer(ViewerPath, args, PSFilename, wait, ErrMsg);
  }

  // dotty
  if (S.TryFindProgram("dotty", ViewerPath)) {
    std::vector<const char *> args;
    args.push_back(ViewerPath.c_str());
    args.push_back(Filename.c_str());
    args.push_back(nullptr);

// Dotty spawns another app and doesn't wait until it returns
#ifdef LLVM_ON_WIN32
    wait = false;
#endif
    errs() << "Running 'dotty' program... ";
    return ExecGraphViewer(ViewerPath, args, Filename, wait, ErrMsg);
  }

  errs() << "Error: Couldn't find a usable graph viewer program:\n";
  errs() << S.LogBuffer << "\n";
  return true;
}
<commit_msg>[Support] Always wait for GraphViz before opening the viewer<commit_after>//===-- GraphWriter.cpp - Implements GraphWriter support routines ---------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements misc. GraphWriter support routines.
//
//===----------------------------------------------------------------------===//

#include "llvm/Support/GraphWriter.h"
#include "llvm/Config/config.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Program.h"
using namespace llvm;

static cl::opt<bool> ViewBackground("view-background", cl::Hidden,
  cl::desc("Execute graph viewer in the background. Creates tmp file litter."));

std::string llvm::DOT::EscapeString(const std::string &Label) {
  std::string Str(Label);
  for (unsigned i = 0; i != Str.length(); ++i)
  switch (Str[i]) {
    case '\n':
      Str.insert(Str.begin()+i, '\\');  // Escape character...
      ++i;
      Str[i] = 'n';
      break;
    case '\t':
      Str.insert(Str.begin()+i, ' ');  // Convert to two spaces
      ++i;
      Str[i] = ' ';
      break;
    case '\\':
      if (i+1 != Str.length())
        switch (Str[i+1]) {
          case 'l': continue; // don't disturb \l
          case '|': case '{': case '}':
            Str.erase(Str.begin()+i); continue;
          default: break;
        }
    case '{': case '}':
    case '<': case '>':
    case '|': case '"':
      Str.insert(Str.begin()+i, '\\');  // Escape character...
      ++i;  // don't infinite loop
      break;
  }
  return Str;
}

/// \brief Get a color string for this node number. Simply round-robin selects
/// from a reasonable number of colors.
StringRef llvm::DOT::getColorString(unsigned ColorNumber) {
  static const int NumColors = 20;
  static const char* Colors[NumColors] = {
    "aaaaaa", "aa0000", "00aa00", "aa5500", "0055ff", "aa00aa", "00aaaa",
    "555555", "ff5555", "55ff55", "ffff55", "5555ff", "ff55ff", "55ffff",
    "ffaaaa", "aaffaa", "ffffaa", "aaaaff", "ffaaff", "aaffff"};
  return Colors[ColorNumber % NumColors];
}

std::string llvm::createGraphFilename(const Twine &Name, int &FD) {
  FD = -1;
  SmallString<128> Filename;
  std::error_code EC = sys::fs::createTemporaryFile(Name, "dot", FD, Filename);
  if (EC) {
    errs() << "Error: " << EC.message() << "\n";
    return "";
  }

  errs() << "Writing '" << Filename << "'... ";
  return Filename.str();
}

// Execute the graph viewer. Return true if there were errors.
static bool ExecGraphViewer(StringRef ExecPath, std::vector<const char *> &args,
                            StringRef Filename, bool wait,
                            std::string &ErrMsg) {
  assert(args.back() == nullptr);
  if (wait) {
    if (sys::ExecuteAndWait(ExecPath, args.data(), nullptr, nullptr, 0, 0,
                            &ErrMsg)) {
      errs() << "Error: " << ErrMsg << "\n";
      return true;
    }
    sys::fs::remove(Filename);
    errs() << " done. \n";
  } else {
    sys::ExecuteNoWait(ExecPath, args.data(), nullptr, nullptr, 0, &ErrMsg);
    errs() << "Remember to erase graph file: " << Filename << "\n";
  }
  return false;
}

namespace {
struct GraphSession {
  std::string LogBuffer;
  bool TryFindProgram(StringRef Names, std::string &ProgramPath) {
    raw_string_ostream Log(LogBuffer);
    SmallVector<StringRef, 8> parts;
    Names.split(parts, "|");
    for (auto Name : parts) {
      if (ErrorOr<std::string> P = sys::findProgramByName(Name)) {
        ProgramPath = *P;
        return true;
      }
      Log << "  Tried '" << Name << "'\n";
    }
    return false;
  }
};
} // namespace

static const char *getProgramName(GraphProgram::Name program) {
  switch (program) {
  case GraphProgram::DOT:
    return "dot";
  case GraphProgram::FDP:
    return "fdp";
  case GraphProgram::NEATO:
    return "neato";
  case GraphProgram::TWOPI:
    return "twopi";
  case GraphProgram::CIRCO:
    return "circo";
  }
  llvm_unreachable("bad kind");
}

bool llvm::DisplayGraph(StringRef FilenameRef, bool wait,
                        GraphProgram::Name program) {
  std::string Filename = FilenameRef;
  std::string ErrMsg;
  std::string ViewerPath;
  GraphSession S;

#ifdef __APPLE__
  wait &= !ViewBackground;
  if (S.TryFindProgram("open", ViewerPath)) {
    std::vector<const char *> args;
    args.push_back(ViewerPath.c_str());
    if (wait)
      args.push_back("-W");
    args.push_back(Filename.c_str());
    args.push_back(nullptr);
    errs() << "Trying 'open' program... ";
    if (!ExecGraphViewer(ViewerPath, args, Filename, wait, ErrMsg))
      return false;
  }
#endif
  if (S.TryFindProgram("xdg-open", ViewerPath)) {
    std::vector<const char *> args;
    args.push_back(ViewerPath.c_str());
    args.push_back(Filename.c_str());
    args.push_back(nullptr);
    errs() << "Trying 'xdg-open' program... ";
    if (!ExecGraphViewer(ViewerPath, args, Filename, wait, ErrMsg))
      return false;
  }

  // Graphviz
  if (S.TryFindProgram("Graphviz", ViewerPath)) {
    std::vector<const char *> args;
    args.push_back(ViewerPath.c_str());
    args.push_back(Filename.c_str());
    args.push_back(nullptr);

    errs() << "Running 'Graphviz' program... ";
    return ExecGraphViewer(ViewerPath, args, Filename, wait, ErrMsg);
  }

  // xdot
  if (S.TryFindProgram("xdot|xdot.py", ViewerPath)) {
    std::vector<const char *> args;
    args.push_back(ViewerPath.c_str());
    args.push_back(Filename.c_str());

    args.push_back("-f");
    args.push_back(getProgramName(program));

    args.push_back(nullptr);

    errs() << "Running 'xdot.py' program... ";
    return ExecGraphViewer(ViewerPath, args, Filename, wait, ErrMsg);
  }

  enum PSViewerKind { PSV_None, PSV_OSXOpen, PSV_XDGOpen, PSV_Ghostview };
  PSViewerKind PSViewer = PSV_None;
#ifdef __APPLE__
  if (!PSViewer && S.TryFindProgram("open", ViewerPath))
    PSViewer = PSV_OSXOpen;
#endif
  if (!PSViewer && S.TryFindProgram("gv", ViewerPath))
    PSViewer = PSV_Ghostview;
  if (!PSViewer && S.TryFindProgram("xdg-open", ViewerPath))
    PSViewer = PSV_XDGOpen;

  // PostScript graph generator + PostScript viewer
  std::string GeneratorPath;
  if (PSViewer &&
      (S.TryFindProgram(getProgramName(program), GeneratorPath) ||
       S.TryFindProgram("dot|fdp|neato|twopi|circo", GeneratorPath))) {
    std::string PSFilename = Filename + ".ps";

    std::vector<const char *> args;
    args.push_back(GeneratorPath.c_str());
    args.push_back("-Tps");
    args.push_back("-Nfontname=Courier");
    args.push_back("-Gsize=7.5,10");
    args.push_back(Filename.c_str());
    args.push_back("-o");
    args.push_back(PSFilename.c_str());
    args.push_back(nullptr);

    errs() << "Running '" << GeneratorPath << "' program... ";

    if (ExecGraphViewer(GeneratorPath, args, Filename, true, ErrMsg))
      return true;

    args.clear();
    args.push_back(ViewerPath.c_str());
    switch (PSViewer) {
    case PSV_OSXOpen:
      args.push_back("-W");
      args.push_back(PSFilename.c_str());
      break;
    case PSV_XDGOpen:
      wait = false;
      args.push_back(PSFilename.c_str());
      break;
    case PSV_Ghostview:
      args.push_back("--spartan");
      args.push_back(PSFilename.c_str());
      break;
    case PSV_None:
      llvm_unreachable("Invalid viewer");
    }
    args.push_back(nullptr);

    ErrMsg.clear();
    return ExecGraphViewer(ViewerPath, args, PSFilename, wait, ErrMsg);
  }

  // dotty
  if (S.TryFindProgram("dotty", ViewerPath)) {
    std::vector<const char *> args;
    args.push_back(ViewerPath.c_str());
    args.push_back(Filename.c_str());
    args.push_back(nullptr);

// Dotty spawns another app and doesn't wait until it returns
#ifdef LLVM_ON_WIN32
    wait = false;
#endif
    errs() << "Running 'dotty' program... ";
    return ExecGraphViewer(ViewerPath, args, Filename, wait, ErrMsg);
  }

  errs() << "Error: Couldn't find a usable graph viewer program:\n";
  errs() << S.LogBuffer << "\n";
  return true;
}
<|endoftext|>


<commit_before>//===- llvm/ADT/SmallVector.cpp - 'Normally small' vectors ----------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the SmallVector class.
//
//===----------------------------------------------------------------------===//

#include "llvm/ADT/SmallVector.h"
using namespace llvm;

/// grow_pod - This is an implementation of the grow() method which only works
/// on POD-like datatypes and is out of line to reduce code duplication.
void SmallVectorBase::grow_pod(void *FirstEl, size_t MinSizeInBytes,
                               size_t TSize) {
  size_t CurSizeBytes = size_in_bytes();
  size_t NewCapacityInBytes = 2 * capacity_in_bytes() + TSize; // Always grow.
  if (NewCapacityInBytes < MinSizeInBytes)
    NewCapacityInBytes = MinSizeInBytes;

  void *NewElts;
  if (BeginX == FirstEl) {
    NewElts = malloc(NewCapacityInBytes);

    // Copy the elements over.  No need to run dtors on PODs.
    memcpy(NewElts, this->BeginX, CurSizeBytes);
  } else {
    // If this wasn't grown from the inline copy, grow the allocated space.
    NewElts = realloc(this->BeginX, NewCapacityInBytes);
  }

  this->EndX = (char*)NewElts+CurSizeBytes;
  this->BeginX = NewElts;
  this->CapacityX = (char*)this->BeginX + NewCapacityInBytes;
}
<commit_msg>[ADT] Assert that SmallVectorBase::grow_pod() successfully reallocates memory.<commit_after>//===- llvm/ADT/SmallVector.cpp - 'Normally small' vectors ----------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the SmallVector class.
//
//===----------------------------------------------------------------------===//

#include "llvm/ADT/SmallVector.h"
using namespace llvm;

/// grow_pod - This is an implementation of the grow() method which only works
/// on POD-like datatypes and is out of line to reduce code duplication.
void SmallVectorBase::grow_pod(void *FirstEl, size_t MinSizeInBytes,
                               size_t TSize) {
  size_t CurSizeBytes = size_in_bytes();
  size_t NewCapacityInBytes = 2 * capacity_in_bytes() + TSize; // Always grow.
  if (NewCapacityInBytes < MinSizeInBytes)
    NewCapacityInBytes = MinSizeInBytes;

  void *NewElts;
  if (BeginX == FirstEl) {
    NewElts = malloc(NewCapacityInBytes);

    // Copy the elements over.  No need to run dtors on PODs.
    memcpy(NewElts, this->BeginX, CurSizeBytes);
  } else {
    // If this wasn't grown from the inline copy, grow the allocated space.
    NewElts = realloc(this->BeginX, NewCapacityInBytes);
  }
  assert(NewElts && "Out of memory");

  this->EndX = (char*)NewElts+CurSizeBytes;
  this->BeginX = NewElts;
  this->CapacityX = (char*)this->BeginX + NewCapacityInBytes;
}
<|endoftext|>


<commit_before>// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "hitcollector.h"
#include <vespa/searchlib/fef/feature_resolver.h>

#include <vespa/log/log.h>
LOG_SETUP(".searchvisitor.hitcollector");

using search::FeatureSet;
using search::fef::MatchData;
using vdslib::SearchResult;

namespace storage {

HitCollector::Hit::Hit(const vsm::StorageDocument *  doc, uint32_t docId, const search::fef::MatchData & matchData,
                       double score, const void * sortData, size_t sortDataLen) :
    _docid(docId),
    _score(score),
    _document(std::move(doc)),
    _matchData(),
    _sortBlob(sortData, sortDataLen)
{
    _matchData.reserve(matchData.getNumTermFields());
    for (search::fef::TermFieldHandle handle = 0; handle < matchData.getNumTermFields(); ++handle) {
        _matchData.emplace_back(*matchData.resolveTermField(handle));
    }
}

HitCollector::Hit::~Hit() { }

HitCollector::HitCollector(size_t wantedHits) :
    _hits(),
    _sortedByDocId(true)
{
    _hits.reserve(wantedHits);
}

const vsm::Document &
HitCollector::getDocSum(const search::DocumentIdT & docId) const
{
    for (const Hit & hit : _hits) {
        if (docId == hit.getDocId()) {
            return hit.getDocument();
        }
    }
    throw std::runtime_error(vespalib::make_string("Could not look up document id %d", docId));
}

bool
HitCollector::addHit(const vsm::StorageDocument * doc, uint32_t docId, const search::fef::MatchData & data, double score)
{
    return addHit(Hit(doc, docId, data, score));
}

bool
HitCollector::addHit(const vsm::StorageDocument * doc, uint32_t docId, const search::fef::MatchData & data,
                     double score, const void * sortData, size_t sortDataLen)
{
    return addHit(Hit(doc, docId, data, score, sortData, sortDataLen));
}

void
HitCollector::sortByDocId()
{
    if (!_sortedByDocId) {
        std::sort(_hits.begin(), _hits.end()); // sort on docId
        _sortedByDocId = true;
    }
}

bool
HitCollector::addHitToHeap(const Hit & hit) const
{
    // return true if the given hit is better than the current worst one.
    return (hit.getSortBlob().empty())
        ? (hit.cmpRank(_hits[0]) < 0)
        : (hit.cmpSort(_hits[0]) < 0);
}

bool
HitCollector::addHit(Hit && hit)
{
    bool amongTheBest(false);
    ssize_t avail = (_hits.capacity() - _hits.size());
    bool useSortBlob( ! hit.getSortBlob().empty() );
    if (avail > 1) {
        // No heap yet.
        _hits.emplace_back(std::move(hit));
        amongTheBest = true;
    } else if (_hits.capacity() == 0) {
        // this happens when wantedHitCount = 0
        // in this case we shall not put anything on the heap (which is empty)
    } else if ( avail == 0 && addHitToHeap(hit)) { // already a heap
        if (useSortBlob) {
            std::pop_heap(_hits.begin(), _hits.end(), Hit::SortComparator());
        } else {
            std::pop_heap(_hits.begin(), _hits.end(), Hit::RankComparator());
        }

        _hits.back() = std::move(hit);
        amongTheBest = true;

        if (useSortBlob) {
            std::push_heap(_hits.begin(), _hits.end(), Hit::SortComparator());
        } else {
            std::push_heap(_hits.begin(), _hits.end(), Hit::RankComparator());
        }
    } else if (avail == 1) { // make a heap of the hit vector
        _hits.emplace_back(std::move(hit));
        amongTheBest = true;
        if (useSortBlob) {
            std::make_heap(_hits.begin(), _hits.end(), Hit::SortComparator());
        } else {
            std::make_heap(_hits.begin(), _hits.end(), Hit::RankComparator());
        }
        _sortedByDocId = false; // the hit vector is no longer sorted by docId
    }
    return amongTheBest;
}

void
HitCollector::fillSearchResult(vdslib::SearchResult & searchResult)
{
    sortByDocId();
    for (const Hit & hit : _hits) {
        vespalib::string documentId(hit.getDocument().docDoc().getId().toString());
        search::DocumentIdT docId = hit.getDocId();
        SearchResult::RankType rank = hit.getRankScore();

        LOG(debug, "fillSearchResult: gDocId(%s), lDocId(%u), rank(%f)", documentId.c_str(), docId, (float)rank);

        if (hit.getSortBlob().empty()) {
            searchResult.addHit(docId, documentId.c_str(), rank);
        } else {
            searchResult.addHit(docId, documentId.c_str(), rank, hit.getSortBlob().c_str(), hit.getSortBlob().size());
        }
    }
}

FeatureSet::SP
HitCollector::getFeatureSet(IRankProgram &rankProgram,
                            const search::fef::FeatureResolver &resolver)
{
    if (resolver.num_features() == 0 || _hits.empty()) {
        return FeatureSet::SP(new FeatureSet());
    }
    sortByDocId();
    std::vector<vespalib::string> names;
    names.reserve(resolver.num_features());
    for (size_t i = 0; i < resolver.num_features(); ++i) {
        names.emplace_back(resolver.name_of(i));
    }
    FeatureSet::SP retval = FeatureSet::SP(new FeatureSet(names, _hits.size()));
    for (const Hit & hit : _hits) {
        rankProgram.run(hit.getDocId(), hit.getMatchData());
        uint32_t docId = hit.getDocId();
        search::feature_t * f = retval->getFeaturesByIndex(retval->addDocId(docId));
        for (uint32_t j = 0; j < names.size(); ++j) {
            f[j] = resolver.resolve(j).as_number(docId);
            LOG(debug, "getFeatureSet: lDocId(%u), '%s': %f", docId, names[j].c_str(), f[j]);
        }
    }
    return retval;
}

} // namespace storage

<commit_msg>No need for std::move<commit_after>// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "hitcollector.h"
#include <vespa/searchlib/fef/feature_resolver.h>

#include <vespa/log/log.h>
LOG_SETUP(".searchvisitor.hitcollector");

using search::FeatureSet;
using search::fef::MatchData;
using vdslib::SearchResult;

namespace storage {

HitCollector::Hit::Hit(const vsm::StorageDocument *  doc, uint32_t docId, const search::fef::MatchData & matchData,
                       double score, const void * sortData, size_t sortDataLen) :
    _docid(docId),
    _score(score),
    _document(doc),
    _matchData(),
    _sortBlob(sortData, sortDataLen)
{
    _matchData.reserve(matchData.getNumTermFields());
    for (search::fef::TermFieldHandle handle = 0; handle < matchData.getNumTermFields(); ++handle) {
        _matchData.emplace_back(*matchData.resolveTermField(handle));
    }
}

HitCollector::Hit::~Hit() { }

HitCollector::HitCollector(size_t wantedHits) :
    _hits(),
    _sortedByDocId(true)
{
    _hits.reserve(wantedHits);
}

const vsm::Document &
HitCollector::getDocSum(const search::DocumentIdT & docId) const
{
    for (const Hit & hit : _hits) {
        if (docId == hit.getDocId()) {
            return hit.getDocument();
        }
    }
    throw std::runtime_error(vespalib::make_string("Could not look up document id %d", docId));
}

bool
HitCollector::addHit(const vsm::StorageDocument * doc, uint32_t docId, const search::fef::MatchData & data, double score)
{
    return addHit(Hit(doc, docId, data, score));
}

bool
HitCollector::addHit(const vsm::StorageDocument * doc, uint32_t docId, const search::fef::MatchData & data,
                     double score, const void * sortData, size_t sortDataLen)
{
    return addHit(Hit(doc, docId, data, score, sortData, sortDataLen));
}

void
HitCollector::sortByDocId()
{
    if (!_sortedByDocId) {
        std::sort(_hits.begin(), _hits.end()); // sort on docId
        _sortedByDocId = true;
    }
}

bool
HitCollector::addHitToHeap(const Hit & hit) const
{
    // return true if the given hit is better than the current worst one.
    return (hit.getSortBlob().empty())
        ? (hit.cmpRank(_hits[0]) < 0)
        : (hit.cmpSort(_hits[0]) < 0);
}

bool
HitCollector::addHit(Hit && hit)
{
    bool amongTheBest(false);
    ssize_t avail = (_hits.capacity() - _hits.size());
    bool useSortBlob( ! hit.getSortBlob().empty() );
    if (avail > 1) {
        // No heap yet.
        _hits.emplace_back(std::move(hit));
        amongTheBest = true;
    } else if (_hits.capacity() == 0) {
        // this happens when wantedHitCount = 0
        // in this case we shall not put anything on the heap (which is empty)
    } else if ( avail == 0 && addHitToHeap(hit)) { // already a heap
        if (useSortBlob) {
            std::pop_heap(_hits.begin(), _hits.end(), Hit::SortComparator());
        } else {
            std::pop_heap(_hits.begin(), _hits.end(), Hit::RankComparator());
        }

        _hits.back() = std::move(hit);
        amongTheBest = true;

        if (useSortBlob) {
            std::push_heap(_hits.begin(), _hits.end(), Hit::SortComparator());
        } else {
            std::push_heap(_hits.begin(), _hits.end(), Hit::RankComparator());
        }
    } else if (avail == 1) { // make a heap of the hit vector
        _hits.emplace_back(std::move(hit));
        amongTheBest = true;
        if (useSortBlob) {
            std::make_heap(_hits.begin(), _hits.end(), Hit::SortComparator());
        } else {
            std::make_heap(_hits.begin(), _hits.end(), Hit::RankComparator());
        }
        _sortedByDocId = false; // the hit vector is no longer sorted by docId
    }
    return amongTheBest;
}

void
HitCollector::fillSearchResult(vdslib::SearchResult & searchResult)
{
    sortByDocId();
    for (const Hit & hit : _hits) {
        vespalib::string documentId(hit.getDocument().docDoc().getId().toString());
        search::DocumentIdT docId = hit.getDocId();
        SearchResult::RankType rank = hit.getRankScore();

        LOG(debug, "fillSearchResult: gDocId(%s), lDocId(%u), rank(%f)", documentId.c_str(), docId, (float)rank);

        if (hit.getSortBlob().empty()) {
            searchResult.addHit(docId, documentId.c_str(), rank);
        } else {
            searchResult.addHit(docId, documentId.c_str(), rank, hit.getSortBlob().c_str(), hit.getSortBlob().size());
        }
    }
}

FeatureSet::SP
HitCollector::getFeatureSet(IRankProgram &rankProgram,
                            const search::fef::FeatureResolver &resolver)
{
    if (resolver.num_features() == 0 || _hits.empty()) {
        return FeatureSet::SP(new FeatureSet());
    }
    sortByDocId();
    std::vector<vespalib::string> names;
    names.reserve(resolver.num_features());
    for (size_t i = 0; i < resolver.num_features(); ++i) {
        names.emplace_back(resolver.name_of(i));
    }
    FeatureSet::SP retval = FeatureSet::SP(new FeatureSet(names, _hits.size()));
    for (const Hit & hit : _hits) {
        rankProgram.run(hit.getDocId(), hit.getMatchData());
        uint32_t docId = hit.getDocId();
        search::feature_t * f = retval->getFeaturesByIndex(retval->addDocId(docId));
        for (uint32_t j = 0; j < names.size(); ++j) {
            f[j] = resolver.resolve(j).as_number(docId);
            LOG(debug, "getFeatureSet: lDocId(%u), '%s': %f", docId, names[j].c_str(), f[j]);
        }
    }
    return retval;
}

} // namespace storage

<|endoftext|>