<commit_before>/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://www.qt.io/licensing.  For further information
** use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "jsonwizard.h"

#include "jsonwizardgeneratorfactory.h"

#include <utils/algorithm.h>
#include <utils/qtcassert.h>

#include <QFileInfo>
#include <QMessageBox>
#include <QVariant>

namespace ProjectExplorer {

JsonWizard::JsonWizard(QWidget *parent) :
    Utils::Wizard(parent)
{
    setMinimumSize(800, 500);
    m_expander.registerExtraResolver([this](const QString &name, QString *ret) -> bool {
        QVariant v = value(name);
        if (v.isValid()) {
            if (v.type() == QVariant::Bool)
                *ret = v.toBool() ? QLatin1String("true") : QString();
            else
                *ret = v.toString();
        }
        return v.isValid();
    });
    m_expander.registerPrefix("Exists", tr("Check whether a variable exists. Returns \"true\" if it does and an empty string if not."),
                   [this](const QString &value) -> QString
    {
        const QString key = QString::fromLatin1("%{") + value + QLatin1Char('}');
        return m_expander.expand(key) == key ? QString() : QLatin1String("true");
    });

}

JsonWizard::~JsonWizard()
{
    qDeleteAll(m_generators);
}

void JsonWizard::addGenerator(JsonWizardGenerator *gen)
{
    QTC_ASSERT(gen, return);
    QTC_ASSERT(!m_generators.contains(gen), return);

    m_generators.append(gen);
}

Utils::MacroExpander *JsonWizard::expander()
{
    return &m_expander;
}

void JsonWizard::resetFileList()
{
    m_files.clear();
}

JsonWizard::GeneratorFiles JsonWizard::fileList()
{
    QString errorMessage;
    GeneratorFiles list;

    QString targetPath = value(QLatin1String("TargetPath")).toString();
    if (targetPath.isEmpty()) {
        errorMessage = tr("Could not determine target path. \"TargetPath\" was not set on any page.");
        return list;
    }

    if (m_files.isEmpty()) {
        emit preGenerateFiles();
        foreach (JsonWizardGenerator *gen, m_generators) {
            Core::GeneratedFiles tmp = gen->fileList(&m_expander, value(QStringLiteral("WizardDir")).toString(),
                                                     targetPath, &errorMessage);
            if (!errorMessage.isEmpty())
                break;
            list.append(Utils::transform(tmp, [&gen](const Core::GeneratedFile &f)
                                              { return JsonWizard::GeneratorFile(f, gen); }));
        }

        if (errorMessage.isEmpty())
            m_files = list;
        emit postGenerateFiles(m_files);
    }

    if (!errorMessage.isEmpty()) {
        QMessageBox::critical(this, tr("File Generation Failed"),
                              tr("The wizard failed to generate files.
"
                                 "The error message was: \"%1\".").arg(errorMessage));
        reject();
        return GeneratorFiles();
    }

    return m_files;
}

QVariant JsonWizard::value(const QString &n) const
{
    QVariant v = property(n.toUtf8());
    if (v.isValid()) {
        if (v.type() == QVariant::String)
            return m_expander.expand(v.toString());
        else
            return v;
    }
    if (hasField(n))
        return field(n); // Can not contain macros!
    return QVariant();
}

void JsonWizard::setValue(const QString &key, const QVariant &value)
{
    setProperty(key.toUtf8(), value);
}

bool JsonWizard::boolFromVariant(const QVariant &v, Utils::MacroExpander *expander)
{
    if (v.type() == QVariant::String)
        return !expander->expand(v.toString()).isEmpty();
    return v.toBool();
}

void JsonWizard::removeAttributeFromAllFiles(Core::GeneratedFile::Attribute a)
{
    for (int i = 0; i < m_files.count(); ++i)
        m_files[i].file.setAttributes(m_files.at(i).file.attributes() ^ a);
}

void JsonWizard::accept()
{
    Utils::Wizard::accept();

    QString errorMessage;
    GeneratorFiles list = fileList();

    if (list.isEmpty())
        return;

    emit prePromptForOverwrite(m_files);
    JsonWizardGenerator::OverwriteResult overwrite =
            JsonWizardGenerator::promptForOverwrite(&list, &errorMessage);
    if (overwrite == JsonWizardGenerator::OverwriteError) {
        if (!errorMessage.isEmpty())
            QMessageBox::warning(this, tr("Failed to Overwrite Files"), errorMessage);
        return;
    }

    emit preFormatFiles(m_files);
    if (!JsonWizardGenerator::formatFiles(this, &list, &errorMessage)) {
        if (!errorMessage.isEmpty())
            QMessageBox::warning(this, tr("Failed to Format Files"), errorMessage);
        return;
    }

    emit preWriteFiles(m_files);
    if (!JsonWizardGenerator::writeFiles(this, &list, &errorMessage)) {
        if (!errorMessage.isEmpty())
            QMessageBox::warning(this, tr("Failed to Write Files"), errorMessage);
        return;
    }

    emit postProcessFiles(m_files);
    if (!JsonWizardGenerator::postWrite(this, &list, &errorMessage)) {
        if (!errorMessage.isEmpty())
            QMessageBox::warning(this, tr("Failed to Post-Process Files"), errorMessage);
        return;
    }
    emit filesReady(m_files);
    if (!JsonWizardGenerator::allDone(this, &list, &errorMessage)) {
        if (!errorMessage.isEmpty())
            QMessageBox::warning(this, tr("Failed to Open Files"), errorMessage);
        return;
    }

    emit allDone(m_files);
}

} // namespace ProjectExplorer
<commit_msg>JsonWizard: Use up-to-date file information<commit_after>/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://www.qt.io/licensing.  For further information
** use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "jsonwizard.h"

#include "jsonwizardgeneratorfactory.h"

#include <utils/algorithm.h>
#include <utils/qtcassert.h>

#include <QFileInfo>
#include <QMessageBox>
#include <QVariant>

namespace ProjectExplorer {

JsonWizard::JsonWizard(QWidget *parent) :
    Utils::Wizard(parent)
{
    setMinimumSize(800, 500);
    m_expander.registerExtraResolver([this](const QString &name, QString *ret) -> bool {
        QVariant v = value(name);
        if (v.isValid()) {
            if (v.type() == QVariant::Bool)
                *ret = v.toBool() ? QLatin1String("true") : QString();
            else
                *ret = v.toString();
        }
        return v.isValid();
    });
    m_expander.registerPrefix("Exists", tr("Check whether a variable exists. Returns \"true\" if it does and an empty string if not."),
                   [this](const QString &value) -> QString
    {
        const QString key = QString::fromLatin1("%{") + value + QLatin1Char('}');
        return m_expander.expand(key) == key ? QString() : QLatin1String("true");
    });

}

JsonWizard::~JsonWizard()
{
    qDeleteAll(m_generators);
}

void JsonWizard::addGenerator(JsonWizardGenerator *gen)
{
    QTC_ASSERT(gen, return);
    QTC_ASSERT(!m_generators.contains(gen), return);

    m_generators.append(gen);
}

Utils::MacroExpander *JsonWizard::expander()
{
    return &m_expander;
}

void JsonWizard::resetFileList()
{
    m_files.clear();
}

JsonWizard::GeneratorFiles JsonWizard::fileList()
{
    QString errorMessage;
    GeneratorFiles list;

    QString targetPath = value(QLatin1String("TargetPath")).toString();
    if (targetPath.isEmpty()) {
        errorMessage = tr("Could not determine target path. \"TargetPath\" was not set on any page.");
        return list;
    }

    if (m_files.isEmpty()) {
        emit preGenerateFiles();
        foreach (JsonWizardGenerator *gen, m_generators) {
            Core::GeneratedFiles tmp = gen->fileList(&m_expander, value(QStringLiteral("WizardDir")).toString(),
                                                     targetPath, &errorMessage);
            if (!errorMessage.isEmpty())
                break;
            list.append(Utils::transform(tmp, [&gen](const Core::GeneratedFile &f)
                                              { return JsonWizard::GeneratorFile(f, gen); }));
        }

        if (errorMessage.isEmpty())
            m_files = list;
        emit postGenerateFiles(m_files);
    }

    if (!errorMessage.isEmpty()) {
        QMessageBox::critical(this, tr("File Generation Failed"),
                              tr("The wizard failed to generate files.
"
                                 "The error message was: \"%1\".").arg(errorMessage));
        reject();
        return GeneratorFiles();
    }

    return m_files;
}

QVariant JsonWizard::value(const QString &n) const
{
    QVariant v = property(n.toUtf8());
    if (v.isValid()) {
        if (v.type() == QVariant::String)
            return m_expander.expand(v.toString());
        else
            return v;
    }
    if (hasField(n))
        return field(n); // Can not contain macros!
    return QVariant();
}

void JsonWizard::setValue(const QString &key, const QVariant &value)
{
    setProperty(key.toUtf8(), value);
}

bool JsonWizard::boolFromVariant(const QVariant &v, Utils::MacroExpander *expander)
{
    if (v.type() == QVariant::String)
        return !expander->expand(v.toString()).isEmpty();
    return v.toBool();
}

void JsonWizard::removeAttributeFromAllFiles(Core::GeneratedFile::Attribute a)
{
    for (int i = 0; i < m_files.count(); ++i)
        m_files[i].file.setAttributes(m_files.at(i).file.attributes() ^ a);
}

void JsonWizard::accept()
{
    Utils::Wizard::accept();

    QString errorMessage;
    if (fileList().isEmpty())
        return;

    emit prePromptForOverwrite(m_files);
    JsonWizardGenerator::OverwriteResult overwrite =
            JsonWizardGenerator::promptForOverwrite(&m_files, &errorMessage);
    if (overwrite == JsonWizardGenerator::OverwriteError) {
        if (!errorMessage.isEmpty())
            QMessageBox::warning(this, tr("Failed to Overwrite Files"), errorMessage);
        return;
    }

    emit preFormatFiles(m_files);
    if (!JsonWizardGenerator::formatFiles(this, &m_files, &errorMessage)) {
        if (!errorMessage.isEmpty())
            QMessageBox::warning(this, tr("Failed to Format Files"), errorMessage);
        return;
    }

    emit preWriteFiles(m_files);
    if (!JsonWizardGenerator::writeFiles(this, &m_files, &errorMessage)) {
        if (!errorMessage.isEmpty())
            QMessageBox::warning(this, tr("Failed to Write Files"), errorMessage);
        return;
    }

    emit postProcessFiles(m_files);
    if (!JsonWizardGenerator::postWrite(this, &m_files, &errorMessage)) {
        if (!errorMessage.isEmpty())
            QMessageBox::warning(this, tr("Failed to Post-Process Files"), errorMessage);
        return;
    }
    emit filesReady(m_files);
    if (!JsonWizardGenerator::allDone(this, &m_files, &errorMessage)) {
        if (!errorMessage.isEmpty())
            QMessageBox::warning(this, tr("Failed to Open Files"), errorMessage);
        return;
    }

    emit allDone(m_files);
}

} // namespace ProjectExplorer
<|endoftext|>


<commit_before>#include <assert.h>
#include <cstdio>

#include <set>

#ifndef HAVE_LLVM
#error "This code needs LLVM enabled"
#endif

#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Module.h>
#include <llvm/IR/Instructions.h>
#include <llvm/Support/SourceMgr.h>
#include <llvm/Support/raw_os_ostream.h>
#include <llvm/IRReader/IRReader.h>
#include <llvm/Bitcode/ReaderWriter.h>

#include <iostream>
#include <sstream>
#include <fstream>
#include <string>

#include "llvm/analysis/PointsTo.h"

#include "analysis/PointsTo/PointsToFlowInsensitive.h"
#include "analysis/PointsTo/PointsToFlowSensitive.h"
#include "analysis/PointsTo/Pointer.h"

#include "Utils.h"

using namespace dg;
using namespace dg::analysis::pss;
using llvm::errs;

enum PTType {
    FLOW_SENSITIVE = 1,
    FLOW_INSENSITIVE,
};

static std::string
getInstName(const llvm::Value *val)
{
    std::ostringstream ostr;
    llvm::raw_os_ostream ro(ostr);

    assert(val);
    ro << *val;
    ro.flush();

    // break the string if it is too long
    return ostr.str();
}

static void
printName(PSSNode *node)
{
    const char *name = node->getName();
    std::string nm;
    if (!name) {
        if (!node->getUserData<llvm::Value>()) {
            printf("%p\n", node);

            return;
        }

        nm = getInstName(node->getUserData<llvm::Value>());
        name = nm.c_str();
    }

    // escape the " character
    for (int i = 0; name[i] != '\0'; ++i) {
        // crop long names
        if (i >= 70) {
            printf(" ...");
            break;
        }

        if (name[i] == '"')
            putchar('\\');

        putchar(name[i]);
    }
}

static void
dumpPSSNode(PSSNode *n)
{
    const char *name = n->getName();

    printf("NODE: ");
    printName(n);

    if (n->getSize() || n->isHeap() || n->isZeroInitialized())
        printf(" [size: %lu, heap: %u, zeroed: %u]",
               n->getSize(), n->isHeap(), n->isZeroInitialized());

    if (n->pointsTo.empty()) {
        puts(" -- no points-to");
        return;
    } else
        putchar('\n');

    for (const Pointer& ptr : n->pointsTo) {
        printf("    -> ");
        printName(ptr.target);
        if (ptr.offset.isUnknown())
            puts(" + UNKNOWN_OFFSET");
        else
            printf(" + %lu\n", *ptr.offset);
    }
}

static bool verify_ptsets(LLVMPointsToAnalysis *fi, LLVMPointsToAnalysis *fs)
{
    bool ok = true;
    const std::unordered_map<const llvm::Value *, PSSNode *>& mp = fi->getNodesMap();
    for (auto it : mp) {
        PSSNode *fsnode = fs->getPointsTo(it.first);
        if (!fsnode) {
            llvm::errs() << "FS don't have points-to for: " << *it.first << "\n"
                         << "but FI has:\n";
            dumpPSSNode(it.second);
            ok = false;
            continue;
        }

        if (!it.second) {
            llvm::errs() << "PSS node is null: " << *it.first << "\n";
            ok = false;
            continue;
        }

        for (const Pointer& ptr : fsnode->pointsTo) {
            bool found = false;
            for (const Pointer& ptr2 : it.second->pointsTo) {
                // FIXME: what about UNKNOWN_OFFSETS?
                if ((ptr2.target->getUserData<llvm::Value>()
                    == ptr.target->getUserData<llvm::Value>())
                    && (ptr2.offset == ptr.offset)) {
                    found = true;
                    break;
                }
            }

            if (!found) {
                    llvm::errs() << "FS not subset of FI: " << *it.first << "\n";
                    llvm::errs() << "FI:\n";
                    dumpPSSNode(it.second);
                    llvm::errs() << "FS:\n";
                    dumpPSSNode(fsnode);
                    llvm::errs() << " ---- \n";
                    ok = false;
            }
        }
    }

    return ok;
}

int main(int argc, char *argv[])
{
    llvm::Module *M;
    llvm::LLVMContext context;
    llvm::SMDiagnostic SMD;
    const char *module = nullptr;
    unsigned type = FLOW_SENSITIVE | FLOW_INSENSITIVE;

    // parse options
    for (int i = 1; i < argc; ++i) {
        // run only given points-to analysis
        if (strcmp(argv[i], "-pta") == 0) {
            if (strcmp(argv[i+1], "fs") == 0)
                type = FLOW_SENSITIVE;
            else if (strcmp(argv[i+1], "fi") == 0)
                type = FLOW_INSENSITIVE;
            else {
                errs() << "Unknown PTA type" << argv[i + 1] << "\n";
                abort();
            }
        /*} else if (strcmp(argv[i], "-v") == 0) {
            verbose = true;*/
        } else {
            module = argv[i];
        }
    }

    if (!module) {
        errs() << "Usage: % llvm-pss-compare [-pta fs|fi] IR_module\n";
        return 1;
    }

#if (LLVM_VERSION_MINOR < 5)
    M = llvm::ParseIRFile(module, SMD, context);
#else
    auto _M = llvm::parseIRFile(module, SMD, context);
    // _M is unique pointer, we need to get Module *
    M = &*_M;
#endif

    debug::TimeMeasure tm;

    LLVMPointsToAnalysis *PTAfs;
    LLVMPointsToAnalysis *PTAfi;
    if (type & FLOW_INSENSITIVE) {
        PTAfi = new LLVMPointsToAnalysisImpl<analysis::pss::PointsToFlowInsensitive>(M);

        tm.start();
        PTAfi->run();
        tm.stop();
        tm.report("INFO: Points-to flow-insensitive analysis took");
    }

    if (type & FLOW_SENSITIVE) {
            PTAfs = new LLVMPointsToAnalysisImpl<analysis::pss::PointsToFlowSensitive>(M);
        tm.start();
        PTAfs->run();
        tm.stop();
        tm.report("INFO: Points-to flow-sensitive analysis took");
    }

    int ret = 0;
    if (type == (FLOW_SENSITIVE | FLOW_INSENSITIVE)) {
        ret = !verify_ptsets(PTAfi, PTAfs);
        if (ret == 0)
            llvm::errs() << "FS is a subset of FI, all OK\n";
    }

    return ret;
}
<commit_msg>llvm-pss-compare: handle UNKNOWN_OFFSET<commit_after>#include <assert.h>
#include <cstdio>

#include <set>

#ifndef HAVE_LLVM
#error "This code needs LLVM enabled"
#endif

#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Module.h>
#include <llvm/IR/Instructions.h>
#include <llvm/Support/SourceMgr.h>
#include <llvm/Support/raw_os_ostream.h>
#include <llvm/IRReader/IRReader.h>
#include <llvm/Bitcode/ReaderWriter.h>

#include <iostream>
#include <sstream>
#include <fstream>
#include <string>

#include "llvm/analysis/PointsTo.h"

#include "analysis/PointsTo/PointsToFlowInsensitive.h"
#include "analysis/PointsTo/PointsToFlowSensitive.h"
#include "analysis/PointsTo/Pointer.h"

#include "Utils.h"

using namespace dg;
using namespace dg::analysis::pss;
using llvm::errs;

enum PTType {
    FLOW_SENSITIVE = 1,
    FLOW_INSENSITIVE,
};

static std::string
getInstName(const llvm::Value *val)
{
    std::ostringstream ostr;
    llvm::raw_os_ostream ro(ostr);

    assert(val);
    ro << *val;
    ro.flush();

    // break the string if it is too long
    return ostr.str();
}

static void
printName(PSSNode *node)
{
    const char *name = node->getName();
    std::string nm;
    if (!name) {
        if (!node->getUserData<llvm::Value>()) {
            printf("%p\n", node);

            return;
        }

        nm = getInstName(node->getUserData<llvm::Value>());
        name = nm.c_str();
    }

    // escape the " character
    for (int i = 0; name[i] != '\0'; ++i) {
        // crop long names
        if (i >= 70) {
            printf(" ...");
            break;
        }

        if (name[i] == '"')
            putchar('\\');

        putchar(name[i]);
    }
}

static void
dumpPSSNode(PSSNode *n)
{
    const char *name = n->getName();

    printf("NODE: ");
    printName(n);

    if (n->getSize() || n->isHeap() || n->isZeroInitialized())
        printf(" [size: %lu, heap: %u, zeroed: %u]",
               n->getSize(), n->isHeap(), n->isZeroInitialized());

    if (n->pointsTo.empty()) {
        puts(" -- no points-to");
        return;
    } else
        putchar('\n');

    for (const Pointer& ptr : n->pointsTo) {
        printf("    -> ");
        printName(ptr.target);
        if (ptr.offset.isUnknown())
            puts(" + UNKNOWN_OFFSET");
        else
            printf(" + %lu\n", *ptr.offset);
    }
}

static bool verify_ptsets(LLVMPointsToAnalysis *fi, LLVMPointsToAnalysis *fs)
{
    bool ok = true;
    const std::unordered_map<const llvm::Value *, PSSNode *>& mp = fi->getNodesMap();
    for (auto it : mp) {
        PSSNode *fsnode = fs->getPointsTo(it.first);
        if (!fsnode) {
            llvm::errs() << "FS don't have points-to for: " << *it.first << "\n"
                         << "but FI has:\n";
            dumpPSSNode(it.second);
            ok = false;
            continue;
        }

        if (!it.second) {
            llvm::errs() << "PSS node is null: " << *it.first << "\n";
            ok = false;
            continue;
        }

        for (const Pointer& ptr : fsnode->pointsTo) {
            bool found = false;
            for (const Pointer& ptr2 : it.second->pointsTo) {
                // either the pointer is there or
                // FS has (target, offset) and FI has (target, UNKNOWN_OFFSET),
                // than everything is fine. The other case (FS has UNKNOWN_OFFSET)
                // we don't consider here, since that should not happen
                if ((ptr2.target->getUserData<llvm::Value>()
                    == ptr.target->getUserData<llvm::Value>())
                    && (ptr2.offset == ptr.offset ||
                        ptr2.offset.isUnknown()
                        /* || ptr.offset.isUnknown()*/)) {
                    found = true;
                    break;
                }
            }

            if (!found) {
                    llvm::errs() << "FS not subset of FI: " << *it.first << "\n";
                    llvm::errs() << "FI:\n";
                    dumpPSSNode(it.second);
                    llvm::errs() << "FS:\n";
                    dumpPSSNode(fsnode);
                    llvm::errs() << " ---- \n";
                    ok = false;
            }
        }
    }

    return ok;
}

int main(int argc, char *argv[])
{
    llvm::Module *M;
    llvm::LLVMContext context;
    llvm::SMDiagnostic SMD;
    const char *module = nullptr;
    unsigned type = FLOW_SENSITIVE | FLOW_INSENSITIVE;

    // parse options
    for (int i = 1; i < argc; ++i) {
        // run only given points-to analysis
        if (strcmp(argv[i], "-pta") == 0) {
            if (strcmp(argv[i+1], "fs") == 0)
                type = FLOW_SENSITIVE;
            else if (strcmp(argv[i+1], "fi") == 0)
                type = FLOW_INSENSITIVE;
            else {
                errs() << "Unknown PTA type" << argv[i + 1] << "\n";
                abort();
            }
        /*} else if (strcmp(argv[i], "-v") == 0) {
            verbose = true;*/
        } else {
            module = argv[i];
        }
    }

    if (!module) {
        errs() << "Usage: % llvm-pss-compare [-pta fs|fi] IR_module\n";
        return 1;
    }

#if (LLVM_VERSION_MINOR < 5)
    M = llvm::ParseIRFile(module, SMD, context);
#else
    auto _M = llvm::parseIRFile(module, SMD, context);
    // _M is unique pointer, we need to get Module *
    M = &*_M;
#endif

    debug::TimeMeasure tm;

    LLVMPointsToAnalysis *PTAfs;
    LLVMPointsToAnalysis *PTAfi;
    if (type & FLOW_INSENSITIVE) {
        PTAfi = new LLVMPointsToAnalysisImpl<analysis::pss::PointsToFlowInsensitive>(M);

        tm.start();
        PTAfi->run();
        tm.stop();
        tm.report("INFO: Points-to flow-insensitive analysis took");
    }

    if (type & FLOW_SENSITIVE) {
            PTAfs = new LLVMPointsToAnalysisImpl<analysis::pss::PointsToFlowSensitive>(M);
        tm.start();
        PTAfs->run();
        tm.stop();
        tm.report("INFO: Points-to flow-sensitive analysis took");
    }

    int ret = 0;
    if (type == (FLOW_SENSITIVE | FLOW_INSENSITIVE)) {
        ret = !verify_ptsets(PTAfi, PTAfs);
        if (ret == 0)
            llvm::errs() << "FS is a subset of FI, all OK\n";
    }

    return ret;
}
<|endoftext|>


<commit_before>#include <vector>
#include <fstream>

#include "board.hpp"
#include "config.hpp"
#include "log.hpp"

namespace roadagain
{

Log::Log(int y, int x, BoardState stone) : y(y), x(x), stone(stone)
{
}

void log_records(std::vector<Log>& logs, BoardState winner)
{
    int size = logs.size();
    std::ofstream log_file(Config::instance().log_file().c_str());
    for (int i = 0; i < size; i++){
        if (logs[i].stone == BLACK){
            log_file << 'B';
        }
        else {
            log_file << 'W';
        }
        log_file << ' ' << (char)('a' + logs[i].x);
        log_file << ' ' << logs[i].y;
        log_file << '\n';
    }
    if (winner == BLACK){
        log_file << "Winner is Blackn";
    }
    else if (winner == WHITE){
        log_file << "Winner is Whiten";
    }
    else {
        log_file << "Drawn";
    }
    log_file << '\n';

    log_file.close();
}

}
<commit_msg>Check log is available<commit_after>#include <vector>
#include <fstream>

#include "board.hpp"
#include "config.hpp"
#include "log.hpp"

namespace roadagain
{

Log::Log(int y, int x, BoardState stone) : y(y), x(x), stone(stone)
{
}

void log_records(std::vector<Log>& logs, BoardState winner)
{
    Config& config = Config::instance();

    if (config.log_file().empty()){
        return;
    }

    int size = logs.size();
    std::ofstream log_file(config.log_file().c_str());
    for (int i = 0; i < size; i++){
        if (logs[i].stone == BLACK){
            log_file << 'B';
        }
        else {
            log_file << 'W';
        }
        log_file << ' ' << (char)('a' + logs[i].x);
        log_file << ' ' << logs[i].y;
        log_file << '\n';
    }
    if (winner == BLACK){
        log_file << "Winner is Blackn";
    }
    else if (winner == WHITE){
        log_file << "Winner is Whiten";
    }
    else {
        log_file << "Drawn";
    }
    log_file << '\n';

    log_file.close();
}

}
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////
//
// Copyright 2016 Realm Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////

#include "sync/impl/apple/network_reachability_observer.hpp"

#if NETWORK_REACHABILITY_AVAILABLE

using namespace realm;

namespace {

static NetworkReachabilityStatus reachability_status_for_flags(SCNetworkReachabilityFlags flags)
{
    if (!(flags & kSCNetworkReachabilityFlagsReachable))
        return NotReachable;

    if (flags & kSCNetworkReachabilityFlagsConnectionRequired) {
        if (!(flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) ||
            (flags & kSCNetworkReachabilityFlagsInterventionRequired)) {
            return NotReachable;
        }
    }

    NetworkReachabilityStatus status = ReachableViaWiFi;

#if TARGET_OS_IPHONE
    if (flags & kSCNetworkReachabilityFlagsIsWWAN) {
        status = ReachableViaWWAN;
    }
#endif

    return status;
}

static void reachability_callback(SCNetworkReachabilityRef, SCNetworkReachabilityFlags, void* info)
{
    auto callback = reinterpret_cast<std::function<void ()> *>(info);
    (*callback)();
}

} // (anonymous namespace)

NetworkReachabilityObserver::NetworkReachabilityObserver(util::Optional<std::string> hostname,
                                                         std::function<void (const NetworkReachabilityStatus)> handler)
: m_callback_queue(dispatch_queue_create("io.realm.sync.reachability", DISPATCH_QUEUE_SERIAL))
, m_reachability_callback([=]() { reachability_changed(); })
, m_change_handler(std::move(handler))
{
    if (hostname) {
        m_reachability_ref = util::adoptCF(SCNetworkReachabilityCreateWithName(nullptr, hostname->c_str()));
    } else {
        struct sockaddr zeroAddress = {};
        zeroAddress.sa_len = sizeof(zeroAddress);
        zeroAddress.sa_family = AF_INET;

        m_reachability_ref = util::adoptCF(SCNetworkReachabilityCreateWithAddress(nullptr, &zeroAddress));
    }
}

NetworkReachabilityObserver::~NetworkReachabilityObserver()
{
    stop_observing();
    dispatch_release(m_callback_queue);
}

NetworkReachabilityStatus NetworkReachabilityObserver::reachability_status() const
{
    SCNetworkReachabilityFlags flags;

    if (SCNetworkReachabilityGetFlags(m_reachability_ref.get(), &flags)) {
        return reachability_status_for_flags(flags);
    }

    return NotReachable;
}

bool NetworkReachabilityObserver::start_observing()
{
    m_previous_status = reachability_status();

    SCNetworkReachabilityContext context = {0, &m_reachability_callback, nullptr, nullptr, nullptr};

    if (!SCNetworkReachabilitySetCallback(m_reachability_ref.get(), reachability_callback, &context)) {
        return false;
    }

    if (!SCNetworkReachabilitySetDispatchQueue(m_reachability_ref.get(), m_callback_queue)) {
        return false;
    }

    return true;
}

void NetworkReachabilityObserver::stop_observing()
{
    SCNetworkReachabilitySetDispatchQueue(m_reachability_ref.get(), nullptr);
    SCNetworkReachabilitySetCallback(m_reachability_ref.get(), nullptr, nullptr);

    // Wait for all previously-enqueued blocks to execute to guarantee that
    // no callback will be called after returning from this method
    dispatch_sync(m_callback_queue, ^{});
}

void NetworkReachabilityObserver::reachability_changed()
{
    auto current_status = reachability_status();

    // When observing reachability of the specific host the callback might be called
    // several times (because of DNS queries) with the same reachability flags while
    // the caller should be notified only when the reachability status is really changed.
    if (current_status != m_previous_status) {
        m_change_handler(current_status);
        m_previous_status = current_status;
    }
}

#endif
<commit_msg>remove extra braces<commit_after>////////////////////////////////////////////////////////////////////////////
//
// Copyright 2016 Realm Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////

#include "sync/impl/apple/network_reachability_observer.hpp"

#if NETWORK_REACHABILITY_AVAILABLE

using namespace realm;

namespace {

static NetworkReachabilityStatus reachability_status_for_flags(SCNetworkReachabilityFlags flags)
{
    if (!(flags & kSCNetworkReachabilityFlagsReachable))
        return NotReachable;

    if (flags & kSCNetworkReachabilityFlagsConnectionRequired) {
        if (!(flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) ||
            (flags & kSCNetworkReachabilityFlagsInterventionRequired))
            return NotReachable;
    }

    NetworkReachabilityStatus status = ReachableViaWiFi;

#if TARGET_OS_IPHONE
    if (flags & kSCNetworkReachabilityFlagsIsWWAN) {
        status = ReachableViaWWAN;
    }
#endif

    return status;
}

static void reachability_callback(SCNetworkReachabilityRef, SCNetworkReachabilityFlags, void* info)
{
    auto callback = reinterpret_cast<std::function<void ()> *>(info);
    (*callback)();
}

} // (anonymous namespace)

NetworkReachabilityObserver::NetworkReachabilityObserver(util::Optional<std::string> hostname,
                                                         std::function<void (const NetworkReachabilityStatus)> handler)
: m_callback_queue(dispatch_queue_create("io.realm.sync.reachability", DISPATCH_QUEUE_SERIAL))
, m_reachability_callback([=]() { reachability_changed(); })
, m_change_handler(std::move(handler))
{
    if (hostname) {
        m_reachability_ref = util::adoptCF(SCNetworkReachabilityCreateWithName(nullptr, hostname->c_str()));
    } else {
        struct sockaddr zeroAddress = {};
        zeroAddress.sa_len = sizeof(zeroAddress);
        zeroAddress.sa_family = AF_INET;

        m_reachability_ref = util::adoptCF(SCNetworkReachabilityCreateWithAddress(nullptr, &zeroAddress));
    }
}

NetworkReachabilityObserver::~NetworkReachabilityObserver()
{
    stop_observing();
    dispatch_release(m_callback_queue);
}

NetworkReachabilityStatus NetworkReachabilityObserver::reachability_status() const
{
    SCNetworkReachabilityFlags flags;

    if (SCNetworkReachabilityGetFlags(m_reachability_ref.get(), &flags)) {
        return reachability_status_for_flags(flags);
    }

    return NotReachable;
}

bool NetworkReachabilityObserver::start_observing()
{
    m_previous_status = reachability_status();

    SCNetworkReachabilityContext context = {0, &m_reachability_callback, nullptr, nullptr, nullptr};

    if (!SCNetworkReachabilitySetCallback(m_reachability_ref.get(), reachability_callback, &context)) {
        return false;
    }

    if (!SCNetworkReachabilitySetDispatchQueue(m_reachability_ref.get(), m_callback_queue)) {
        return false;
    }

    return true;
}

void NetworkReachabilityObserver::stop_observing()
{
    SCNetworkReachabilitySetDispatchQueue(m_reachability_ref.get(), nullptr);
    SCNetworkReachabilitySetCallback(m_reachability_ref.get(), nullptr, nullptr);

    // Wait for all previously-enqueued blocks to execute to guarantee that
    // no callback will be called after returning from this method
    dispatch_sync(m_callback_queue, ^{});
}

void NetworkReachabilityObserver::reachability_changed()
{
    auto current_status = reachability_status();

    // When observing reachability of the specific host the callback might be called
    // several times (because of DNS queries) with the same reachability flags while
    // the caller should be notified only when the reachability status is really changed.
    if (current_status != m_previous_status) {
        m_change_handler(current_status);
        m_previous_status = current_status;
    }
}

#endif
<|endoftext|>


<commit_before>/*
 * Copyright (c) 1998-2001, Index Data.
 * See the file LICENSE for details.
 *
 * $Id: yaz-socket-manager.cpp,v 1.20 2003-07-25 19:27:36 adam Exp $
 */
#include <assert.h>
#ifdef WIN32
#include <winsock.h>
#else
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#endif
#include <errno.h>
#include <string.h>

#include <yaz/log.h>
#include <yaz++/socket-manager.h>

Yaz_SocketManager::YazSocketEntry **Yaz_SocketManager::lookupObserver(
    IYazSocketObserver *observer)
{
    YazSocketEntry **se;

    for (se = &m_observers; *se; se = &(*se)->next)
	if ((*se)->observer == observer)
	    break;
    return se;
}

void Yaz_SocketManager::addObserver(int fd, IYazSocketObserver *observer)
{
    YazSocketEntry *se;

    se = *lookupObserver(observer);
    if (!se)
    {
	se = new YazSocketEntry;
	se->next= m_observers;
	m_observers = se;
	se->observer = observer;
    }
    se->fd = fd;
    se->mask = 0;
    se->last_activity = 0;
    se->timeout = 0;
}

void Yaz_SocketManager::deleteObserver(IYazSocketObserver *observer)
{
    YazSocketEntry **se = lookupObserver(observer);
    if (*se)
    {
	removeEvent (observer);
	YazSocketEntry *se_tmp = *se;
	*se = (*se)->next;
	delete se_tmp;
    }
}

void Yaz_SocketManager::deleteObservers()
{
    YazSocketEntry *se = m_observers;

    while (se)
    {
	YazSocketEntry *se_next = se->next;
	delete se;
	se = se_next;
    }
    m_observers = 0;
}

void Yaz_SocketManager::maskObserver(IYazSocketObserver *observer, int mask)
{
    YazSocketEntry *se;

    yaz_log(m_log, "obs=%p read=%d write=%d except=%d", observer,
	            mask & YAZ_SOCKET_OBSERVE_READ,
	            mask & YAZ_SOCKET_OBSERVE_WRITE,
	            mask & YAZ_SOCKET_OBSERVE_EXCEPT);

    se = *lookupObserver(observer);
    if (se)
	se->mask = mask;
}

void Yaz_SocketManager::timeoutObserver(IYazSocketObserver *observer,
					unsigned timeout)
{
    YazSocketEntry *se;

    se = *lookupObserver(observer);
    if (se)
	se->timeout = timeout;
}

int Yaz_SocketManager::processEvent()
{
    YazSocketEntry *p;
    YazSocketEvent *event = getEvent();
    unsigned timeout = 0;
    yaz_log (m_log, "Yaz_SocketManager::processEvent manager=%p", this);
    if (event)
    {
	event->observer->socketNotify(event->event);
	delete event;
	return 1;
    }

    fd_set in, out, except;
    int res;
    int max = 0;
    int no = 0;

    FD_ZERO(&in);
    FD_ZERO(&out);
    FD_ZERO(&except);

    time_t now = time(0);
    for (p = m_observers; p; p = p->next)
    {
	int fd = p->fd;
	if (p->mask)
	    no++;
	if (p->mask & YAZ_SOCKET_OBSERVE_READ)
        {
            yaz_log (m_log, "Yaz_SocketManager::select fd=%d read", fd);
	    FD_SET(fd, &in);
        }
	if (p->mask & YAZ_SOCKET_OBSERVE_WRITE)
        {
            yaz_log (m_log, "Yaz_SocketManager::select fd=%d write", fd);
	    FD_SET(fd, &out);
        }
	if (p->mask & YAZ_SOCKET_OBSERVE_EXCEPT)
        {
            yaz_log (m_log, "Yaz_SocketManager::select fd=%d except", fd);
	    FD_SET(fd, &except);
        }
	if (fd > max)
	    max = fd;
	if (p->timeout)
	{
	    unsigned timeout_this;
	    timeout_this = p->timeout;
	    if (p->last_activity)
		timeout_this -= now - p->last_activity;
	    else
		p->last_activity = now;
	    if (timeout_this < 1 || timeout_this > 2147483646)
		timeout_this = 1;
	    if (!timeout || timeout_this < timeout)
		timeout = timeout_this;
            p->timeout_this = timeout_this;
            yaz_log (m_log, "Yaz_SocketManager::select timeout_this=%d",
                     p->timeout_this);
	}
    }
    if (!no)
    {
	yaz_log (m_log, "no pending events return 0");
	if (!m_observers)
	    yaz_log (m_log, "no observers");
	return 0;
    }

    struct timeval to;
    to.tv_sec = timeout;
    to.tv_usec = 0;

    yaz_log (m_log, "Yaz_SocketManager::select begin no=%d timeout=%d",
             no, timeout);
    while ((res = select(max + 1, &in, &out, &except, timeout ? &to : 0)) < 0)
	if (errno != EINTR)
	{
	    yaz_log (LOG_LOG|LOG_WARN, "select");
	    return -1;
	}
    now = time(0);
    for (p = m_observers; p; p = p->next)
    {
	int fd = p->fd;
	int mask = 0;
	if (FD_ISSET(fd, &in))
	    mask |= YAZ_SOCKET_OBSERVE_READ;

	if (FD_ISSET(fd, &out))
	    mask |= YAZ_SOCKET_OBSERVE_WRITE;

	if (FD_ISSET(fd, &except))
	    mask |= YAZ_SOCKET_OBSERVE_EXCEPT;

	if (mask)
	{
	    YazSocketEvent *event = new YazSocketEvent;
	    p->last_activity = now;
	    event->observer = p->observer;
	    event->event = mask;
	    putEvent (event);
	}
	else if (res == 0 && p->timeout && p->timeout_this == timeout)
	{
	    YazSocketEvent *event = new YazSocketEvent;
            assert (p->last_activity);
	    yaz_log (m_log, "timeout, now = %ld last_activity=%ld timeout=%d",
                     now, p->last_activity, p->timeout);
	    p->last_activity = now;
	    event->observer = p->observer;
	    event->event = YAZ_SOCKET_OBSERVE_TIMEOUT;
	    putEvent (event);
	}
    }
    if ((event = getEvent()))
    {
	event->observer->socketNotify(event->event);
	delete event;
	return 1;
    }
    yaz_log (LOG_WARN, "unhandled event in processEvent");
    return 1;
}

//    n p    n p  ......   n p    n p
//   front                        back

void Yaz_SocketManager::putEvent(YazSocketEvent *event)
{
    // put in back of queue
    if (m_queue_back)
    {
	m_queue_back->prev = event;
	assert (m_queue_front);
    }
    else
    {
	assert (!m_queue_front);
	m_queue_front = event;
    }
    event->next = m_queue_back;
    event->prev = 0;
    m_queue_back = event;
}

Yaz_SocketManager::YazSocketEvent *Yaz_SocketManager::getEvent()
{
    // get from front of queue
    YazSocketEvent *event = m_queue_front;
    if (!event)
	return 0;
    assert (m_queue_back);
    m_queue_front = event->prev;
    if (m_queue_front)
    {
	assert (m_queue_back);
	m_queue_front->next = 0;
    }
    else
	m_queue_back = 0;
    return event;
}

void Yaz_SocketManager::removeEvent(IYazSocketObserver *observer)
{
    YazSocketEvent *ev = m_queue_back;
    while (ev)
    {
	YazSocketEvent *ev_next = ev->next;
	if (observer == ev->observer)
	{
	    if (ev->prev)
		ev->prev->next = ev->next;
	    else
		m_queue_back = ev->next;
	    if (ev->next)
		ev->next->prev = ev->prev;
	    else
		m_queue_front = ev->prev;
	    delete ev;
	}
	ev = ev_next;
    }
}

Yaz_SocketManager::Yaz_SocketManager()
{
    m_observers = 0;
    m_queue_front = 0;
    m_queue_back = 0;
    m_log = LOG_DEBUG;
}

Yaz_SocketManager::~Yaz_SocketManager()
{
    deleteObservers();
}
<commit_msg>Timeout event was not fired when select returned I/O (res > 0).<commit_after>/*
 * Copyright (c) 1998-2001, Index Data.
 * See the file LICENSE for details.
 *
 * $Id: yaz-socket-manager.cpp,v 1.21 2003-12-16 11:26:14 adam Exp $
 */
#include <assert.h>
#ifdef WIN32
#include <winsock.h>
#else
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#endif
#include <errno.h>
#include <string.h>

#include <yaz/log.h>
#include <yaz++/socket-manager.h>

Yaz_SocketManager::YazSocketEntry **Yaz_SocketManager::lookupObserver(
    IYazSocketObserver *observer)
{
    YazSocketEntry **se;

    for (se = &m_observers; *se; se = &(*se)->next)
	if ((*se)->observer == observer)
	    break;
    return se;
}

void Yaz_SocketManager::addObserver(int fd, IYazSocketObserver *observer)
{
    YazSocketEntry *se;

    se = *lookupObserver(observer);
    if (!se)
    {
	se = new YazSocketEntry;
	se->next= m_observers;
	m_observers = se;
	se->observer = observer;
    }
    se->fd = fd;
    se->mask = 0;
    se->last_activity = 0;
    se->timeout = 0;
}

void Yaz_SocketManager::deleteObserver(IYazSocketObserver *observer)
{
    YazSocketEntry **se = lookupObserver(observer);
    if (*se)
    {
	removeEvent (observer);
	YazSocketEntry *se_tmp = *se;
	*se = (*se)->next;
	delete se_tmp;
    }
}

void Yaz_SocketManager::deleteObservers()
{
    YazSocketEntry *se = m_observers;

    while (se)
    {
	YazSocketEntry *se_next = se->next;
	delete se;
	se = se_next;
    }
    m_observers = 0;
}

void Yaz_SocketManager::maskObserver(IYazSocketObserver *observer, int mask)
{
    YazSocketEntry *se;

    yaz_log(m_log, "obs=%p read=%d write=%d except=%d", observer,
	            mask & YAZ_SOCKET_OBSERVE_READ,
	            mask & YAZ_SOCKET_OBSERVE_WRITE,
	            mask & YAZ_SOCKET_OBSERVE_EXCEPT);

    se = *lookupObserver(observer);
    if (se)
	se->mask = mask;
}

void Yaz_SocketManager::timeoutObserver(IYazSocketObserver *observer,
					unsigned timeout)
{
    YazSocketEntry *se;

    se = *lookupObserver(observer);
    if (se)
	se->timeout = timeout;
}

int Yaz_SocketManager::processEvent()
{
    YazSocketEntry *p;
    YazSocketEvent *event = getEvent();
    unsigned timeout = 0;
    yaz_log (m_log, "Yaz_SocketManager::processEvent manager=%p", this);
    if (event)
    {
	event->observer->socketNotify(event->event);
	delete event;
	return 1;
    }

    fd_set in, out, except;
    int res;
    int max = 0;
    int no = 0;

    FD_ZERO(&in);
    FD_ZERO(&out);
    FD_ZERO(&except);

    time_t now = time(0);
    for (p = m_observers; p; p = p->next)
    {
	int fd = p->fd;
	if (p->mask)
	    no++;
	if (p->mask & YAZ_SOCKET_OBSERVE_READ)
        {
            yaz_log (m_log, "Yaz_SocketManager::select fd=%d read", fd);
	    FD_SET(fd, &in);
        }
	if (p->mask & YAZ_SOCKET_OBSERVE_WRITE)
        {
            yaz_log (m_log, "Yaz_SocketManager::select fd=%d write", fd);
	    FD_SET(fd, &out);
        }
	if (p->mask & YAZ_SOCKET_OBSERVE_EXCEPT)
        {
            yaz_log (m_log, "Yaz_SocketManager::select fd=%d except", fd);
	    FD_SET(fd, &except);
        }
	if (fd > max)
	    max = fd;
	if (p->timeout)
	{
	    unsigned timeout_this;
	    timeout_this = p->timeout;
	    if (p->last_activity)
		timeout_this -= now - p->last_activity;
	    else
		p->last_activity = now;
	    if (timeout_this < 1 || timeout_this > 2147483646)
		timeout_this = 1;
	    if (!timeout || timeout_this < timeout)
		timeout = timeout_this;
            p->timeout_this = timeout_this;
            yaz_log (m_log, "Yaz_SocketManager::select timeout_this=%d",
                     p->timeout_this);
	}
    }
    if (!no)
    {
	yaz_log (m_log, "no pending events return 0");
	if (!m_observers)
	    yaz_log (m_log, "no observers");
	return 0;
    }

    struct timeval to;
    to.tv_sec = timeout;
    to.tv_usec = 0;

    yaz_log (m_log, "Yaz_SocketManager::select begin no=%d timeout=%d",
             no, timeout);
    while ((res = select(max + 1, &in, &out, &except, timeout ? &to : 0)) < 0)
	if (errno != EINTR)
	{
	    yaz_log (LOG_LOG|LOG_WARN, "select");
	    return -1;
	}
    now = time(0);
    for (p = m_observers; p; p = p->next)
    {
	int fd = p->fd;
	int mask = 0;
	if (FD_ISSET(fd, &in))
	    mask |= YAZ_SOCKET_OBSERVE_READ;

	if (FD_ISSET(fd, &out))
	    mask |= YAZ_SOCKET_OBSERVE_WRITE;

	if (FD_ISSET(fd, &except))
	    mask |= YAZ_SOCKET_OBSERVE_EXCEPT;

	if (mask)
	{
	    YazSocketEvent *event = new YazSocketEvent;
	    p->last_activity = now;
	    event->observer = p->observer;
	    event->event = mask;
	    putEvent (event);

	    yaz_log (m_log, "putEvent I/O mask=%d", mask);
	}
	else if (p->timeout && (now - p->last_activity) >= p->timeout)
	{
	    YazSocketEvent *event = new YazSocketEvent;
            assert (p->last_activity);
	    yaz_log (m_log, "putEvent timeout, now = %ld last_activity=%ld timeout=%d",
                     now, p->last_activity, p->timeout);
	    p->last_activity = now;
	    event->observer = p->observer;
	    event->event = YAZ_SOCKET_OBSERVE_TIMEOUT;
	    putEvent (event);
	}
    }
    if ((event = getEvent()))
    {
	event->observer->socketNotify(event->event);
	delete event;
	return 1;
    }
    yaz_log (LOG_WARN, "unhandled event in processEvent");
    return 1;
}

//    n p    n p  ......   n p    n p
//   front                        back

void Yaz_SocketManager::putEvent(YazSocketEvent *event)
{
    // put in back of queue
    if (m_queue_back)
    {
	m_queue_back->prev = event;
	assert (m_queue_front);
    }
    else
    {
	assert (!m_queue_front);
	m_queue_front = event;
    }
    event->next = m_queue_back;
    event->prev = 0;
    m_queue_back = event;
}

Yaz_SocketManager::YazSocketEvent *Yaz_SocketManager::getEvent()
{
    // get from front of queue
    YazSocketEvent *event = m_queue_front;
    if (!event)
	return 0;
    assert (m_queue_back);
    m_queue_front = event->prev;
    if (m_queue_front)
    {
	assert (m_queue_back);
	m_queue_front->next = 0;
    }
    else
	m_queue_back = 0;
    return event;
}

void Yaz_SocketManager::removeEvent(IYazSocketObserver *observer)
{
    YazSocketEvent *ev = m_queue_back;
    while (ev)
    {
	YazSocketEvent *ev_next = ev->next;
	if (observer == ev->observer)
	{
	    if (ev->prev)
		ev->prev->next = ev->next;
	    else
		m_queue_back = ev->next;
	    if (ev->next)
		ev->next->prev = ev->prev;
	    else
		m_queue_front = ev->prev;
	    delete ev;
	}
	ev = ev_next;
    }
}

Yaz_SocketManager::Yaz_SocketManager()
{
    m_observers = 0;
    m_queue_front = 0;
    m_queue_back = 0;
    m_log = LOG_DEBUG;
}

Yaz_SocketManager::~Yaz_SocketManager()
{
    deleteObservers();
}
<|endoftext|>


<commit_before>#include "vga/vga.h"

#include "lib/common/attribute_macros.h"
#include "lib/armv7m/exceptions.h"

#include "lib/stm32f4xx/adv_timer.h"
#include "lib/stm32f4xx/ahb.h"
#include "lib/stm32f4xx/apb.h"
#include "lib/stm32f4xx/dma.h"
#include "lib/stm32f4xx/gpio.h"
#include "lib/stm32f4xx/interrupts.h"
#include "lib/stm32f4xx/rcc.h"
#include "lib/stm32f4xx/syscfg.h"

using stm32f4xx::AdvTimer;
using stm32f4xx::AhbPeripheral;
using stm32f4xx::ApbPeripheral;
using stm32f4xx::Dma;
using stm32f4xx::dma2;
using stm32f4xx::Gpio;
using stm32f4xx::gpioc;
using stm32f4xx::gpioe;
using stm32f4xx::Interrupt;
using stm32f4xx::rcc;
using stm32f4xx::syscfg;
using stm32f4xx::tim8;
using stm32f4xx::Word;

#define IN_SCAN_RAM SECTION(".vga_scan_ram")

namespace vga {

/*******************************************************************************
 * Driver state and configuration.
 */

// Used to adjust size of scan_buffer, below.
static constexpr unsigned max_pixels_per_line = 800;

// The current mode, set by select_mode.
static VideoMode const *current_mode;

// [0, current_mode.video_end_line).  Updated at front porch interrupt.
static unsigned volatile current_line;

/*
 * The vertical timing state.  This is a Gray code and the bits have meaning.
 * See the inspector functions below.
 */
enum class State {
  blank     = 0b00,
  starting  = 0b01,
  active    = 0b11,
  finishing = 0b10,
};

// Should we be producing a video signal?
inline bool is_displayed_state(State s) {
  return static_cast<unsigned>(s) & 0b10;
}

// Should we be rendering a scanline?
inline bool is_rendered_state(State s) {
  return static_cast<unsigned>(s) & 0b01;
}

// Finally, the actual variable.
static State volatile state;

// This is the DMA source for scan-out, filled during pend_sv.
ALIGNED(4) IN_SCAN_RAM
static unsigned char scan_buffer[max_pixels_per_line + 4];

/*******************************************************************************
 * Driver API.
 */

void init() {
  // Turn on I/O compensation cell to reduce noise on power supply.
  rcc.enable_clock(ApbPeripheral::syscfg);
  syscfg.write_cmpcr(syscfg.read_cmpcr().with_cmp_pd(true));

  // Turn a bunch of stuff on.
  rcc.enable_clock(ApbPeripheral::tim8);
  rcc.enable_clock(AhbPeripheral::gpioc);  // Sync signals
  rcc.enable_clock(AhbPeripheral::gpioe);  // Video
  rcc.enable_clock(AhbPeripheral::dma2);

  // Hold TIM8 in reset until we do mode-setting.
  rcc.enter_reset(ApbPeripheral::tim8);

  set_irq_priority(Interrupt::tim8_cc, 0);
  set_exception_priority(armv7m::Exception::pend_sv, 0xFF);

  video_off();
}

void video_off() {
  // Tristate all output ports.
  gpioc.set_mode((1 << 6) | (1 << 7), Gpio::Mode::input);
  gpioc.set_pull((1 << 6) | (1 << 7), Gpio::Pull::none);

  gpioe.set_mode(0xFF00, Gpio::Mode::input);
  gpioe.set_pull(0xFF00, Gpio::Pull::none);
}

void video_on() {
  // Configure PC6 to produce hsync using TIM8_CH1
  gpioc.set_alternate_function(Gpio::p6, 3);
  gpioc.set_output_type(Gpio::p6, Gpio::OutputType::push_pull);
  gpioc.set_output_speed(Gpio::p6, Gpio::OutputSpeed::fast_50mhz);
  gpioc.set_mode(Gpio::p6, Gpio::Mode::alternate);

  // Configure PC7 as GPIO output.
  gpioc.set_output_type(Gpio::p7, Gpio::OutputType::push_pull);
  gpioc.set_output_speed(Gpio::p7, Gpio::OutputSpeed::fast_50mhz);
  gpioc.set_mode(Gpio::p7, Gpio::Mode::gpio);

  // Configure the high byte of port E for parallel video.
  // Using 100MHz output speed gets slightly sharper transitions than 50MHz.
  gpioe.set_output_type(0xFF00, Gpio::OutputType::push_pull);
  gpioe.set_output_speed(0xFF00, Gpio::OutputSpeed::high_100mhz);
  gpioe.set_mode(0xFF00, Gpio::Mode::gpio);
}

void select_mode(VideoMode const &mode) {
  // Disable outputs during mode change.
  video_off();

  // Place TIM8 in reset, stopping all timing, and disable its interrupt.
  rcc.enter_reset(ApbPeripheral::tim8);
  disable_irq(Interrupt::tim8_cc);

  // Busy-wait for pending DMA to complete.
  while (dma2.stream1.read_cr().get_en());

  // TODO: apply buffered changes.

  // Switch to new CPU clock settings.
  rcc.configure_clocks(mode.clock_config);

  // Configure TIM8 for horizontal sync generation.
  rcc.leave_reset(ApbPeripheral::tim8);
  tim8.write_psc(4 - 1);  // Count in pixels, 1 pixel = 4 CCLK

  tim8.write_arr(mode.line_pixels - 1);
  tim8.write_ccr1(mode.sync_pixels);
  tim8.write_ccr2(mode.sync_pixels + mode.back_porch_pixels - mode.video_lead);
  tim8.write_ccr3(
      mode.sync_pixels + mode.back_porch_pixels + mode.video_pixels);

  tim8.write_ccmr1(AdvTimer::ccmr1_value_t()
                   .with_oc1m(AdvTimer::OcMode::pwm1)
                   .with_cc1s(AdvTimer::ccmr1_value_t::cc1s_t::output));

  tim8.write_bdtr(AdvTimer::bdtr_value_t()
                  .with_ossr(true)
                  .with_moe(true));

  tim8.write_ccer(AdvTimer::ccer_value_t()
                  .with_cc1e(true)
                  .with_cc1p(
                      mode.hsync_polarity == VideoMode::Polarity::negative));

  tim8.write_dier(AdvTimer::dier_value_t()
                  .with_cc2ie(true)    // Interrupt at start of active video.
                  .with_cc3ie(true));  // Interrupt at end of active video.

  // Note: TIM8 is still not running.

  switch (mode.vsync_polarity) {
    case VideoMode::Polarity::positive: gpioc.clear(1 << 7); break;
    case VideoMode::Polarity::negative: gpioc.set  (1 << 7); break;
  }

  // Scribble over scan buffer to help catch bugs.
  for (unsigned i = 0; i < sizeof(scan_buffer) - 4; i += 2) {
    scan_buffer[i] = 0xFF;
    scan_buffer[i + 1] = 0x00;
  }
  // But the final four must be black.
  scan_buffer[sizeof(scan_buffer) - 4] = 0;
  scan_buffer[sizeof(scan_buffer) - 3] = 0;
  scan_buffer[sizeof(scan_buffer) - 2] = 0;
  scan_buffer[sizeof(scan_buffer) - 1] = 0;

  // Set up global state.
  current_mode = &mode;  // TODO(cbiffle): copy into RAM for less jitter?
  current_line = 0;

  // Start the timer.
  enable_irq(Interrupt::tim8_cc);
  tim8.write_cr1(tim8.read_cr1().with_cen(true));

  // Enable display and sync signals.
  video_on();
}

}  // namespace vga

/*******************************************************************************
 * Horizontal timing interrupt.
 */
extern "C" void stm32f4xx_tim8_cc_handler() {
  // We have to clear our interrupt flags, or this will recur.
  auto sr = tim8.read_sr();
  tim8.write_sr(sr.with_cc2if(false).with_cc3if(false));

  vga::VideoMode const &mode = *vga::current_mode;

  if (sr.get_cc2if()) {
    // CC2 indicates start of active video (end of back porch).
    // This only matters in displayed states.
    if (is_displayed_state(vga::state)) {
      // Clear stream 1 flags (lifcr is a write-1-to-clear register).
      dma2.write_lifcr(Dma::lifcr_value_t()
                       .with_cdmeif1(true)
                       .with_cteif1(true)
                       .with_chtif1(true)
                       .with_ctcif1(true));

      auto &st = dma2.stream1;

      // Shut off stream 1 by zeroing CR.
      // TODO(cbiffle): necessary?
      st.write_cr(Dma::Stream::cr_value_t());

      // Prepare to transfer pixels as words, plus the final black word.
      st.write_ndtr(mode.video_pixels / 4 + 1);

      // Set addresses.  Note that we're using memory as the peripheral side.
      // This DMA controller is a little odd.
      st.write_par(reinterpret_cast<Word>(&vga::scan_buffer));
      st.write_m0ar(0x40021015);  // High byte of GPIOE ODR (hack hack)

      // Configure FIFO.
      st.write_fcr(Dma::Stream::fcr_value_t()
                   .with_fth(Dma::Stream::fcr_value_t::fth_t::quarter)
                   .with_dmdis(true)
                   .with_feie(false));

      /*
       * Configure and enable the DMA stream.  The configuration used here
       * deserves more discussion.
       *
       * As noted above, our "peripheral" is RAM and our "memory" is the GPIO
       * unit.  In memory-to-memory mode (which we use) the distinction is
       * not useful, since the peripherals are memory-mapped; the controller
       * insists that "peripheral" be source and "memory" be destination in that
       * mode.  The key here is that the transfer runs at full speed.  On the
       * STM32F407 the transfer will not exceed one unit per 4 AHB cycles.  The
       * reason for this is not obvious.
       *
       * Address incrementation on this chip is independent from whether an
       * address is considered "peripheral" or "memory."  Here we auto-increment
       * the peripheral address (to walk through the scan buffer) while leaving
       * the memory address fixed (at the appropriate byte of the GPIO port).
       *
       * Because we're using memory-to-memory, the hardware enforces several
       * restrictions:
       *
       *  1. We're stuck using DMA2.  DMA1 can't do it.
       *  2. We're required to use the FIFO -- direct mode is verboten.
       *  3. We can't use circular mode.  (Double-buffer mode appears permitted,
       *     but I haven't tried it.)
       *
       * Fortunately we can tie the FIFO to a tree by giving it a really low
       * threshold level.
       *
       * I have not experimented with burst modes, but I suspect they'll make
       * the timing less regular.
       *
       * Note that the priority (pl field) is only used for arbitration between
       * streams of the same DMA controller.  The STM32F4 does not provide any
       * control over the AHB matrix arbitration scheme, unlike (say) the NXP
       * LPC1788.  Shame, that.  It means we have to be very careful about our
       * use of the bus matrix during scan-out.
       */
      typedef Dma::Stream::cr_value_t cr_t;
      st.write_cr(Dma::Stream::cr_value_t()
                  // Originally chosen to play nice with TIM8.  Now, arbitrary.
                  .with_chsel(7)
                  .with_pl(cr_t::pl_t::very_high)
                  .with_dir(cr_t::dir_t::memory_to_memory)
                  // Input settings:
                  .with_pburst(Dma::Stream::BurstSize::single)
                  .with_psize(Dma::Stream::TransferSize::word)
                  .with_pinc(true)
                  // Output settings:
                  .with_mburst(Dma::Stream::BurstSize::single)
                  .with_msize(Dma::Stream::TransferSize::byte)
                  .with_minc(false)
                  // Look at all these options we don't use:
                  .with_dbm(false)
                  .with_pincos(false)
                  .with_circ(false)
                  .with_pfctrl(false)
                  .with_tcie(false)
                  .with_htie(false)
                  .with_teie(false)
                  .with_dmeie(false)
                  // Finally, enable.
                  .with_en(true));
    } else {
      // Not displayed state.  Ensure pins are black.
      // TODO(cbiffle): almost certainly not necessary...
      gpioe.clear(0xFF00);
    }
  }

  if (sr.get_cc3if()) {
    // CC3 indicates end of active video (start of front porch).
    unsigned line = vga::current_line;

    if (line == 0) {
      // Start of frame!  Time to stop displaying pixels.
      vga::state = vga::State::blank;
      // TODO(cbiffle): suppress video output.
      // TODO(cbiffle): latch configuration changes.
    } else if (line == mode.vsync_start_line
            || line == mode.vsync_end_line) {
      // Either edge of vsync pulse.
      gpioc.toggle(Gpio::p7);
    } else if (line == static_cast<unsigned short>(mode.video_start_line - 1)) {
      // Time to start generating the first scan buffer.
      vga::state = vga::State::starting;
    } else if (line == mode.video_start_line) {
      // Time to start output.
      vga::state = vga::State::active;
    } else if (line == static_cast<unsigned short>(mode.video_end_line - 1)) {
      // Time to stop rendering new scan buffers.
      vga::state = vga::State::finishing;
      line = static_cast<unsigned>(-1);  // Make line roll over to zero.
    }

    vga::current_line = line + 1;

    if (is_rendered_state(vga::state)) {
      // TODO(cbiffle): PendSV to kick off a buffer flip and rasterization.
    }
  }
}

<commit_msg>vga: clean up some TODOs and paranoid code.<commit_after>#include "vga/vga.h"

#include "lib/common/attribute_macros.h"
#include "lib/armv7m/exceptions.h"

#include "lib/stm32f4xx/adv_timer.h"
#include "lib/stm32f4xx/ahb.h"
#include "lib/stm32f4xx/apb.h"
#include "lib/stm32f4xx/dma.h"
#include "lib/stm32f4xx/gpio.h"
#include "lib/stm32f4xx/interrupts.h"
#include "lib/stm32f4xx/rcc.h"
#include "lib/stm32f4xx/syscfg.h"

using stm32f4xx::AdvTimer;
using stm32f4xx::AhbPeripheral;
using stm32f4xx::ApbPeripheral;
using stm32f4xx::Dma;
using stm32f4xx::dma2;
using stm32f4xx::Gpio;
using stm32f4xx::gpioc;
using stm32f4xx::gpioe;
using stm32f4xx::Interrupt;
using stm32f4xx::rcc;
using stm32f4xx::syscfg;
using stm32f4xx::tim8;
using stm32f4xx::Word;

#define IN_SCAN_RAM SECTION(".vga_scan_ram")

namespace vga {

/*******************************************************************************
 * Driver state and configuration.
 */

// Used to adjust size of scan_buffer, below.
static constexpr unsigned max_pixels_per_line = 800;

// The current mode, set by select_mode.
static VideoMode const *current_mode;

// [0, current_mode.video_end_line).  Updated at front porch interrupt.
static unsigned volatile current_line;

/*
 * The vertical timing state.  This is a Gray code and the bits have meaning.
 * See the inspector functions below.
 */
enum class State {
  blank     = 0b00,
  starting  = 0b01,
  active    = 0b11,
  finishing = 0b10,
};

// Should we be producing a video signal?
inline bool is_displayed_state(State s) {
  return static_cast<unsigned>(s) & 0b10;
}

// Should we be rendering a scanline?
inline bool is_rendered_state(State s) {
  return static_cast<unsigned>(s) & 0b01;
}

// Finally, the actual variable.
static State volatile state;

// This is the DMA source for scan-out, filled during pend_sv.
ALIGNED(4) IN_SCAN_RAM
static unsigned char scan_buffer[max_pixels_per_line + 4];

/*******************************************************************************
 * Driver API.
 */

void init() {
  // Turn on I/O compensation cell to reduce noise on power supply.
  rcc.enable_clock(ApbPeripheral::syscfg);
  syscfg.write_cmpcr(syscfg.read_cmpcr().with_cmp_pd(true));

  // Turn a bunch of stuff on.
  rcc.enable_clock(ApbPeripheral::tim8);
  rcc.enable_clock(AhbPeripheral::gpioc);  // Sync signals
  rcc.enable_clock(AhbPeripheral::gpioe);  // Video
  rcc.enable_clock(AhbPeripheral::dma2);

  // Hold TIM8 in reset until we do mode-setting.
  rcc.enter_reset(ApbPeripheral::tim8);

  set_irq_priority(Interrupt::tim8_cc, 0);
  set_exception_priority(armv7m::Exception::pend_sv, 0xFF);

  video_off();
}

void video_off() {
  // Tristate all output ports.
  gpioc.set_mode((1 << 6) | (1 << 7), Gpio::Mode::input);
  gpioc.set_pull((1 << 6) | (1 << 7), Gpio::Pull::none);

  gpioe.set_mode(0xFF00, Gpio::Mode::input);
  gpioe.set_pull(0xFF00, Gpio::Pull::none);
}

void video_on() {
  // Configure PC6 to produce hsync using TIM8_CH1
  gpioc.set_alternate_function(Gpio::p6, 3);
  gpioc.set_output_type(Gpio::p6, Gpio::OutputType::push_pull);
  gpioc.set_output_speed(Gpio::p6, Gpio::OutputSpeed::fast_50mhz);
  gpioc.set_mode(Gpio::p6, Gpio::Mode::alternate);

  // Configure PC7 as GPIO output.
  gpioc.set_output_type(Gpio::p7, Gpio::OutputType::push_pull);
  gpioc.set_output_speed(Gpio::p7, Gpio::OutputSpeed::fast_50mhz);
  gpioc.set_mode(Gpio::p7, Gpio::Mode::gpio);

  // Configure the high byte of port E for parallel video.
  // Using 100MHz output speed gets slightly sharper transitions than 50MHz.
  gpioe.set_output_type(0xFF00, Gpio::OutputType::push_pull);
  gpioe.set_output_speed(0xFF00, Gpio::OutputSpeed::high_100mhz);
  gpioe.set_mode(0xFF00, Gpio::Mode::gpio);
}

void select_mode(VideoMode const &mode) {
  // Disable outputs during mode change.
  video_off();

  // Place TIM8 in reset, stopping all timing, and disable its interrupt.
  rcc.enter_reset(ApbPeripheral::tim8);
  disable_irq(Interrupt::tim8_cc);

  // Busy-wait for pending DMA to complete.
  while (dma2.stream1.read_cr().get_en());

  // TODO: apply buffered changes.

  // Switch to new CPU clock settings.
  rcc.configure_clocks(mode.clock_config);

  // Configure TIM8 for horizontal sync generation.
  rcc.leave_reset(ApbPeripheral::tim8);
  tim8.write_psc(4 - 1);  // Count in pixels, 1 pixel = 4 CCLK

  tim8.write_arr(mode.line_pixels - 1);
  tim8.write_ccr1(mode.sync_pixels);
  tim8.write_ccr2(mode.sync_pixels + mode.back_porch_pixels - mode.video_lead);
  tim8.write_ccr3(
      mode.sync_pixels + mode.back_porch_pixels + mode.video_pixels);

  tim8.write_ccmr1(AdvTimer::ccmr1_value_t()
                   .with_oc1m(AdvTimer::OcMode::pwm1)
                   .with_cc1s(AdvTimer::ccmr1_value_t::cc1s_t::output));

  tim8.write_bdtr(AdvTimer::bdtr_value_t()
                  .with_ossr(true)
                  .with_moe(true));

  tim8.write_ccer(AdvTimer::ccer_value_t()
                  .with_cc1e(true)
                  .with_cc1p(
                      mode.hsync_polarity == VideoMode::Polarity::negative));

  tim8.write_dier(AdvTimer::dier_value_t()
                  .with_cc2ie(true)    // Interrupt at start of active video.
                  .with_cc3ie(true));  // Interrupt at end of active video.

  // Note: TIM8 is still not running.

  switch (mode.vsync_polarity) {
    case VideoMode::Polarity::positive: gpioc.clear(1 << 7); break;
    case VideoMode::Polarity::negative: gpioc.set  (1 << 7); break;
  }

  // Scribble over scan buffer to help catch bugs.
  for (unsigned i = 0; i < sizeof(scan_buffer) - 4; i += 2) {
    scan_buffer[i] = 0xFF;
    scan_buffer[i + 1] = 0x00;
  }
  // But the final four must be black.
  scan_buffer[sizeof(scan_buffer) - 4] = 0;
  scan_buffer[sizeof(scan_buffer) - 3] = 0;
  scan_buffer[sizeof(scan_buffer) - 2] = 0;
  scan_buffer[sizeof(scan_buffer) - 1] = 0;

  // Set up global state.
  current_mode = &mode;  // TODO(cbiffle): copy into RAM for less jitter?
  current_line = 0;

  // Start the timer.
  enable_irq(Interrupt::tim8_cc);
  tim8.write_cr1(tim8.read_cr1().with_cen(true));

  // Enable display and sync signals.
  video_on();
}

}  // namespace vga

/*******************************************************************************
 * Horizontal timing interrupt.
 */
extern "C" void stm32f4xx_tim8_cc_handler() {
  // We have to clear our interrupt flags, or this will recur.
  auto sr = tim8.read_sr();
  tim8.write_sr(sr.with_cc2if(false).with_cc3if(false));

  vga::VideoMode const &mode = *vga::current_mode;

  if (sr.get_cc2if()) {
    // CC2 indicates start of active video (end of back porch).
    // This only matters in displayed states.
    if (is_displayed_state(vga::state)) {
      // Clear stream 1 flags (lifcr is a write-1-to-clear register).
      dma2.write_lifcr(Dma::lifcr_value_t()
                       .with_cdmeif1(true)
                       .with_cteif1(true)
                       .with_chtif1(true)
                       .with_ctcif1(true));

      auto &st = dma2.stream1;

      // Prepare to transfer pixels as words, plus the final black word.
      st.write_ndtr(mode.video_pixels / 4 + 1);

      // Set addresses.  Note that we're using memory as the peripheral side.
      // This DMA controller is a little odd.
      st.write_par(reinterpret_cast<Word>(&vga::scan_buffer));
      st.write_m0ar(0x40021015);  // High byte of GPIOE ODR (hack hack)

      // Configure FIFO.
      st.write_fcr(Dma::Stream::fcr_value_t()
                   .with_fth(Dma::Stream::fcr_value_t::fth_t::quarter)
                   .with_dmdis(true)
                   .with_feie(false));

      /*
       * Configure and enable the DMA stream.  The configuration used here
       * deserves more discussion.
       *
       * As noted above, our "peripheral" is RAM and our "memory" is the GPIO
       * unit.  In memory-to-memory mode (which we use) the distinction is
       * not useful, since the peripherals are memory-mapped; the controller
       * insists that "peripheral" be source and "memory" be destination in that
       * mode.  The key here is that the transfer runs at full speed.  On the
       * STM32F407 the transfer will not exceed one unit per 4 AHB cycles.  The
       * reason for this is not obvious.
       *
       * Address incrementation on this chip is independent from whether an
       * address is considered "peripheral" or "memory."  Here we auto-increment
       * the peripheral address (to walk through the scan buffer) while leaving
       * the memory address fixed (at the appropriate byte of the GPIO port).
       *
       * Because we're using memory-to-memory, the hardware enforces several
       * restrictions:
       *
       *  1. We're stuck using DMA2.  DMA1 can't do it.
       *  2. We're required to use the FIFO -- direct mode is verboten.
       *  3. We can't use circular mode.  (Double-buffer mode appears permitted,
       *     but I haven't tried it.)
       *
       * Fortunately we can tie the FIFO to a tree by giving it a really low
       * threshold level.
       *
       * I have not experimented with burst modes, but I suspect they'll make
       * the timing less regular.
       *
       * Note that the priority (pl field) is only used for arbitration between
       * streams of the same DMA controller.  The STM32F4 does not provide any
       * control over the AHB matrix arbitration scheme, unlike (say) the NXP
       * LPC1788.  Shame, that.  It means we have to be very careful about our
       * use of the bus matrix during scan-out.
       */
      typedef Dma::Stream::cr_value_t cr_t;
      st.write_cr(Dma::Stream::cr_value_t()
                  // Originally chosen to play nice with TIM8.  Now, arbitrary.
                  .with_chsel(7)
                  .with_pl(cr_t::pl_t::very_high)
                  .with_dir(cr_t::dir_t::memory_to_memory)
                  // Input settings:
                  .with_pburst(Dma::Stream::BurstSize::single)
                  .with_psize(Dma::Stream::TransferSize::word)
                  .with_pinc(true)
                  // Output settings:
                  .with_mburst(Dma::Stream::BurstSize::single)
                  .with_msize(Dma::Stream::TransferSize::byte)
                  .with_minc(false)
                  // Look at all these options we don't use:
                  .with_dbm(false)
                  .with_pincos(false)
                  .with_circ(false)
                  .with_pfctrl(false)
                  .with_tcie(false)
                  .with_htie(false)
                  .with_teie(false)
                  .with_dmeie(false)
                  // Finally, enable.
                  .with_en(true));
    }
  }

  if (sr.get_cc3if()) {
    // CC3 indicates end of active video (start of front porch).
    unsigned line = vga::current_line;

    if (line == 0) {
      // Start of frame!  Time to stop displaying pixels.
      vga::state = vga::State::blank;
      // TODO(cbiffle): latch configuration changes.
    } else if (line == mode.vsync_start_line
            || line == mode.vsync_end_line) {
      // Either edge of vsync pulse.
      gpioc.toggle(Gpio::p7);
    } else if (line == static_cast<unsigned short>(mode.video_start_line - 1)) {
      // Time to start generating the first scan buffer.
      vga::state = vga::State::starting;
    } else if (line == mode.video_start_line) {
      // Time to start output.
      vga::state = vga::State::active;
    } else if (line == static_cast<unsigned short>(mode.video_end_line - 1)) {
      // Time to stop rendering new scan buffers.
      vga::state = vga::State::finishing;
      line = static_cast<unsigned>(-1);  // Make line roll over to zero.
    }

    vga::current_line = line + 1;

    if (is_rendered_state(vga::state)) {
      // TODO(cbiffle): PendSV to kick off a buffer flip and rasterization.
    }
  }
}

<|endoftext|>


<commit_before>// tOleInPlaceSite.cpp: implementation of the tOleInPlaceSite class.
//
//////////////////////////////////////////////////////////////////////

#include "tOleInPlaceSite.h"
#include "tOleHandler.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

BOOL        g_fSwitchingActive=FALSE;

/*
 * tOleInPlaceSite::tOleInPlaceSite
 * tOleInPlaceSite::~tOleInPlaceSite
 *
 * Parameters (Constructor):
 *  pTen            PCTenant of the tenant we're in.
 *  pUnkOuter       LPUNKNOWN to which we delegate.
 */

tOleInPlaceSite::tOleInPlaceSite(class tOleHandler *pTen
    , LPUNKNOWN pUnkOuter)
    {
    m_cRef=0;
    m_pTen=pTen;
    m_pUnkOuter=pUnkOuter;
    m_oleinplaceframe = new tOleInPlaceFrame(m_pTen->m_hWnd);
    return;
    }

tOleInPlaceSite::~tOleInPlaceSite(void)
    {
    return;
    }

/*
 * tOleInPlaceSite::QueryInterface
 * tOleInPlaceSite::AddRef
 * tOleInPlaceSite::Release
 *
 * Purpose:
 *  IUnknown members for tOleInPlaceSite object.
 */

STDMETHODIMP tOleInPlaceSite::QueryInterface(REFIID riid
    , LPVOID *ppv)
    {
    return m_pUnkOuter->QueryInterface(riid, ppv);
    }

STDMETHODIMP_(ULONG) tOleInPlaceSite::AddRef(void)
    {
    ++m_cRef;
    return m_pUnkOuter->AddRef();
    }

STDMETHODIMP_(ULONG) tOleInPlaceSite::Release(void)
    {
    --m_cRef;
    return m_pUnkOuter->Release();
    }

/*
 * tOleInPlaceActiveObject::GetWindow
 *
 * Purpose:
 *  Retrieves the handle of the window associated with the object
 *  on which this interface is implemented.
 *
 * Parameters:
 *  phWnd           HWND * in which to store the window handle.
 *
 * Return Value:
 *  HRESULT         NOERROR if successful, E_FAIL if there is no
 *                  window.
 */

STDMETHODIMP tOleInPlaceSite::GetWindow(HWND *phWnd)
    {
    *phWnd=m_pTen->m_hWnd;
    return NOERROR;
    }

/*
 * tOleInPlaceActiveObject::ContextSensitiveHelp
 *
 * Purpose:
 *  Instructs the object on which this interface is implemented to
 *  enter or leave a context-sensitive help mode.
 *
 * Parameters:
 *  fEnterMode      BOOL TRUE to enter the mode, FALSE otherwise.
 *
 * Return Value:
 *  HRESULT         NOERROR
 */

STDMETHODIMP tOleInPlaceSite::ContextSensitiveHelp
    (BOOL fEnterMode)
    {
    return E_NOTIMPL;
    }

/*
 * tOleInPlaceSite::CanInPlaceActivate
 *
 * Purpose:
 *  Answers the server whether or not we can currently in-place
 *  activate its object.  By implementing this interface we say
 *  that we support in-place activation, but through this function
 *  we indicate whether the object can currently be activated
 *  in-place.  Iconic aspects, for example, cannot, meaning we
 *  return S_FALSE.
 *
 * Parameters:
 *  None
 *
 * Return Value:
 *  HRESULT         NOERROR if we can in-place activate the object
 *                  in this site, S_FALSE if not.
 */

STDMETHODIMP tOleInPlaceSite::CanInPlaceActivate(void)
    {
    if (DVASPECT_CONTENT!=m_pTen->m_fe.dwAspect)
        return ResultFromScode(S_FALSE);

    return NOERROR;
    }

/*
 * tOleInPlaceSite::OnInPlaceActivate
 *
 * Purpose:
 *  Informs the container that an object is being activated in-place
 *  such that the container can prepare appropriately.  The
 *  container does not, however, make any user interface changes at
 *  this point.  See OnUIActivate.
 *
 * Parameters:
 *  None
 *
 * Return Value:
 *  HRESULT         NOERROR or an appropriate error code.
 */

STDMETHODIMP tOleInPlaceSite::OnInPlaceActivate(void)
    {
    //CHAPTER24MOD
    m_pTen->m_fPendingDeactivate=FALSE;
    //End CHAPTER24MOD

    //m_pIOleIPObject is our in-place flag.
    m_pTen->m_pObj->QueryInterface(IID_IOleInPlaceObject
        , (PPVOID)&m_pTen->m_pIOleIPObject);

    return NOERROR;
    }

/*
 * tOleInPlaceSite::OnInPlaceDeactivate
 *
 * Purpose:
 *  Notifies the container that the object has deactivated itself
 *  from an in-place state.  Opposite of OnInPlaceActivate.  The
 *  container does not change any UI at this point.
 *
 * Parameters:
 *  None
 *
 * Return Value:
 *  HRESULT         NOERROR or an appropriate error code.
 */

STDMETHODIMP tOleInPlaceSite::OnInPlaceDeactivate(void)
    {
    /*
     * Since we don't have an Undo command, we can tell the object
     * right away to discard its Undo state.
     */
    m_pTen->Activate(OLEIVERB_DISCARDUNDOSTATE, NULL);
    ReleaseInterface(m_pTen->m_pIOleIPObject);
    return NOERROR;
    }

/*
 * tOleInPlaceSite::OnUIActivate
 *
 * Purpose:
 *  Informs the container that the object is going to start munging
 *  around with user interface, like replacing the menu.  The
 *  container should remove any relevant UI in preparation.
 *
 * Parameters:
 *  None
 *
 * Return Value:
 *  HRESULT         NOERROR or an appropriate error code.
 */

STDMETHODIMP tOleInPlaceSite::OnUIActivate(void)
    {
    //CHAPTER24MOD
    m_pTen->m_fPendingDeactivate=FALSE;
    //End CHAPTER24MOD

    /*
     * Change the currently selected tenant in the page.  This
     * will UIDeactivate the currently UI Active tenant.
     */
    g_fSwitchingActive=TRUE;
    //m_pTen->m_pPG->m_pPageCur->SwitchActiveTenant(m_pTen);
    g_fSwitchingActive=FALSE;

    return NOERROR;
    }

/*
 * tOleInPlaceSite::OnUIDeactivate
 *
 * Purpose:
 *  Informs the container that the object is deactivating its
 *  in-place user interface at which time the container may
 *  reinstate its own.  Opposite of OnUIActivate.
 *
 * Parameters:
 *  fUndoable       BOOL indicating if the object will actually
 *                  perform an Undo if the container calls
 *                  ReactivateAndUndo.
 *
 * Return Value:
 *  HRESULT         NOERROR or an appropriate error code.
 */

STDMETHODIMP tOleInPlaceSite::OnUIDeactivate(BOOL fUndoable)
    {
    MSG         msg;

    /*
     * Ignore this notification if we're switching between
     * multiple active objects.
     */
    if (g_fSwitchingActive)
        return NOERROR;

    //If in shutdown (NULL storage), don't check messages.
/*    if (NULL==m_pTen->m_pIStorage)
        {
        g_pFR->ReinstateUI();
        return NOERROR;
        }*/

    //If there's a pending double-click, delay showing our UI
/*    if (!PeekMessage(&msg, pDoc->Window(), WM_LBUTTONDBLCLK
        , WM_LBUTTONDBLCLK, PM_NOREMOVE | PM_NOYIELD))
        {
        //Turn everything back on.
        g_pFR->ReinstateUI();
        }
    else*/

    return NOERROR;
    }

/*
 * tOleInPlaceSite::DeactivateAndUndo
 *
 * Purpose:
 *  If immediately after activation the object does an Undo, the
 *  action being undone is the activation itself, and this call
 *  informs the container that this is, in fact, what happened.
 *  The container should call IOleInPlaceObject::UIDeactivate.
 *
 * Parameters:
 *  None
 *
 * Return Value:
 *  HRESULT         NOERROR or an appropriate error code.
 */

STDMETHODIMP tOleInPlaceSite::DeactivateAndUndo(void)
    {
    //CHAPTER24MOD
    /*
     * Note that we don't pay attention to the locking
     * from IOleControlSite::LockInPlaceActive since only
     * the object calls this function and should know
     * that it's going to be deactivated.
     */
    //End CHAPTER24MOD

    m_pTen->m_pIOleIPObject->InPlaceDeactivate();
    return NOERROR;
    }

/*
 * tOleInPlaceSite::DiscardUndoState
 *
 * Purpose:
 *  Informs the container that something happened in the object
 *  that means the container should discard any undo information
 *  it currently maintains for the object.
 *
 * Parameters:
 *  None
 *
 * Return Value:
 *  HRESULT         NOERROR or an appropriate error code.
 */

STDMETHODIMP tOleInPlaceSite::DiscardUndoState(void)
    {
    return ResultFromScode(E_NOTIMPL);
    }

/*
 * tOleInPlaceSite::GetWindowContext
 *
 * Purpose:
 *  Provides an in-place object with pointers to the frame and
 *  document level in-place interfaces (IOleInPlaceFrame and
 *  IOleInPlaceUIWindow) such that the object can do border
 *  negotiation and so forth.  Also requests the position and
 *  clipping rectangles of the object in the container and a
 *  pointer to an OLEINPLACEFRAME info structure which contains
 *  accelerator information.
 *
 *  Note that the two interfaces this call returns are not
 *  available through QueryInterface on IOleInPlaceSite since they
 *  live with the frame and document, but not the site.
 *
 * Parameters:
 *  ppIIPFrame      LPOLEINPLACEFRAME * in which to return the
 *                  AddRef'd pointer to the container's
 *                  IOleInPlaceFrame.
 *  ppIIPUIWindow   LPOLEINPLACEUIWINDOW * in which to return
 *                  the AddRef'd pointer to the container document's
 *                  IOleInPlaceUIWindow.
 *  prcPos          LPRECT in which to store the object's position.
 *  prcClip         LPRECT in which to store the object's visible
 *                  region.
 *  pFI             LPOLEINPLACEFRAMEINFO to fill with accelerator
 *                  stuff.
 *
 * Return Value:
 *  HRESULT         NOERROR
 */

STDMETHODIMP tOleInPlaceSite::GetWindowContext
    (LPOLEINPLACEFRAME *ppIIPFrame, LPOLEINPLACEUIWINDOW
    *ppIIPUIWindow, LPRECT prcPos, LPRECT prcClip
    , LPOLEINPLACEFRAMEINFO pFI)
    {
    RECTL           rcl;

    *ppIIPUIWindow=NULL;
    *ppIIPFrame=m_oleinplaceframe;
    m_oleinplaceframe->AddRef();

    GetClientRect(m_pTen->m_hWnd, prcPos);
    GetClientRect(m_pTen->m_hWnd, prcClip);

/*    *ppIIPFrame=(LPOLEINPLACEFRAME)g_pFR;
    g_pFR->AddRef();*/

/*    if (NULL!=pDoc)
        {
        pDoc->QueryInterface(IID_IOleInPlaceUIWindow
            , (PPVOID)ppIIPUIWindow);
        }*/

    //Now get the rectangles and frame information.
    /*m_pTen->RectGet(&rcl, TRUE);
    RECTFROMRECTL(*prcPos, rcl);
                                  0
    //Include scroll position here.
    OffsetRect(prcPos, -(int)m_pTen->m_pPG->m_xPos
        , -(int)m_pTen->m_pPG->m_yPos);

    SetRect(prcClip, 0, 0, 32767, 32767);
*/
    pFI->cb=sizeof(OLEINPLACEFRAMEINFO);
    pFI->fMDIApp=FALSE;

    pFI->hwndFrame=m_pTen->m_hWnd;

    pFI->haccel=NULL;
    pFI->cAccelEntries=0;

    return NOERROR;
    }

/*
 * tOleInPlaceSite::Scroll
 *
 * Purpose:
 *  Asks the container to scroll the document, and thus the object,
 *  by the given amounts in the sz parameter.
 *
 * Parameters:
 *  sz              SIZE containing signed horizontal and vertical
 *                  extents by which the container should scroll.
 *                  These are in device units.
 *
 * Return Value:
 *  HRESULT         NOERROR
 */

STDMETHODIMP tOleInPlaceSite::Scroll(SIZE sz)
    {
    /*int         x, y;

    x=m_pTen->m_pPG->m_xPos+sz.cx;
    y=m_pTen->m_pPG->m_yPos+sz.cy;

    SendScrollPosition(m_pTen->m_hWnd, WM_HSCROLL, x);
    SendScrollPosition(m_pTen->m_hWnd, WM_VSCROLL, y);*/
    return NOERROR;
    }

/*
 * tOleInPlaceSite::OnPosRectChange
 *
 * Purpose:
 *  Informs the container that the in-place object was resized.
 *  The container must call IOleInPlaceObject::SetObjectRects.
 *  This does not change the site's rectangle in any case.
 *
 * Parameters:
 *  prcPos          LPCRECT containing the new size of the object.
 *
 * Return Value:
 *  HRESULT         NOERROR
 */

STDMETHODIMP tOleInPlaceSite::OnPosRectChange(LPCRECT prcPos)
    {
    if (NULL!=prcPos)
        m_pTen->m_rcPos=*prcPos;

    m_pTen->UpdateInPlaceObjectRects(prcPos, FALSE);
    return NOERROR;
    }

<commit_msg>Fixed: object position in  IupOleControl.<commit_after>// tOleInPlaceSite.cpp: implementation of the tOleInPlaceSite class.
//
//////////////////////////////////////////////////////////////////////

#include "tOleInPlaceSite.h"
#include "tOleHandler.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

BOOL        g_fSwitchingActive=FALSE;

/*
 * tOleInPlaceSite::tOleInPlaceSite
 * tOleInPlaceSite::~tOleInPlaceSite
 *
 * Parameters (Constructor):
 *  pTen            PCTenant of the tenant we're in.
 *  pUnkOuter       LPUNKNOWN to which we delegate.
 */

tOleInPlaceSite::tOleInPlaceSite(class tOleHandler *pTen
    , LPUNKNOWN pUnkOuter)
    {
    m_cRef=0;
    m_pTen=pTen;
    m_pUnkOuter=pUnkOuter;
    m_oleinplaceframe = new tOleInPlaceFrame(m_pTen->m_hWnd);
    return;
    }

tOleInPlaceSite::~tOleInPlaceSite(void)
    {
    return;
    }

/*
 * tOleInPlaceSite::QueryInterface
 * tOleInPlaceSite::AddRef
 * tOleInPlaceSite::Release
 *
 * Purpose:
 *  IUnknown members for tOleInPlaceSite object.
 */

STDMETHODIMP tOleInPlaceSite::QueryInterface(REFIID riid
    , LPVOID *ppv)
    {
    return m_pUnkOuter->QueryInterface(riid, ppv);
    }

STDMETHODIMP_(ULONG) tOleInPlaceSite::AddRef(void)
    {
    ++m_cRef;
    return m_pUnkOuter->AddRef();
    }

STDMETHODIMP_(ULONG) tOleInPlaceSite::Release(void)
    {
    --m_cRef;
    return m_pUnkOuter->Release();
    }

/*
 * tOleInPlaceActiveObject::GetWindow
 *
 * Purpose:
 *  Retrieves the handle of the window associated with the object
 *  on which this interface is implemented.
 *
 * Parameters:
 *  phWnd           HWND * in which to store the window handle.
 *
 * Return Value:
 *  HRESULT         NOERROR if successful, E_FAIL if there is no
 *                  window.
 */

STDMETHODIMP tOleInPlaceSite::GetWindow(HWND *phWnd)
    {
    *phWnd=m_pTen->m_hWnd;
    return NOERROR;
    }

/*
 * tOleInPlaceActiveObject::ContextSensitiveHelp
 *
 * Purpose:
 *  Instructs the object on which this interface is implemented to
 *  enter or leave a context-sensitive help mode.
 *
 * Parameters:
 *  fEnterMode      BOOL TRUE to enter the mode, FALSE otherwise.
 *
 * Return Value:
 *  HRESULT         NOERROR
 */

STDMETHODIMP tOleInPlaceSite::ContextSensitiveHelp
    (BOOL fEnterMode)
    {
    return E_NOTIMPL;
    }

/*
 * tOleInPlaceSite::CanInPlaceActivate
 *
 * Purpose:
 *  Answers the server whether or not we can currently in-place
 *  activate its object.  By implementing this interface we say
 *  that we support in-place activation, but through this function
 *  we indicate whether the object can currently be activated
 *  in-place.  Iconic aspects, for example, cannot, meaning we
 *  return S_FALSE.
 *
 * Parameters:
 *  None
 *
 * Return Value:
 *  HRESULT         NOERROR if we can in-place activate the object
 *                  in this site, S_FALSE if not.
 */

STDMETHODIMP tOleInPlaceSite::CanInPlaceActivate(void)
    {
    if (DVASPECT_CONTENT!=m_pTen->m_fe.dwAspect)
        return ResultFromScode(S_FALSE);

    return NOERROR;
    }

/*
 * tOleInPlaceSite::OnInPlaceActivate
 *
 * Purpose:
 *  Informs the container that an object is being activated in-place
 *  such that the container can prepare appropriately.  The
 *  container does not, however, make any user interface changes at
 *  this point.  See OnUIActivate.
 *
 * Parameters:
 *  None
 *
 * Return Value:
 *  HRESULT         NOERROR or an appropriate error code.
 */

STDMETHODIMP tOleInPlaceSite::OnInPlaceActivate(void)
    {
    //CHAPTER24MOD
    m_pTen->m_fPendingDeactivate=FALSE;
    //End CHAPTER24MOD

    //m_pIOleIPObject is our in-place flag.
    m_pTen->m_pObj->QueryInterface(IID_IOleInPlaceObject
        , (PPVOID)&m_pTen->m_pIOleIPObject);

    return NOERROR;
    }

/*
 * tOleInPlaceSite::OnInPlaceDeactivate
 *
 * Purpose:
 *  Notifies the container that the object has deactivated itself
 *  from an in-place state.  Opposite of OnInPlaceActivate.  The
 *  container does not change any UI at this point.
 *
 * Parameters:
 *  None
 *
 * Return Value:
 *  HRESULT         NOERROR or an appropriate error code.
 */

STDMETHODIMP tOleInPlaceSite::OnInPlaceDeactivate(void)
    {
    /*
     * Since we don't have an Undo command, we can tell the object
     * right away to discard its Undo state.
     */
    m_pTen->Activate(OLEIVERB_DISCARDUNDOSTATE, NULL);
    ReleaseInterface(m_pTen->m_pIOleIPObject);
    return NOERROR;
    }

/*
 * tOleInPlaceSite::OnUIActivate
 *
 * Purpose:
 *  Informs the container that the object is going to start munging
 *  around with user interface, like replacing the menu.  The
 *  container should remove any relevant UI in preparation.
 *
 * Parameters:
 *  None
 *
 * Return Value:
 *  HRESULT         NOERROR or an appropriate error code.
 */

STDMETHODIMP tOleInPlaceSite::OnUIActivate(void)
    {
    //CHAPTER24MOD
    m_pTen->m_fPendingDeactivate=FALSE;
    //End CHAPTER24MOD

    /*
     * Change the currently selected tenant in the page.  This
     * will UIDeactivate the currently UI Active tenant.
     */
    g_fSwitchingActive=TRUE;
    //m_pTen->m_pPG->m_pPageCur->SwitchActiveTenant(m_pTen);
    g_fSwitchingActive=FALSE;

    return NOERROR;
    }

/*
 * tOleInPlaceSite::OnUIDeactivate
 *
 * Purpose:
 *  Informs the container that the object is deactivating its
 *  in-place user interface at which time the container may
 *  reinstate its own.  Opposite of OnUIActivate.
 *
 * Parameters:
 *  fUndoable       BOOL indicating if the object will actually
 *                  perform an Undo if the container calls
 *                  ReactivateAndUndo.
 *
 * Return Value:
 *  HRESULT         NOERROR or an appropriate error code.
 */

STDMETHODIMP tOleInPlaceSite::OnUIDeactivate(BOOL fUndoable)
    {
    MSG         msg;

    /*
     * Ignore this notification if we're switching between
     * multiple active objects.
     */
    if (g_fSwitchingActive)
        return NOERROR;

    //If in shutdown (NULL storage), don't check messages.
/*    if (NULL==m_pTen->m_pIStorage)
        {
        g_pFR->ReinstateUI();
        return NOERROR;
        }*/

    //If there's a pending double-click, delay showing our UI
/*    if (!PeekMessage(&msg, pDoc->Window(), WM_LBUTTONDBLCLK
        , WM_LBUTTONDBLCLK, PM_NOREMOVE | PM_NOYIELD))
        {
        //Turn everything back on.
        g_pFR->ReinstateUI();
        }
    else*/

    return NOERROR;
    }

/*
 * tOleInPlaceSite::DeactivateAndUndo
 *
 * Purpose:
 *  If immediately after activation the object does an Undo, the
 *  action being undone is the activation itself, and this call
 *  informs the container that this is, in fact, what happened.
 *  The container should call IOleInPlaceObject::UIDeactivate.
 *
 * Parameters:
 *  None
 *
 * Return Value:
 *  HRESULT         NOERROR or an appropriate error code.
 */

STDMETHODIMP tOleInPlaceSite::DeactivateAndUndo(void)
    {
    //CHAPTER24MOD
    /*
     * Note that we don't pay attention to the locking
     * from IOleControlSite::LockInPlaceActive since only
     * the object calls this function and should know
     * that it's going to be deactivated.
     */
    //End CHAPTER24MOD

    m_pTen->m_pIOleIPObject->InPlaceDeactivate();
    return NOERROR;
    }

/*
 * tOleInPlaceSite::DiscardUndoState
 *
 * Purpose:
 *  Informs the container that something happened in the object
 *  that means the container should discard any undo information
 *  it currently maintains for the object.
 *
 * Parameters:
 *  None
 *
 * Return Value:
 *  HRESULT         NOERROR or an appropriate error code.
 */

STDMETHODIMP tOleInPlaceSite::DiscardUndoState(void)
    {
    return ResultFromScode(E_NOTIMPL);
    }

/*
 * tOleInPlaceSite::GetWindowContext
 *
 * Purpose:
 *  Provides an in-place object with pointers to the frame and
 *  document level in-place interfaces (IOleInPlaceFrame and
 *  IOleInPlaceUIWindow) such that the object can do border
 *  negotiation and so forth.  Also requests the position and
 *  clipping rectangles of the object in the container and a
 *  pointer to an OLEINPLACEFRAME info structure which contains
 *  accelerator information.
 *
 *  Note that the two interfaces this call returns are not
 *  available through QueryInterface on IOleInPlaceSite since they
 *  live with the frame and document, but not the site.
 *
 * Parameters:
 *  ppIIPFrame      LPOLEINPLACEFRAME * in which to return the
 *                  AddRef'd pointer to the container's
 *                  IOleInPlaceFrame.
 *  ppIIPUIWindow   LPOLEINPLACEUIWINDOW * in which to return
 *                  the AddRef'd pointer to the container document's
 *                  IOleInPlaceUIWindow.
 *  prcPos          LPRECT in which to store the object's position.
 *  prcClip         LPRECT in which to store the object's visible
 *                  region.
 *  pFI             LPOLEINPLACEFRAMEINFO to fill with accelerator
 *                  stuff.
 *
 * Return Value:
 *  HRESULT         NOERROR
 */

STDMETHODIMP tOleInPlaceSite::GetWindowContext
    (LPOLEINPLACEFRAME *ppIIPFrame, LPOLEINPLACEUIWINDOW
    *ppIIPUIWindow, LPRECT prcPos, LPRECT prcClip
    , LPOLEINPLACEFRAMEINFO pFI)
    {
    RECTL           rcl;

    *ppIIPUIWindow=NULL;
    *ppIIPFrame=m_oleinplaceframe;
    m_oleinplaceframe->AddRef();

    GetClientRect(m_pTen->m_hWnd, prcPos);
    GetClientRect(m_pTen->m_hWnd, prcClip);

/*    *ppIIPFrame=(LPOLEINPLACEFRAME)g_pFR;
    g_pFR->AddRef();*/

/*    if (NULL!=pDoc)
        {
        pDoc->QueryInterface(IID_IOleInPlaceUIWindow
            , (PPVOID)ppIIPUIWindow);
        }*/

    //Now get the rectangles and frame information.
    /*m_pTen->RectGet(&rcl, TRUE);
    RECTFROMRECTL(*prcPos, rcl);
                                  0
    //Include scroll position here.
    OffsetRect(prcPos, -(int)m_pTen->m_pPG->m_xPos
        , -(int)m_pTen->m_pPG->m_yPos);

    SetRect(prcClip, 0, 0, 32767, 32767);
*/
    pFI->cb=sizeof(OLEINPLACEFRAMEINFO);
    pFI->fMDIApp=FALSE;

    pFI->hwndFrame=m_pTen->m_hWnd;

    pFI->haccel=NULL;
    pFI->cAccelEntries=0;

    return NOERROR;
    }

/*
 * tOleInPlaceSite::Scroll
 *
 * Purpose:
 *  Asks the container to scroll the document, and thus the object,
 *  by the given amounts in the sz parameter.
 *
 * Parameters:
 *  sz              SIZE containing signed horizontal and vertical
 *                  extents by which the container should scroll.
 *                  These are in device units.
 *
 * Return Value:
 *  HRESULT         NOERROR
 */

STDMETHODIMP tOleInPlaceSite::Scroll(SIZE sz)
    {
    /*int         x, y;

    x=m_pTen->m_pPG->m_xPos+sz.cx;
    y=m_pTen->m_pPG->m_yPos+sz.cy;

    SendScrollPosition(m_pTen->m_hWnd, WM_HSCROLL, x);
    SendScrollPosition(m_pTen->m_hWnd, WM_VSCROLL, y);*/
    return NOERROR;
    }

/*
 * tOleInPlaceSite::OnPosRectChange
 *
 * Purpose:
 *  Informs the container that the in-place object was resized.
 *  The container must call IOleInPlaceObject::SetObjectRects.
 *  This does not change the site's rectangle in any case.
 *
 * Parameters:
 *  prcPos          LPCRECT containing the new size of the object.
 *
 * Return Value:
 *  HRESULT         NOERROR
 */

STDMETHODIMP tOleInPlaceSite::OnPosRectChange(LPCRECT prcPos)
    {
    if (NULL!=prcPos)
        {
        // This change was necessary because some controls were not working, and being positioned in a wrong place.
        // Contribution by Kommit
        LPRECT pPos = (LPRECT)prcPos; // convert the const pointer to non-const pointer to modify it's member values.
        pPos->right -= pPos->left;
        pPos->bottom -= pPos->top;
        pPos->left = 0;
        pPos->top = 0;

        m_pTen->m_rcPos=*prcPos;
        }

    m_pTen->UpdateInPlaceObjectRects(prcPos, FALSE);
    return NOERROR;
    }

<|endoftext|>