<commit_before>/*
 * Skaffari - a mail account administration web interface based on Cutelyst
 * Copyright (C) 2017 Matthias Fehring <kontakt@buschmann23.de>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "skaffari.h"

#include <Cutelyst/Application>
#include <Cutelyst/Plugins/StaticSimple/StaticSimple>
#include <Cutelyst/Plugins/View/Grantlee/grantleeview.h>
#include <Cutelyst/Plugins/Session/Session>
#include <Cutelyst/Plugins/Authentication/authentication.h>
#include <Cutelyst/Plugins/Authentication/credentialpassword.h>
#include <Cutelyst/Plugins/Authentication/authenticationrealm.h>
#include <Cutelyst/Plugins/Utils/Sql>
#include <Cutelyst/Plugins/StatusMessage>
#include <Cutelyst/Plugins/Memcached/Memcached>
#include <Cutelyst/Plugins/MemcachedSessionStore/MemcachedSessionStore>
#include <Cutelyst/Engine>
#include <Cutelyst/Plugins/CSRFProtection/CSRFProtection>
#include <grantlee5/grantlee/metatype.h>
#include <grantlee5/grantlee/engine.h>
#include <QSqlDatabase>
#include <QSqlError>
#include <QDir>
#include <QMetaType>
#include <QCoreApplication>
#include <QTranslator>
#include <QFile>
#include <QJsonDocument>
#include <QJsonObject>

extern "C"
{
#ifdef WITH_SYSTEMD
#define SD_JOURNAL_SUPPRESS_LOCATION
#include <systemd/sd-journal.h>
#endif

#include <syslog.h>
}

#include "objects/domain.h"
#include "objects/simpleadmin.h"
#include "objects/simpledomain.h"
#include "objects/simpleaccount.h"
#include "objects/adminaccount.h"
#include "objects/account.h"
#include "objects/folder.h"
#include "objects/helpentry.h"
#include "objects/emailaddress.h"

#include "utils/language.h"
#include "utils/skaffariconfig.h"

#include "../common/config.h"
#include "../common/global.h"
#include "root.h"
#include "authstoresql.h"
#include "login.h"
#include "logout.h"
#include "domaineditor.h"
#include "accounteditor.h"
#include "admineditor.h"
#include "myaccount.h"
#include "settingseditor.h"

Q_LOGGING_CATEGORY(SK_CORE, "skaffari.core")

using namespace Cutelyst;

bool Skaffari::isInitialized = false;
bool Skaffari::messageHandlerInstalled = false;

#ifdef WITH_SYSTEMD
void journaldMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
    int prio = LOG_INFO;
    switch (type) {
    case QtDebugMsg:
        prio = LOG_DEBUG;
        break;
    case QtInfoMsg:
        prio = LOG_INFO;
        break;
    case QtWarningMsg:
        prio = LOG_WARNING;
        break;
    case QtCriticalMsg:
        prio = LOG_CRIT;
        break;
    case QtFatalMsg:
        prio = LOG_ALERT;
        break;
    }

#ifdef QT_DEBUG
    sd_journal_send("PRIORITY=%i", prio, "SYSLOG_FACILITY=1", "SYSLOG_IDENTIFIER=%s", context.category, "SYSLOG_PID=%lli", QCoreApplication::applicationPid(), "MESSAGE=%s", qFormatLogMessage(type, context, msg).toUtf8().constData(), "CODE_FILE=%s", context.file, "CODE_LINE=%s", context.line, "CODE_FUNC=%s", context.function, NULL);
#else
    sd_journal_send("PRIORITY=%i", prio, "SYSLOG_FACILITY=1", "SYSLOG_IDENTIFIER=%s", context.category, "SYSLOG_PID=%lli", QCoreApplication::applicationPid(), "MESSAGE=%s", qFormatLogMessage(type, context, msg).toUtf8().constData(), NULL);
#endif

    if (prio == 0) {
        abort();
    }
}
#endif

void syslogMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
    int prio = LOG_INFO;
    switch (type) {
    case QtDebugMsg:
        prio = LOG_DEBUG;
        break;
    case QtInfoMsg:
        prio = LOG_INFO;
        break;
    case QtWarningMsg:
        prio = LOG_WARNING;
        break;
    case QtCriticalMsg:
        prio = LOG_CRIT;
        break;
    case QtFatalMsg:
        prio = LOG_ALERT;
        break;
    }

    openlog(context.category, LOG_PID, LOG_USER);
    syslog(prio, "%s", qFormatLogMessage(type, context, msg).toUtf8().constData());
    closelog();

    if (prio == 0) {
        abort();
    }
}

Skaffari::Skaffari(QObject *parent) : Application(parent)
{
}

Skaffari::~Skaffari()
{
}

bool Skaffari::init()
{
    const QVariantMap generalConfig = engine()->config(QStringLiteral("Skaffari"));

    if (!messageHandlerInstalled) {
        const QString backend = generalConfig.value(QStringLiteral("logging_backend")).toString();
        if (backend.compare(QLatin1String("syslog"), Qt::CaseInsensitive) == 0) {
            qSetMessagePattern(QStringLiteral("%{message}"));
            qInstallMessageHandler(syslogMessageOutput);
            qCInfo(SK_CORE, "Using syslog logging backend.");
        }
#ifdef WITH_SYSTEMD
        else if (backend.compare(QLatin1String("journald"), Qt::CaseInsensitive) == 0) {
            qSetMessagePattern(QStringLiteral("%{message}"));
            qInstallMessageHandler(journaldMessageOutput);
            qCInfo(SK_CORE, "Using systemd's journald logging backend.");
        }
#endif
        else {
            qCInfo(SK_CORE, "Using stdout logging backend.");
        }
        messageHandlerInstalled = true;
    }

    QCoreApplication::setApplicationName(QStringLiteral("Skaffari"));
    QCoreApplication::setApplicationVersion(QStringLiteral(SKAFFARI_VERSION));

    qRegisterMetaType<quota_size_t>("quota_size_t");
    qRegisterMetaType<dbid_t>("dbid_t");
    qRegisterMetaType<Folder>();
    qRegisterMetaType<Domain>();
    qRegisterMetaType<SimpleAdmin>();
    qRegisterMetaType<SimpleDomain>();
    qRegisterMetaType<SimpleAccount>();
    qRegisterMetaType<AdminAccount>();
    qRegisterMetaType<Language>();
    qRegisterMetaType<Account>();
    qRegisterMetaType<HelpEntry>();
    qRegisterMetaType<HelpHash>("HelpHash");
    qRegisterMetaType<EmailAddress>();

    Grantlee::registerMetaType<Folder>();
    Grantlee::registerMetaType<Domain>();
    Grantlee::registerMetaType<SimpleAdmin>();
    Grantlee::registerMetaType<SimpleDomain>();
    Grantlee::registerMetaType<SimpleAccount>();
    Grantlee::registerMetaType<AdminAccount>();
    Grantlee::registerMetaType<Language>();
    Grantlee::registerMetaType<Account>();
    Grantlee::registerMetaType<HelpEntry>();
    Grantlee::registerMetaType<EmailAddress>();

    const QString tmplName = generalConfig.value(QStringLiteral("template"), QStringLiteral("default")).toString();
    const QString tmplBasePath = QStringLiteral(SKAFFARI_TMPLDIR) + QLatin1Char('/') + tmplName;
    SkaffariConfig::setTmplBasePath(tmplBasePath);

    if (!isInitialized) {
        QVariantMap tmplConfig;
        QFile tmplConfigFile(tmplBasePath + QLatin1String("/metadata.json"));
        if (tmplConfigFile.exists()) {
            qCDebug(SK_CORE, "Found template metadata file.");
            if (tmplConfigFile.open(QIODevice::ReadOnly|QIODevice::Text)) {
                QJsonParseError jpe;
                QJsonDocument tmplJsonConfig(QJsonDocument::fromJson(tmplConfigFile.readAll(), &jpe));
                if (jpe.error != QJsonParseError::NoError) {
                    qCCritical(SK_CORE, "Failed to parse template metadata file: %s", qUtf8Printable(jpe.errorString()));
                    return false;
                }

                tmplConfig = tmplJsonConfig.object().value(QStringLiteral("config")).toObject().toVariantMap();
            } else {
                qCCritical(SK_CORE, "Failed to open template metadata file %s.", qUtf8Printable(tmplConfigFile.fileName()));
                return false;
            }
        }

        qCDebug(SK_CORE) << "Initializing configuration.";
        SkaffariConfig::load(generalConfig,
                             engine()->config(QStringLiteral("Accounts")),
                             engine()->config(QStringLiteral("Admins")),
                             engine()->config(QStringLiteral("IMAP")),
                             tmplConfig);

        if (SkaffariConfig::imapUser().isEmpty()) {
            qCCritical(SK_CORE) << "No valid IMAP user defined.";
            return false;
        }

        if (SkaffariConfig::imapPassword().isEmpty()) {
            qCCritical(SK_CORE) << "No valid IMAP password defined.";
            return false;
        }

        // initialize DB one time to prevent https://bugreports.qt.io/browse/QTBUG-54872
        if (!initDb()) {
            return false;
        }

        SkaffariConfig::loadSettingsFromDB();

        isInitialized = true;
    }

    QString sitePath = tmplBasePath + QLatin1String("/site");

    auto view = new GrantleeView(this);
    view->setTemplateExtension(QStringLiteral(".html"));
    view->setWrapper(QStringLiteral("wrapper.html"));
    view->setCache(false);
    view->setIncludePaths({sitePath});
    view->engine()->addDefaultLibrary(QStringLiteral("grantlee_i18ntags"));
    view->engine()->addDefaultLibrary(QStringLiteral("grantlee_skaffari"));

    /* Start loading translations */
    const QString tmplTransFileName = QLatin1String("tmpl_") + tmplName;
    const QString tmplTransFilePath = tmplBasePath + QLatin1String("/l10n");

    for (const QString &lang : SKAFFARI_SUPPORTED_LANGS) {
        if (Q_LIKELY(lang != QLatin1String("en"))) {
            qCDebug(SK_CORE, "Loading translations for language %s.", qUtf8Printable(lang));
            const QLocale locale(lang);
            if (Q_LIKELY(locale.language() != QLocale::C)) {
                auto coreTrans = new QTranslator(this);
                if (Q_LIKELY(coreTrans->load(locale, QStringLiteral("skaffari"), QStringLiteral("_"), QStringLiteral(SKAFFARI_L10NDIR)))) {
                    addTranslator(locale, coreTrans);
                } else {
                    qCWarning(SK_CORE, "Failed to load core translation file for language %s from %s.", qUtf8Printable(locale.bcp47Name()), SKAFFARI_L10NDIR);
                    delete coreTrans;
                }

                auto tmplTrans = new QTranslator(this);
                if (Q_LIKELY(tmplTrans->load(locale, tmplTransFileName, QStringLiteral("_"), tmplTransFilePath))) {
                    view->addTranslator(locale, tmplTrans);
                } else {
                    qCWarning(SK_CORE, "Failed to load template translation file for language %s from %s.", qUtf8Printable(locale.bcp47Name()), qUtf8Printable(tmplTransFilePath));
                    delete tmplTrans;
                }
            } else {
                qCWarning(SK_CORE, "Invalid language code: %s", qUtf8Printable(lang));
            }
        }
    }
    /* End loading translations */

    new Root(this);
    new Login(this);
    new Logout(this);
    new DomainEditor(this);
    new AccountEditor(this);
    new AdminEditor(this);
    new MyAccount(this);
    new SettingsEditor(this);

    auto staticSimple = new StaticSimple(this);
    const QString staticPath = tmplBasePath + QLatin1String("/static");
    staticSimple->setIncludePaths({staticPath, QStringLiteral(SKAFFARI_STATICDIR)});

    if (SkaffariConfig::useMemcached()) {
        auto memc = new Memcached(this);
        memc->setDefaultConfig({
                                   {QStringLiteral("binary_protocol"), true}
                               });
    }

    auto sess = new Session(this);

    if (SkaffariConfig::useMemcachedSession()) {
        sess->setStorage(new MemcachedSessionStore(this, this));
    }

    auto csrf = new CSRFProtection(this);
    csrf->setDefaultDetachTo(QStringLiteral("/csrfdenied"));

    new StatusMessage(this);

    auto auth = new Authentication(this);
    auto cred = new CredentialPassword;
    cred->setPasswordType(CredentialPassword::Hashed);
    auto store = new AuthStoreSql;
    auth->addRealm(store, cred);

    defaultHeaders().setHeader(QStringLiteral("X-Frame-Options"), QStringLiteral("DENY"));
    defaultHeaders().setHeader(QStringLiteral("X-Content-Type-Options"), QStringLiteral("nosniff"));
    defaultHeaders().setHeader(QStringLiteral("X-XSS-Protection"), QStringLiteral("1; mode=block"));
    defaultHeaders().setHeader(QStringLiteral("Content-Security-Policy"), QStringLiteral("default-src 'none'; script-src 'self'; style-src 'self'; font-src 'self'; img-src 'self' data:; connect-src 'self'; base-uri 'self'; form-action: 'self';"));
    defaultHeaders().setHeader(QStringLiteral("X-Robots-Tag"), QStringLiteral("none"));
    defaultHeaders().setHeader(QStringLiteral("Referrer-Policy"), QStringLiteral("no-referrer, strict-origin-when-cross-origin"));

    return true;
}

bool Skaffari::postFork()
{

    initDb();

    return true;
}

bool Skaffari::initDb() const
{
    const QVariantMap dbconfig = engine()->config(QStringLiteral("Database"));
    const QString dbtype = dbconfig.value(QStringLiteral("type")).toString();
    const QString dbname = dbconfig.value(QStringLiteral("name")).toString();
    const QString dbuser = dbconfig.value(QStringLiteral("user")).toString();
    const QString dbpass = dbconfig.value(QStringLiteral("password")).toString();
    const QString dbhost = dbconfig.value(QStringLiteral("host"), QStringLiteral("localhost")).toString();
    const int dbport = dbconfig.value(QStringLiteral("port"), QStringLiteral("3306")).toInt();

    qCDebug(SK_CORE) << "Establishing database connection";
    QSqlDatabase db;
    const QString dbConName = Sql::databaseNameThread();
    if (dbtype == QLatin1String("QMYSQL")) {
        if (dbname.isEmpty()) {
            qCCritical(SK_CORE) << "No database name set!";
            return false;
        }
        if (dbuser.isEmpty()) {
            qCCritical(SK_CORE) << "No database user set!";
            return false;
        }
        if (dbpass.isEmpty()) {
            qCCritical(SK_CORE) << "No database password set!";
            return false;
        }

        db = QSqlDatabase::addDatabase(dbtype, dbConName);
        if (Q_LIKELY(db.isValid())) {
            db.setDatabaseName(dbname);
            db.setUserName(dbuser);
            db.setPassword(dbpass);

            if (dbhost[0] == QLatin1Char('/')) {
                db.setConnectOptions(QStringLiteral("UNIX_SOCKET=%1;MYSQL_OPT_RECONNECT=1;CLIENT_INTERACTIVE=1").arg(dbhost));
            } else {
                db.setConnectOptions(QStringLiteral("MYSQL_OPT_RECONNECT=1;CLIENT_INTERACTIVE=1"));
                db.setHostName(dbhost);
                db.setPort(dbport);
            }
        } else {
            qCCritical(SK_CORE) << "Failed to obtain database object.";
            return false;
        }
    } else {
        qCCritical(SK_CORE) << dbtype << "is not a supported database type.";
        return false;
    }

    if (Q_UNLIKELY(!db.open())) {
        qCCritical(SK_CORE) << "Failed to establish database connection:" << db.lastError().text();
        return false;
    }

    return true;
}

#include "moc_skaffari.cpp"
<commit_msg>Fix default CSP header<commit_after>/*
 * Skaffari - a mail account administration web interface based on Cutelyst
 * Copyright (C) 2017 Matthias Fehring <kontakt@buschmann23.de>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "skaffari.h"

#include <Cutelyst/Application>
#include <Cutelyst/Plugins/StaticSimple/StaticSimple>
#include <Cutelyst/Plugins/View/Grantlee/grantleeview.h>
#include <Cutelyst/Plugins/Session/Session>
#include <Cutelyst/Plugins/Authentication/authentication.h>
#include <Cutelyst/Plugins/Authentication/credentialpassword.h>
#include <Cutelyst/Plugins/Authentication/authenticationrealm.h>
#include <Cutelyst/Plugins/Utils/Sql>
#include <Cutelyst/Plugins/StatusMessage>
#include <Cutelyst/Plugins/Memcached/Memcached>
#include <Cutelyst/Plugins/MemcachedSessionStore/MemcachedSessionStore>
#include <Cutelyst/Engine>
#include <Cutelyst/Plugins/CSRFProtection/CSRFProtection>
#include <grantlee5/grantlee/metatype.h>
#include <grantlee5/grantlee/engine.h>
#include <QSqlDatabase>
#include <QSqlError>
#include <QDir>
#include <QMetaType>
#include <QCoreApplication>
#include <QTranslator>
#include <QFile>
#include <QJsonDocument>
#include <QJsonObject>

extern "C"
{
#ifdef WITH_SYSTEMD
#define SD_JOURNAL_SUPPRESS_LOCATION
#include <systemd/sd-journal.h>
#endif

#include <syslog.h>
}

#include "objects/domain.h"
#include "objects/simpleadmin.h"
#include "objects/simpledomain.h"
#include "objects/simpleaccount.h"
#include "objects/adminaccount.h"
#include "objects/account.h"
#include "objects/folder.h"
#include "objects/helpentry.h"
#include "objects/emailaddress.h"

#include "utils/language.h"
#include "utils/skaffariconfig.h"

#include "../common/config.h"
#include "../common/global.h"
#include "root.h"
#include "authstoresql.h"
#include "login.h"
#include "logout.h"
#include "domaineditor.h"
#include "accounteditor.h"
#include "admineditor.h"
#include "myaccount.h"
#include "settingseditor.h"

Q_LOGGING_CATEGORY(SK_CORE, "skaffari.core")

using namespace Cutelyst;

bool Skaffari::isInitialized = false;
bool Skaffari::messageHandlerInstalled = false;

#ifdef WITH_SYSTEMD
void journaldMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
    int prio = LOG_INFO;
    switch (type) {
    case QtDebugMsg:
        prio = LOG_DEBUG;
        break;
    case QtInfoMsg:
        prio = LOG_INFO;
        break;
    case QtWarningMsg:
        prio = LOG_WARNING;
        break;
    case QtCriticalMsg:
        prio = LOG_CRIT;
        break;
    case QtFatalMsg:
        prio = LOG_ALERT;
        break;
    }

#ifdef QT_DEBUG
    sd_journal_send("PRIORITY=%i", prio, "SYSLOG_FACILITY=1", "SYSLOG_IDENTIFIER=%s", context.category, "SYSLOG_PID=%lli", QCoreApplication::applicationPid(), "MESSAGE=%s", qFormatLogMessage(type, context, msg).toUtf8().constData(), "CODE_FILE=%s", context.file, "CODE_LINE=%s", context.line, "CODE_FUNC=%s", context.function, NULL);
#else
    sd_journal_send("PRIORITY=%i", prio, "SYSLOG_FACILITY=1", "SYSLOG_IDENTIFIER=%s", context.category, "SYSLOG_PID=%lli", QCoreApplication::applicationPid(), "MESSAGE=%s", qFormatLogMessage(type, context, msg).toUtf8().constData(), NULL);
#endif

    if (prio == 0) {
        abort();
    }
}
#endif

void syslogMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
    int prio = LOG_INFO;
    switch (type) {
    case QtDebugMsg:
        prio = LOG_DEBUG;
        break;
    case QtInfoMsg:
        prio = LOG_INFO;
        break;
    case QtWarningMsg:
        prio = LOG_WARNING;
        break;
    case QtCriticalMsg:
        prio = LOG_CRIT;
        break;
    case QtFatalMsg:
        prio = LOG_ALERT;
        break;
    }

    openlog(context.category, LOG_PID, LOG_USER);
    syslog(prio, "%s", qFormatLogMessage(type, context, msg).toUtf8().constData());
    closelog();

    if (prio == 0) {
        abort();
    }
}

Skaffari::Skaffari(QObject *parent) : Application(parent)
{
}

Skaffari::~Skaffari()
{
}

bool Skaffari::init()
{
    const QVariantMap generalConfig = engine()->config(QStringLiteral("Skaffari"));

    if (!messageHandlerInstalled) {
        const QString backend = generalConfig.value(QStringLiteral("logging_backend")).toString();
        if (backend.compare(QLatin1String("syslog"), Qt::CaseInsensitive) == 0) {
            qSetMessagePattern(QStringLiteral("%{message}"));
            qInstallMessageHandler(syslogMessageOutput);
            qCInfo(SK_CORE, "Using syslog logging backend.");
        }
#ifdef WITH_SYSTEMD
        else if (backend.compare(QLatin1String("journald"), Qt::CaseInsensitive) == 0) {
            qSetMessagePattern(QStringLiteral("%{message}"));
            qInstallMessageHandler(journaldMessageOutput);
            qCInfo(SK_CORE, "Using systemd's journald logging backend.");
        }
#endif
        else {
            qCInfo(SK_CORE, "Using stdout logging backend.");
        }
        messageHandlerInstalled = true;
    }

    QCoreApplication::setApplicationName(QStringLiteral("Skaffari"));
    QCoreApplication::setApplicationVersion(QStringLiteral(SKAFFARI_VERSION));

    qRegisterMetaType<quota_size_t>("quota_size_t");
    qRegisterMetaType<dbid_t>("dbid_t");
    qRegisterMetaType<Folder>();
    qRegisterMetaType<Domain>();
    qRegisterMetaType<SimpleAdmin>();
    qRegisterMetaType<SimpleDomain>();
    qRegisterMetaType<SimpleAccount>();
    qRegisterMetaType<AdminAccount>();
    qRegisterMetaType<Language>();
    qRegisterMetaType<Account>();
    qRegisterMetaType<HelpEntry>();
    qRegisterMetaType<HelpHash>("HelpHash");
    qRegisterMetaType<EmailAddress>();

    Grantlee::registerMetaType<Folder>();
    Grantlee::registerMetaType<Domain>();
    Grantlee::registerMetaType<SimpleAdmin>();
    Grantlee::registerMetaType<SimpleDomain>();
    Grantlee::registerMetaType<SimpleAccount>();
    Grantlee::registerMetaType<AdminAccount>();
    Grantlee::registerMetaType<Language>();
    Grantlee::registerMetaType<Account>();
    Grantlee::registerMetaType<HelpEntry>();
    Grantlee::registerMetaType<EmailAddress>();

    const QString tmplName = generalConfig.value(QStringLiteral("template"), QStringLiteral("default")).toString();
    const QString tmplBasePath = QStringLiteral(SKAFFARI_TMPLDIR) + QLatin1Char('/') + tmplName;
    SkaffariConfig::setTmplBasePath(tmplBasePath);

    if (!isInitialized) {
        QVariantMap tmplConfig;
        QFile tmplConfigFile(tmplBasePath + QLatin1String("/metadata.json"));
        if (tmplConfigFile.exists()) {
            qCDebug(SK_CORE, "Found template metadata file.");
            if (tmplConfigFile.open(QIODevice::ReadOnly|QIODevice::Text)) {
                QJsonParseError jpe;
                QJsonDocument tmplJsonConfig(QJsonDocument::fromJson(tmplConfigFile.readAll(), &jpe));
                if (jpe.error != QJsonParseError::NoError) {
                    qCCritical(SK_CORE, "Failed to parse template metadata file: %s", qUtf8Printable(jpe.errorString()));
                    return false;
                }

                tmplConfig = tmplJsonConfig.object().value(QStringLiteral("config")).toObject().toVariantMap();
            } else {
                qCCritical(SK_CORE, "Failed to open template metadata file %s.", qUtf8Printable(tmplConfigFile.fileName()));
                return false;
            }
        }

        qCDebug(SK_CORE) << "Initializing configuration.";
        SkaffariConfig::load(generalConfig,
                             engine()->config(QStringLiteral("Accounts")),
                             engine()->config(QStringLiteral("Admins")),
                             engine()->config(QStringLiteral("IMAP")),
                             tmplConfig);

        if (SkaffariConfig::imapUser().isEmpty()) {
            qCCritical(SK_CORE) << "No valid IMAP user defined.";
            return false;
        }

        if (SkaffariConfig::imapPassword().isEmpty()) {
            qCCritical(SK_CORE) << "No valid IMAP password defined.";
            return false;
        }

        // initialize DB one time to prevent https://bugreports.qt.io/browse/QTBUG-54872
        if (!initDb()) {
            return false;
        }

        SkaffariConfig::loadSettingsFromDB();

        isInitialized = true;
    }

    QString sitePath = tmplBasePath + QLatin1String("/site");

    auto view = new GrantleeView(this);
    view->setTemplateExtension(QStringLiteral(".html"));
    view->setWrapper(QStringLiteral("wrapper.html"));
    view->setCache(false);
    view->setIncludePaths({sitePath});
    view->engine()->addDefaultLibrary(QStringLiteral("grantlee_i18ntags"));
    view->engine()->addDefaultLibrary(QStringLiteral("grantlee_skaffari"));

    /* Start loading translations */
    const QString tmplTransFileName = QLatin1String("tmpl_") + tmplName;
    const QString tmplTransFilePath = tmplBasePath + QLatin1String("/l10n");

    for (const QString &lang : SKAFFARI_SUPPORTED_LANGS) {
        if (Q_LIKELY(lang != QLatin1String("en"))) {
            qCDebug(SK_CORE, "Loading translations for language %s.", qUtf8Printable(lang));
            const QLocale locale(lang);
            if (Q_LIKELY(locale.language() != QLocale::C)) {
                auto coreTrans = new QTranslator(this);
                if (Q_LIKELY(coreTrans->load(locale, QStringLiteral("skaffari"), QStringLiteral("_"), QStringLiteral(SKAFFARI_L10NDIR)))) {
                    addTranslator(locale, coreTrans);
                } else {
                    qCWarning(SK_CORE, "Failed to load core translation file for language %s from %s.", qUtf8Printable(locale.bcp47Name()), SKAFFARI_L10NDIR);
                    delete coreTrans;
                }

                auto tmplTrans = new QTranslator(this);
                if (Q_LIKELY(tmplTrans->load(locale, tmplTransFileName, QStringLiteral("_"), tmplTransFilePath))) {
                    view->addTranslator(locale, tmplTrans);
                } else {
                    qCWarning(SK_CORE, "Failed to load template translation file for language %s from %s.", qUtf8Printable(locale.bcp47Name()), qUtf8Printable(tmplTransFilePath));
                    delete tmplTrans;
                }
            } else {
                qCWarning(SK_CORE, "Invalid language code: %s", qUtf8Printable(lang));
            }
        }
    }
    /* End loading translations */

    new Root(this);
    new Login(this);
    new Logout(this);
    new DomainEditor(this);
    new AccountEditor(this);
    new AdminEditor(this);
    new MyAccount(this);
    new SettingsEditor(this);

    auto staticSimple = new StaticSimple(this);
    const QString staticPath = tmplBasePath + QLatin1String("/static");
    staticSimple->setIncludePaths({staticPath, QStringLiteral(SKAFFARI_STATICDIR)});

    if (SkaffariConfig::useMemcached()) {
        auto memc = new Memcached(this);
        memc->setDefaultConfig({
                                   {QStringLiteral("binary_protocol"), true}
                               });
    }

    auto sess = new Session(this);

    if (SkaffariConfig::useMemcachedSession()) {
        sess->setStorage(new MemcachedSessionStore(this, this));
    }

    auto csrf = new CSRFProtection(this);
    csrf->setDefaultDetachTo(QStringLiteral("/csrfdenied"));

    new StatusMessage(this);

    auto auth = new Authentication(this);
    auto cred = new CredentialPassword;
    cred->setPasswordType(CredentialPassword::Hashed);
    auto store = new AuthStoreSql;
    auth->addRealm(store, cred);

    defaultHeaders().setHeader(QStringLiteral("X-Frame-Options"), QStringLiteral("DENY"));
    defaultHeaders().setHeader(QStringLiteral("X-Content-Type-Options"), QStringLiteral("nosniff"));
    defaultHeaders().setHeader(QStringLiteral("X-XSS-Protection"), QStringLiteral("1; mode=block"));
    defaultHeaders().setHeader(QStringLiteral("Content-Security-Policy"), QStringLiteral("default-src 'none'; script-src 'self'; style-src 'self'; font-src 'self'; img-src 'self' data:; connect-src 'self'; base-uri 'self'; form-action 'self';"));
    defaultHeaders().setHeader(QStringLiteral("X-Robots-Tag"), QStringLiteral("none"));
    defaultHeaders().setHeader(QStringLiteral("Referrer-Policy"), QStringLiteral("no-referrer, strict-origin-when-cross-origin"));

    return true;
}

bool Skaffari::postFork()
{

    initDb();

    return true;
}

bool Skaffari::initDb() const
{
    const QVariantMap dbconfig = engine()->config(QStringLiteral("Database"));
    const QString dbtype = dbconfig.value(QStringLiteral("type")).toString();
    const QString dbname = dbconfig.value(QStringLiteral("name")).toString();
    const QString dbuser = dbconfig.value(QStringLiteral("user")).toString();
    const QString dbpass = dbconfig.value(QStringLiteral("password")).toString();
    const QString dbhost = dbconfig.value(QStringLiteral("host"), QStringLiteral("localhost")).toString();
    const int dbport = dbconfig.value(QStringLiteral("port"), QStringLiteral("3306")).toInt();

    qCDebug(SK_CORE) << "Establishing database connection";
    QSqlDatabase db;
    const QString dbConName = Sql::databaseNameThread();
    if (dbtype == QLatin1String("QMYSQL")) {
        if (dbname.isEmpty()) {
            qCCritical(SK_CORE) << "No database name set!";
            return false;
        }
        if (dbuser.isEmpty()) {
            qCCritical(SK_CORE) << "No database user set!";
            return false;
        }
        if (dbpass.isEmpty()) {
            qCCritical(SK_CORE) << "No database password set!";
            return false;
        }

        db = QSqlDatabase::addDatabase(dbtype, dbConName);
        if (Q_LIKELY(db.isValid())) {
            db.setDatabaseName(dbname);
            db.setUserName(dbuser);
            db.setPassword(dbpass);

            if (dbhost[0] == QLatin1Char('/')) {
                db.setConnectOptions(QStringLiteral("UNIX_SOCKET=%1;MYSQL_OPT_RECONNECT=1;CLIENT_INTERACTIVE=1").arg(dbhost));
            } else {
                db.setConnectOptions(QStringLiteral("MYSQL_OPT_RECONNECT=1;CLIENT_INTERACTIVE=1"));
                db.setHostName(dbhost);
                db.setPort(dbport);
            }
        } else {
            qCCritical(SK_CORE) << "Failed to obtain database object.";
            return false;
        }
    } else {
        qCCritical(SK_CORE) << dbtype << "is not a supported database type.";
        return false;
    }

    if (Q_UNLIKELY(!db.open())) {
        qCCritical(SK_CORE) << "Failed to establish database connection:" << db.lastError().text();
        return false;
    }

    return true;
}

#include "moc_skaffari.cpp"
<|endoftext|>


<commit_before>#include "lua_item.h"

void LuaItem::register_lua(sol::environment env, uint8_t type, uint16_t id) {
    Data d;
    d.api = std::make_shared<ItemLuaApi>(env);
    d.env = env;
    data.emplace(std::tuple{type, id}, d);
}

void LuaItem::delete_item(uint8_t type, uint16_t id) {
    data.erase({type, id});
}

std::weak_ptr<ItemLuaApi> LuaItem::get_lua_api(uint8_t type, uint16_t id) {
    if (auto it = data.find({type, id}); it != data.end()) {
        return it->second.api;
    }
    return {};
}
<commit_msg>Update lua_item.cpp<commit_after>#include "lua_item.h"

void LuaItem::register_lua(sol::environment env, uint8_t type, uint16_t id,
                           std::function<void(RoseCommon::Entity, int, int)>&& addBonusAttr,
                           std::function<void(RoseCommon::Entity, int, int)>&& removeBonusAttr) {
    Data d;
    d.api = std::make_shared<ItemLuaApi>(env);
    d.api->register_add_bonus_attr(std::forward<decltype(addBonusAttr)>(addBonusAttr));
    d.api->register_remove_bonus_attr(std::foward<decltype(removeBonusAttr)>(removeBonusAttr));
    d.env = env;
    data.emplace(std::tuple{type, id}, d);
}

void LuaItem::delete_item(uint8_t type, uint16_t id) {
    data.erase({type, id});
}

std::weak_ptr<ItemLuaApi> LuaItem::get_lua_api(uint8_t type, uint16_t id) {
    if (auto it = data.find({type, id}); it != data.end()) {
        return it->second.api;
    }
    return {};
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2012, Alexander Fronkin
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms,
 * with or without modification, are permitted provided
 * that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above
 *    copyright notice, this list of conditions and the
 *    following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above
 *    copyright notice, this list of conditions and the following
 *    disclaimer in the documentation and/or other materials
 *    provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 * OF SUCH DAMAGE.
 */

#include "marcrecord.h"
#include "marcrecord_tools.h"

/*
 * Constructor.
 */
MarcRecord::Field::Field(const std::string &tag, const std::string &data)
{
	clear();
	m_type = CONTROLFIELD;
	m_tag = tag;
	m_data = data;
}

MarcRecord::Field::Field(const std::string &tag, char ind1, char ind2)
{
	clear();
	m_type = DATAFIELD;
	m_tag = tag;
	m_ind1 = ind1;
	m_ind2 = ind2;
}

/*
 * Clear field data.
 */
void MarcRecord::Field::clear(void)
{
	m_type = CONTROLFIELD;
	m_tag = "";
	m_data.erase();
	m_ind1 = ' ';
	m_ind2 = ' ';
	m_subfieldList.clear();
}

/*
 * Set type of field to control field.
 */
void MarcRecord::Field::setControlFieldType(void)
{
	if (m_type != CONTROLFIELD) {
		m_type = CONTROLFIELD;
		clear();
	}
}

/*
 * Set type of field to data field.
 */
void MarcRecord::Field::setDataFieldType(void)
{
	if (m_type != DATAFIELD) {
		m_type = DATAFIELD;
		clear();
	}
}

/*
 * Return true if file type is control field.
 */
bool MarcRecord::Field::isControlField(void)
{
	return (m_type == CONTROLFIELD);
}

/*
 * Return true if file type is data field.
 */
bool MarcRecord::Field::isDataField(void)
{
	return (m_type == DATAFIELD);
}

/*
 * Get tag of data field.
 */
std::string & MarcRecord::Field::getTag(void)
{
	return m_tag;
}

/*
 * Set tag of data field.
 */
void MarcRecord::Field::setTag(const std::string &tag)
{
	m_tag = tag;
}

/*
 * Get indicator 1 of data field.
 */
char & MarcRecord::Field::getInd1(void)
{
	return m_ind1;
}

/*
 * Get indicator 2 of data field.
 */
char & MarcRecord::Field::getInd2(void)
{
	return m_ind2;
}

/*
 * Set indicator 1 of data field.
 */
void MarcRecord::Field::setInd1(const char ind1)
{
	m_ind1 = ind1;
}

/*
 * Set indicator 2 of data field.
 */
void MarcRecord::Field::setInd2(const char ind2)
{
	m_ind2 = ind2;
}

/*
 * Get data of control field.
 */
std::string & MarcRecord::Field::getData(void)
{
	return m_data;
}

/*
 * Set data of control field.
 */
void MarcRecord::Field::setData(const std::string &data)
{
	m_data = data;
}

/*
 * Format field to string.
 */
std::string MarcRecord::Field::toString(void)
{
	/* Format control field to string. */
	if (m_type == CONTROLFIELD) {
		return (m_tag + " " + m_data);
	}

	/* Format data field to string. */
	std::string textField = m_tag;
	snprintf(textField, 5, " [%c%c]", m_ind1, m_ind2);

	/* Iterate all subfields. */
	for (MarcRecord::SubfieldIt subfieldIt = m_subfieldList.begin();
		subfieldIt != m_subfieldList.end(); subfieldIt++)
	{
		// if (formatVariant == UNIMARC && subfieldIt->id == '1') {
		if (subfieldIt->m_id == '1') {
			/* Print header of embedded field. */
			snprintf(textField, 4, " $%c ", subfieldIt->m_id);
			if (subfieldIt->getEmbeddedTag() < "010") {
				textField += "<" + subfieldIt->getEmbeddedTag() + "> "
					+ subfieldIt->getEmbeddedData();
			} else {
				textField += "<" + subfieldIt->getEmbeddedTag() + "> ["
					+ subfieldIt->getEmbeddedInd1()
					+ subfieldIt->getEmbeddedInd2() + "]";
			}
		} else {
			/* Print regular subfield. */
			snprintf(textField, 4, " $%c ", subfieldIt->m_id);
			textField += subfieldIt->m_data;
		}
	}

	return textField;
}

/*
 * Get list of subfields.
 */
MarcRecord::SubfieldRefList MarcRecord::Field::getSubfields(char subfieldId)
{
	SubfieldRefList resultSubfieldList;
	SubfieldIt subfieldIt;

	/* Check subfields in list. */
	for (subfieldIt = m_subfieldList.begin(); subfieldIt != m_subfieldList.end();
		subfieldIt++)
	{
		if (subfieldId == ' ' || subfieldIt->m_id == subfieldId) {
			resultSubfieldList.push_back(subfieldIt);
		}
	}

	return resultSubfieldList;
}

/*
 * Get subfield.
 */
MarcRecord::SubfieldIt MarcRecord::Field::getSubfield(char subfieldId)
{
	SubfieldIt subfieldIt;

	/* Check subfields in list. */
	for (subfieldIt = m_subfieldList.begin(); subfieldIt != m_subfieldList.end();
		subfieldIt++)
	{
		if (subfieldId == ' ' || subfieldIt->m_id == subfieldId) {
			return subfieldIt;
		}
	}

	return m_subfieldList.end();
}

/*
 * Get list of embedded fields.
 */
MarcRecord::EmbeddedFieldList MarcRecord::Field::getEmbeddedFields(const std::string &fieldTag)
{
	EmbeddedFieldList resultFieldList;
	SubfieldRefList embeddedSubfieldList;

	/* Check subfields in list. */
	embeddedSubfieldList.clear();
	for (SubfieldIt subfieldIt = m_subfieldList.begin();
		subfieldIt != m_subfieldList.end(); subfieldIt++)
	{
		if (subfieldIt->m_id == '1') {
			if (embeddedSubfieldList.empty() == false) {
				/* Append embedded field to the result list. */
				resultFieldList.push_back(embeddedSubfieldList);
				embeddedSubfieldList.clear();
			}

			if (fieldTag == "" || fieldTag == subfieldIt->getEmbeddedTag()) {
				/* Append first subfield of embedded field. */
				embeddedSubfieldList.push_back(subfieldIt);
			}
		} else if (embeddedSubfieldList.empty() == false) {
			/* Append subfield to the embedded field. */
			embeddedSubfieldList.push_back(subfieldIt);
		}
	}

	if (embeddedSubfieldList.empty() == false) {
		/* Append embedded field to the result list. */
		resultFieldList.push_back(embeddedSubfieldList);
	}

	return resultFieldList;
}

/*
 * Get embedded field.
 */
MarcRecord::SubfieldRefList MarcRecord::Field::getEmbeddedField(const std::string &fieldTag)
{
	SubfieldRefList embeddedSubfieldList;

	/* Check subfields in list. */
	embeddedSubfieldList.clear();
	for (SubfieldIt subfieldIt = m_subfieldList.begin();
		subfieldIt != m_subfieldList.end(); subfieldIt++)
	{
		if (subfieldIt->m_id == '1') {
			if (embeddedSubfieldList.empty() == false) {
				break;
			}

			if (fieldTag == "" || fieldTag == subfieldIt->getEmbeddedTag()) {
				/* Append first subfield of embedded field. */
				embeddedSubfieldList.push_back(subfieldIt);
			}
		} else if (embeddedSubfieldList.empty() == false) {
			/* Append subfield to the embedded field. */
			embeddedSubfieldList.push_back(subfieldIt);
		}
	}

	return embeddedSubfieldList;
}

/*
 * Add subfield to the end of field.
 */
MarcRecord::SubfieldIt MarcRecord::Field::addSubfield(const Subfield &subfield)
{
	/* Append subfield to the list. */
	SubfieldIt subfieldIt = m_subfieldList.insert(m_subfieldList.end(), subfield);
	return subfieldIt;
}

MarcRecord::SubfieldIt MarcRecord::Field::addSubfield(char subfieldId,
	const std::string &subfieldData)
{
	/* Append subfield to the list. */
	SubfieldIt subfieldIt = m_subfieldList.insert(m_subfieldList.end(),
		Subfield(subfieldId, subfieldData));
	return subfieldIt;
}

/*
 * Add subfield to the field before specified subfield.
 */
MarcRecord::SubfieldIt MarcRecord::Field::addSubfieldBefore(SubfieldIt nextSubfieldIt,
	const Subfield &subfield)
{
	/* Append subfield to the list. */
	SubfieldIt subfieldIt = m_subfieldList.insert(nextSubfieldIt, subfield);
	return subfieldIt;
}

MarcRecord::SubfieldIt MarcRecord::Field::addSubfieldBefore(SubfieldIt nextSubfieldIt,
	char subfieldId, const std::string &subfieldData)
{
	/* Append subfield to the list. */
	SubfieldIt subfieldIt = m_subfieldList.insert(nextSubfieldIt,
		Subfield(subfieldId, subfieldData));
	return subfieldIt;
}

/*
 * Remove subfield from the field.
 */
void MarcRecord::Field::removeSubfield(SubfieldIt subfieldIt)
{
	/* Remove subfield from the list. */
	m_subfieldList.erase(subfieldIt);
}
<commit_msg>Fixed order of operations in setControlFieldType() and setDataFieldType()<commit_after>/*
 * Copyright (c) 2012, Alexander Fronkin
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms,
 * with or without modification, are permitted provided
 * that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above
 *    copyright notice, this list of conditions and the
 *    following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above
 *    copyright notice, this list of conditions and the following
 *    disclaimer in the documentation and/or other materials
 *    provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 * OF SUCH DAMAGE.
 */

#include "marcrecord.h"
#include "marcrecord_tools.h"

/*
 * Constructor.
 */
MarcRecord::Field::Field(const std::string &tag, const std::string &data)
{
	clear();
	m_type = CONTROLFIELD;
	m_tag = tag;
	m_data = data;
}

MarcRecord::Field::Field(const std::string &tag, char ind1, char ind2)
{
	clear();
	m_type = DATAFIELD;
	m_tag = tag;
	m_ind1 = ind1;
	m_ind2 = ind2;
}

/*
 * Clear field data.
 */
void MarcRecord::Field::clear(void)
{
	m_type = CONTROLFIELD;
	m_tag = "";
	m_data.erase();
	m_ind1 = ' ';
	m_ind2 = ' ';
	m_subfieldList.clear();
}

/*
 * Set type of field to control field.
 */
void MarcRecord::Field::setControlFieldType(void)
{
	if (m_type != CONTROLFIELD) {
		clear();
		m_type = CONTROLFIELD;
	}
}

/*
 * Set type of field to data field.
 */
void MarcRecord::Field::setDataFieldType(void)
{
	if (m_type != DATAFIELD) {
		clear();
		m_type = DATAFIELD;
	}
}

/*
 * Return true if file type is control field.
 */
bool MarcRecord::Field::isControlField(void)
{
	return (m_type == CONTROLFIELD);
}

/*
 * Return true if file type is data field.
 */
bool MarcRecord::Field::isDataField(void)
{
	return (m_type == DATAFIELD);
}

/*
 * Get tag of data field.
 */
std::string & MarcRecord::Field::getTag(void)
{
	return m_tag;
}

/*
 * Set tag of data field.
 */
void MarcRecord::Field::setTag(const std::string &tag)
{
	m_tag = tag;
}

/*
 * Get indicator 1 of data field.
 */
char & MarcRecord::Field::getInd1(void)
{
	return m_ind1;
}

/*
 * Get indicator 2 of data field.
 */
char & MarcRecord::Field::getInd2(void)
{
	return m_ind2;
}

/*
 * Set indicator 1 of data field.
 */
void MarcRecord::Field::setInd1(const char ind1)
{
	m_ind1 = ind1;
}

/*
 * Set indicator 2 of data field.
 */
void MarcRecord::Field::setInd2(const char ind2)
{
	m_ind2 = ind2;
}

/*
 * Get data of control field.
 */
std::string & MarcRecord::Field::getData(void)
{
	return m_data;
}

/*
 * Set data of control field.
 */
void MarcRecord::Field::setData(const std::string &data)
{
	m_data = data;
}

/*
 * Format field to string.
 */
std::string MarcRecord::Field::toString(void)
{
	/* Format control field to string. */
	if (m_type == CONTROLFIELD) {
		return (m_tag + " " + m_data);
	}

	/* Format data field to string. */
	std::string textField = m_tag;
	snprintf(textField, 5, " [%c%c]", m_ind1, m_ind2);

	/* Iterate all subfields. */
	for (MarcRecord::SubfieldIt subfieldIt = m_subfieldList.begin();
		subfieldIt != m_subfieldList.end(); subfieldIt++)
	{
		// if (formatVariant == UNIMARC && subfieldIt->id == '1') {
		if (subfieldIt->m_id == '1') {
			/* Print header of embedded field. */
			snprintf(textField, 4, " $%c ", subfieldIt->m_id);
			if (subfieldIt->getEmbeddedTag() < "010") {
				textField += "<" + subfieldIt->getEmbeddedTag() + "> "
					+ subfieldIt->getEmbeddedData();
			} else {
				textField += "<" + subfieldIt->getEmbeddedTag() + "> ["
					+ subfieldIt->getEmbeddedInd1()
					+ subfieldIt->getEmbeddedInd2() + "]";
			}
		} else {
			/* Print regular subfield. */
			snprintf(textField, 4, " $%c ", subfieldIt->m_id);
			textField += subfieldIt->m_data;
		}
	}

	return textField;
}

/*
 * Get list of subfields.
 */
MarcRecord::SubfieldRefList MarcRecord::Field::getSubfields(char subfieldId)
{
	SubfieldRefList resultSubfieldList;
	SubfieldIt subfieldIt;

	/* Check subfields in list. */
	for (subfieldIt = m_subfieldList.begin(); subfieldIt != m_subfieldList.end();
		subfieldIt++)
	{
		if (subfieldId == ' ' || subfieldIt->m_id == subfieldId) {
			resultSubfieldList.push_back(subfieldIt);
		}
	}

	return resultSubfieldList;
}

/*
 * Get subfield.
 */
MarcRecord::SubfieldIt MarcRecord::Field::getSubfield(char subfieldId)
{
	SubfieldIt subfieldIt;

	/* Check subfields in list. */
	for (subfieldIt = m_subfieldList.begin(); subfieldIt != m_subfieldList.end();
		subfieldIt++)
	{
		if (subfieldId == ' ' || subfieldIt->m_id == subfieldId) {
			return subfieldIt;
		}
	}

	return m_subfieldList.end();
}

/*
 * Get list of embedded fields.
 */
MarcRecord::EmbeddedFieldList MarcRecord::Field::getEmbeddedFields(const std::string &fieldTag)
{
	EmbeddedFieldList resultFieldList;
	SubfieldRefList embeddedSubfieldList;

	/* Check subfields in list. */
	embeddedSubfieldList.clear();
	for (SubfieldIt subfieldIt = m_subfieldList.begin();
		subfieldIt != m_subfieldList.end(); subfieldIt++)
	{
		if (subfieldIt->m_id == '1') {
			if (embeddedSubfieldList.empty() == false) {
				/* Append embedded field to the result list. */
				resultFieldList.push_back(embeddedSubfieldList);
				embeddedSubfieldList.clear();
			}

			if (fieldTag == "" || fieldTag == subfieldIt->getEmbeddedTag()) {
				/* Append first subfield of embedded field. */
				embeddedSubfieldList.push_back(subfieldIt);
			}
		} else if (embeddedSubfieldList.empty() == false) {
			/* Append subfield to the embedded field. */
			embeddedSubfieldList.push_back(subfieldIt);
		}
	}

	if (embeddedSubfieldList.empty() == false) {
		/* Append embedded field to the result list. */
		resultFieldList.push_back(embeddedSubfieldList);
	}

	return resultFieldList;
}

/*
 * Get embedded field.
 */
MarcRecord::SubfieldRefList MarcRecord::Field::getEmbeddedField(const std::string &fieldTag)
{
	SubfieldRefList embeddedSubfieldList;

	/* Check subfields in list. */
	embeddedSubfieldList.clear();
	for (SubfieldIt subfieldIt = m_subfieldList.begin();
		subfieldIt != m_subfieldList.end(); subfieldIt++)
	{
		if (subfieldIt->m_id == '1') {
			if (embeddedSubfieldList.empty() == false) {
				break;
			}

			if (fieldTag == "" || fieldTag == subfieldIt->getEmbeddedTag()) {
				/* Append first subfield of embedded field. */
				embeddedSubfieldList.push_back(subfieldIt);
			}
		} else if (embeddedSubfieldList.empty() == false) {
			/* Append subfield to the embedded field. */
			embeddedSubfieldList.push_back(subfieldIt);
		}
	}

	return embeddedSubfieldList;
}

/*
 * Add subfield to the end of field.
 */
MarcRecord::SubfieldIt MarcRecord::Field::addSubfield(const Subfield &subfield)
{
	/* Append subfield to the list. */
	SubfieldIt subfieldIt = m_subfieldList.insert(m_subfieldList.end(), subfield);
	return subfieldIt;
}

MarcRecord::SubfieldIt MarcRecord::Field::addSubfield(char subfieldId,
	const std::string &subfieldData)
{
	/* Append subfield to the list. */
	SubfieldIt subfieldIt = m_subfieldList.insert(m_subfieldList.end(),
		Subfield(subfieldId, subfieldData));
	return subfieldIt;
}

/*
 * Add subfield to the field before specified subfield.
 */
MarcRecord::SubfieldIt MarcRecord::Field::addSubfieldBefore(SubfieldIt nextSubfieldIt,
	const Subfield &subfield)
{
	/* Append subfield to the list. */
	SubfieldIt subfieldIt = m_subfieldList.insert(nextSubfieldIt, subfield);
	return subfieldIt;
}

MarcRecord::SubfieldIt MarcRecord::Field::addSubfieldBefore(SubfieldIt nextSubfieldIt,
	char subfieldId, const std::string &subfieldData)
{
	/* Append subfield to the list. */
	SubfieldIt subfieldIt = m_subfieldList.insert(nextSubfieldIt,
		Subfield(subfieldId, subfieldData));
	return subfieldIt;
}

/*
 * Remove subfield from the field.
 */
void MarcRecord::Field::removeSubfield(SubfieldIt subfieldIt)
{
	/* Remove subfield from the list. */
	m_subfieldList.erase(subfieldIt);
}
<|endoftext|>


<commit_before>/* -------------------------------------------------------------------------- *
 *                           OpenSim:  Logger.cpp                             *
 * -------------------------------------------------------------------------- *
 * The OpenSim API is a toolkit for musculoskeletal modeling and simulation.  *
 * See http://opensim.stanford.edu and the NOTICE file for more information.  *
 * OpenSim is developed at Stanford University and supported by the US        *
 * National Institutes of Health (U54 GM072970, R24 HD065690) and by DARPA    *
 * through the Warrior Web program.                                           *
 *                                                                            *
 * Copyright (c) 2005-2019 Stanford University and the Authors                *
 *                                                                            *
 * 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 "Logger.h"

#include "Exception.h"
#include "IO.h"
#include "LogSink.h"

#include "spdlog/sinks/stdout_color_sinks.h"

using namespace OpenSim;

// cout logger will be initialized during static initialization time
static std::shared_ptr<spdlog::logger> cout_logger = []() {
    std::shared_ptr<spdlog::logger> logger = spdlog::stdout_color_mt("cout");
    logger->set_level(spdlog::level::info);
    logger->set_pattern("%v");
    return logger;
}();

// default logger will be initialized during static initialization time
static std::shared_ptr<spdlog::logger> default_logger = []() {
    std::shared_ptr<spdlog::logger> logger = spdlog::default_logger();
    logger->set_level(spdlog::level::info);
    logger->set_pattern("[%l] %v");
    return logger;
}();

// this initialization will also happen during static initialization time
static bool other_init = []() {
    spdlog::flush_on(spdlog::level::info);
    return true;
}();

// the file log sink (e.g. `opensim.log`) is *not* necessarily initialized
// during static initialization time. It is only initialized when the first log
// message is about to be written. Users *may* disable this functionality
// before the first log message is written.
static std::shared_ptr<spdlog::sinks::basic_file_sink_mt> m_filesink = nullptr;

// if a user calls `Logger::removeFileSink` before m_filesink is initialized, a
// flag should be set to ensure that the "first use" initialization does not
// subsequently happen.
static bool filesink_auto_initialization_disabled = false;

// when filesink initialization *may* happen, ensure it only happens exactly
// once globally by wrapping it in a function-local static.
static bool _maybeInitFileLogging() {
#ifdef OPENSIM_DISABLE_LOG_FILE
// software builders may want to statically ensure that automatic file logging
// *cannot* happen - even during static initialization. This compiler define
// outright disables the behavior, which is important in Windows applications
// that run multiple instances of OpenSim-linked binaries. There, the logs may
// collide and cause a "multiple processes cannot open the same file" error).
return true;
#else
    static bool initialized = []() {
        if (filesink_auto_initialization_disabled) {
            return true;
        }
        Logger::addFileSink();
        return true;
    }();

    return initialized;
#endif
}

// this function is only called when the caller is about to log something, so
// it should perform lazy initialization of the file sink
spdlog::logger& Logger::getCoutLogger() {
    _maybeInitFileLogging();
    return *cout_logger;
}

// this function is only called when the caller is about to log something, so
// it should perform lazy initialization of the file sink
spdlog::logger& Logger::getDefaultLogger() {
    _maybeInitFileLogging();
    return *default_logger;
}

static void addSinkInternal(std::shared_ptr<spdlog::sinks::sink> sink) {
    cout_logger->sinks().push_back(sink);
    default_logger->sinks().push_back(sink);
}

static void removeSinkInternal(const std::shared_ptr<spdlog::sinks::sink> sink)
{
    {
        auto& sinks = default_logger->sinks();
        auto new_end = std::remove(sinks.begin(), sinks.end(), sink);
        sinks.erase(new_end, sinks.end());
    }
    {
        auto& sinks = cout_logger->sinks();
        auto new_end = std::remove(sinks.begin(), sinks.end(), sink);
        sinks.erase(new_end, sinks.end());
    }
}

void Logger::setLevel(Level level) {
    switch (level) {
    case Level::Off:
        spdlog::set_level(spdlog::level::off);
        break;
    case Level::Critical:
        spdlog::set_level(spdlog::level::critical);
        break;
    case Level::Error:
        spdlog::set_level(spdlog::level::err);
        break;
    case Level::Warn:
        spdlog::set_level(spdlog::level::warn);
        break;
    case Level::Info:
        spdlog::set_level(spdlog::level::info);
        break;
    case Level::Debug:
        spdlog::set_level(spdlog::level::debug);
        break;
    case Level::Trace:
        spdlog::set_level(spdlog::level::trace);
        break;
    default:
        OPENSIM_THROW(Exception, "Internal error.");
    }
    Logger::info("Set log level to {}.", getLevelString());
}

Logger::Level Logger::getLevel() {
    switch (default_logger->level()) {
    case spdlog::level::off: return Level::Off;
    case spdlog::level::critical: return Level::Critical;
    case spdlog::level::err: return Level::Error;
    case spdlog::level::warn: return Level::Warn;
    case spdlog::level::info: return Level::Info;
    case spdlog::level::debug: return Level::Debug;
    case spdlog::level::trace: return Level::Trace;
    default:
        OPENSIM_THROW(Exception, "Internal error.");
    }
}

void Logger::setLevelString(std::string str) {
    Level level;
    str = IO::Lowercase(str);
    if (str == "off") level = Level::Off;
    else if (str == "critical") level = Level::Critical;
    else if (str == "error") level = Level::Error;
    else if (str == "warn") level = Level::Warn;
    else if (str == "info") level = Level::Info;
    else if (str == "debug") level = Level::Debug;
    else if (str == "trace") level = Level::Trace;
    else {
        OPENSIM_THROW(Exception,
                "Expected log level to be Off, Critical, Error, "
                "Warn, Info, Debug, or Trace; got {}.",
                str);
    }
    setLevel(level);
}

std::string Logger::getLevelString() {
    const auto level = getLevel();
    switch (level) {
    case Level::Off: return "Off";
    case Level::Critical: return "Critical";
    case Level::Error: return "Error";
    case Level::Warn: return "Warn";
    case Level::Info: return "Info";
    case Level::Debug: return "Debug";
    case Level::Trace: return "Trace";
    default:
        OPENSIM_THROW(Exception, "Internal error.");
    }
}

bool Logger::shouldLog(Level level) {
    spdlog::level::level_enum spdlogLevel;
    switch (level) {
    case Level::Off: spdlogLevel = spdlog::level::off; break;
    case Level::Critical: spdlogLevel = spdlog::level::critical; break;
    case Level::Error: spdlogLevel = spdlog::level::err; break;
    case Level::Warn: spdlogLevel = spdlog::level::warn; break;
    case Level::Info: spdlogLevel = spdlog::level::info; break;
    case Level::Debug: spdlogLevel = spdlog::level::debug; break;
    case Level::Trace: spdlogLevel = spdlog::level::trace; break;
    default:
        OPENSIM_THROW(Exception, "Internal error.");
    }
    return default_logger->should_log(spdlogLevel);
}

void Logger::addFileSink(const std::string& filepath) {
    if (m_filesink) {
        default_logger->warn("Already logging to file '{}'; log file not added. Call "
             "removeFileSink() first.", m_filesink->filename());
        return;
    }

    // check if file can be opened at the specified path if not return meaningful
    // warning rather than bubble the exception up.
    try {
        m_filesink =
                std::make_shared<spdlog::sinks::basic_file_sink_mt>(filepath);
    }
    catch (...) {
        default_logger->warn("Can't open file '{}' for writing. Log file will not be created. "
             "Check that you have write permissions to the specified path.",
                filepath);
        return;
    }
    addSinkInternal(m_filesink);
}

void Logger::removeFileSink() {
    if (m_filesink == nullptr) {
        // the user called `removeFileSink` before any messages passed through
        // the logger (which would initialize it) and before calling
        // `addFileSink` themselves (which would also initialize it), so they
        // *probably* want to completely disable automatic initialization.
        filesink_auto_initialization_disabled = true;
        return;
    }

    removeSinkInternal(
            std::static_pointer_cast<spdlog::sinks::sink>(m_filesink));
    m_filesink.reset();
}

void Logger::addSink(const std::shared_ptr<LogSink> sink) {
    addSinkInternal(std::static_pointer_cast<spdlog::sinks::sink>(sink));
}

void Logger::removeSink(const std::shared_ptr<LogSink> sink) {
    removeSinkInternal(std::static_pointer_cast<spdlog::sinks::sink>(sink));
}

<commit_msg>Renamed _maybeInitFileLogging to initFileLoggingAsNeeded<commit_after>/* -------------------------------------------------------------------------- *
 *                           OpenSim:  Logger.cpp                             *
 * -------------------------------------------------------------------------- *
 * The OpenSim API is a toolkit for musculoskeletal modeling and simulation.  *
 * See http://opensim.stanford.edu and the NOTICE file for more information.  *
 * OpenSim is developed at Stanford University and supported by the US        *
 * National Institutes of Health (U54 GM072970, R24 HD065690) and by DARPA    *
 * through the Warrior Web program.                                           *
 *                                                                            *
 * Copyright (c) 2005-2019 Stanford University and the Authors                *
 *                                                                            *
 * 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 "Logger.h"

#include "Exception.h"
#include "IO.h"
#include "LogSink.h"

#include "spdlog/sinks/stdout_color_sinks.h"

using namespace OpenSim;

// cout logger will be initialized during static initialization time
static std::shared_ptr<spdlog::logger> cout_logger = []() {
    std::shared_ptr<spdlog::logger> logger = spdlog::stdout_color_mt("cout");
    logger->set_level(spdlog::level::info);
    logger->set_pattern("%v");
    return logger;
}();

// default logger will be initialized during static initialization time
static std::shared_ptr<spdlog::logger> default_logger = []() {
    std::shared_ptr<spdlog::logger> logger = spdlog::default_logger();
    logger->set_level(spdlog::level::info);
    logger->set_pattern("[%l] %v");
    return logger;
}();

// this initialization will also happen during static initialization time
static bool other_init = []() {
    spdlog::flush_on(spdlog::level::info);
    return true;
}();

// the file log sink (e.g. `opensim.log`) is *not* necessarily initialized
// during static initialization time. It is only initialized when the first log
// message is about to be written. Users *may* disable this functionality
// before the first log message is written.
static std::shared_ptr<spdlog::sinks::basic_file_sink_mt> m_filesink = nullptr;

// if a user calls `Logger::removeFileSink` before m_filesink is initialized, a
// flag should be set to ensure that the "first use" initialization does not
// subsequently happen.
static bool filesink_auto_initialization_disabled = false;

// when filesink initialization *may* happen, ensure it only happens exactly
// once globally by wrapping it in a function-local static.
static bool initFileLoggingAsNeeded() {
#ifdef OPENSIM_DISABLE_LOG_FILE
// software builders may want to statically ensure that automatic file logging
// *cannot* happen - even during static initialization. This compiler define
// outright disables the behavior, which is important in Windows applications
// that run multiple instances of OpenSim-linked binaries. There, the logs may
// collide and cause a "multiple processes cannot open the same file" error).
return true;
#else
    static bool initialized = []() {
        if (filesink_auto_initialization_disabled) {
            return true;
        }
        Logger::addFileSink();
        return true;
    }();

    return initialized;
#endif
}

// this function is only called when the caller is about to log something, so
// it should perform lazy initialization of the file sink
spdlog::logger& Logger::getCoutLogger() {
    initFileLoggingAsNeeded();
    return *cout_logger;
}

// this function is only called when the caller is about to log something, so
// it should perform lazy initialization of the file sink
spdlog::logger& Logger::getDefaultLogger() {
    initFileLoggingAsNeeded();
    return *default_logger;
}

static void addSinkInternal(std::shared_ptr<spdlog::sinks::sink> sink) {
    cout_logger->sinks().push_back(sink);
    default_logger->sinks().push_back(sink);
}

static void removeSinkInternal(const std::shared_ptr<spdlog::sinks::sink> sink)
{
    {
        auto& sinks = default_logger->sinks();
        auto new_end = std::remove(sinks.begin(), sinks.end(), sink);
        sinks.erase(new_end, sinks.end());
    }
    {
        auto& sinks = cout_logger->sinks();
        auto new_end = std::remove(sinks.begin(), sinks.end(), sink);
        sinks.erase(new_end, sinks.end());
    }
}

void Logger::setLevel(Level level) {
    switch (level) {
    case Level::Off:
        spdlog::set_level(spdlog::level::off);
        break;
    case Level::Critical:
        spdlog::set_level(spdlog::level::critical);
        break;
    case Level::Error:
        spdlog::set_level(spdlog::level::err);
        break;
    case Level::Warn:
        spdlog::set_level(spdlog::level::warn);
        break;
    case Level::Info:
        spdlog::set_level(spdlog::level::info);
        break;
    case Level::Debug:
        spdlog::set_level(spdlog::level::debug);
        break;
    case Level::Trace:
        spdlog::set_level(spdlog::level::trace);
        break;
    default:
        OPENSIM_THROW(Exception, "Internal error.");
    }
    Logger::info("Set log level to {}.", getLevelString());
}

Logger::Level Logger::getLevel() {
    switch (default_logger->level()) {
    case spdlog::level::off: return Level::Off;
    case spdlog::level::critical: return Level::Critical;
    case spdlog::level::err: return Level::Error;
    case spdlog::level::warn: return Level::Warn;
    case spdlog::level::info: return Level::Info;
    case spdlog::level::debug: return Level::Debug;
    case spdlog::level::trace: return Level::Trace;
    default:
        OPENSIM_THROW(Exception, "Internal error.");
    }
}

void Logger::setLevelString(std::string str) {
    Level level;
    str = IO::Lowercase(str);
    if (str == "off") level = Level::Off;
    else if (str == "critical") level = Level::Critical;
    else if (str == "error") level = Level::Error;
    else if (str == "warn") level = Level::Warn;
    else if (str == "info") level = Level::Info;
    else if (str == "debug") level = Level::Debug;
    else if (str == "trace") level = Level::Trace;
    else {
        OPENSIM_THROW(Exception,
                "Expected log level to be Off, Critical, Error, "
                "Warn, Info, Debug, or Trace; got {}.",
                str);
    }
    setLevel(level);
}

std::string Logger::getLevelString() {
    const auto level = getLevel();
    switch (level) {
    case Level::Off: return "Off";
    case Level::Critical: return "Critical";
    case Level::Error: return "Error";
    case Level::Warn: return "Warn";
    case Level::Info: return "Info";
    case Level::Debug: return "Debug";
    case Level::Trace: return "Trace";
    default:
        OPENSIM_THROW(Exception, "Internal error.");
    }
}

bool Logger::shouldLog(Level level) {
    spdlog::level::level_enum spdlogLevel;
    switch (level) {
    case Level::Off: spdlogLevel = spdlog::level::off; break;
    case Level::Critical: spdlogLevel = spdlog::level::critical; break;
    case Level::Error: spdlogLevel = spdlog::level::err; break;
    case Level::Warn: spdlogLevel = spdlog::level::warn; break;
    case Level::Info: spdlogLevel = spdlog::level::info; break;
    case Level::Debug: spdlogLevel = spdlog::level::debug; break;
    case Level::Trace: spdlogLevel = spdlog::level::trace; break;
    default:
        OPENSIM_THROW(Exception, "Internal error.");
    }
    return default_logger->should_log(spdlogLevel);
}

void Logger::addFileSink(const std::string& filepath) {
    if (m_filesink) {
        default_logger->warn("Already logging to file '{}'; log file not added. Call "
             "removeFileSink() first.", m_filesink->filename());
        return;
    }

    // check if file can be opened at the specified path if not return meaningful
    // warning rather than bubble the exception up.
    try {
        m_filesink =
                std::make_shared<spdlog::sinks::basic_file_sink_mt>(filepath);
    }
    catch (...) {
        default_logger->warn("Can't open file '{}' for writing. Log file will not be created. "
             "Check that you have write permissions to the specified path.",
                filepath);
        return;
    }
    addSinkInternal(m_filesink);
}

void Logger::removeFileSink() {
    if (m_filesink == nullptr) {
        // the user called `removeFileSink` before any messages passed through
        // the logger (which would initialize it) and before calling
        // `addFileSink` themselves (which would also initialize it), so they
        // *probably* want to completely disable automatic initialization.
        filesink_auto_initialization_disabled = true;
        return;
    }

    removeSinkInternal(
            std::static_pointer_cast<spdlog::sinks::sink>(m_filesink));
    m_filesink.reset();
}

void Logger::addSink(const std::shared_ptr<LogSink> sink) {
    addSinkInternal(std::static_pointer_cast<spdlog::sinks::sink>(sink));
}

void Logger::removeSink(const std::shared_ptr<LogSink> sink) {
    removeSinkInternal(std::static_pointer_cast<spdlog::sinks::sink>(sink));
}

<|endoftext|>


<commit_before>/*
 * File:   imc.cc
 * Author: ruehle
 *
 * Created on March 10, 2009, 3:43 PM
 */

#include <iostream>
#include "beadlist.h"
#include "nblist.h"
#include "imc.h"

void Imc::BeginCG(Topology *top, Topology *top_atom) {
    cout << "begin to calculate inverse monte carlo parameters\n";
    cout << "bonded interactions: " << _bonded.size() << endl;
    cout << "non-bonded interactions: " << _nonbonded.size() << endl;

   _nframes = 0;

   for (list<Property*>::iterator iter = _nonbonded.begin();
            iter != _nonbonded.end(); ++iter) {
        string name = (*iter)->get("name").value();

        _interactions[name] = new interaction_t;
        // \todo check weather exists
        interaction_t &i=*_interactions[name];

        i._step = (*iter)->get("step").as<double>();
        i._min = (*iter)->get("min").as<double>();
        i._max = (*iter)->get("max").as<double>();

        int n = (i._max - i._min)/i._step;

       i._current.Initialize(i._min, i._max, n);
       i._average.Initialize(i._min, i._max, n);
    }
};

void Imc::EndCG()
{
    map<string, interaction_t *>::iterator iter;
    for(iter=_interactions.begin(); iter!=_interactions.end(); ++iter) {
        cout << (iter->first) << endl;
        cout << iter->second->_average;
        delete iter->second;
    }
    _interactions.clear();
}

void Imc::LoadOptions(const string &file) {
    load_property_from_xml(_options, file);
    _bonded = _options.Select("cg.bonded");
    _nonbonded = _options.Select("cg.non-bonded");

}

void Imc::EvalConfiguration(Topology *top, Topology *top_atom) {
    _nframes++;
    DoNonbonded(top);
}

void Imc::DoNonbonded(Topology *top)
{
    for (list<Property*>::iterator iter = _nonbonded.begin();
            iter != _nonbonded.end(); ++iter) {
        string name = (*iter)->get("name").value();

        interaction_t &i = *_interactions[name];

        BeadList beads1, beads2;

        beads1.Generate(*top, (*iter)->get("type1").value());
        beads2.Generate(*top, (*iter)->get("type2").value());

        NBList nb;
        nb.setCutoff(i._max);

        if((*iter)->get("type1").value() == (*iter)->get("type2").value())
            nb.Generate(beads1);
        else
            nb.Generate(beads1, beads2);

        i._current.Clear();
        NBList::iterator pair_iter;

        for(pair_iter = nb.begin(); pair_iter!=nb.end();++pair_iter) {
                i._current.Process((*pair_iter)->dist());
        }
        i._average.data().y() += i._current.data().y();
    }
}<commit_msg>minor change<commit_after>/*
 * File:   imc.cc
 * Author: ruehle
 *
 * Created on March 10, 2009, 3:43 PM
 */

#include <iostream>
#include "beadlist.h"
#include "nblist.h"
#include "imc.h"

void Imc::BeginCG(Topology *top, Topology *top_atom) {
    cout << "begin to calculate inverse monte carlo parameters\n";
    cout << "# of bonded interactions: " << _bonded.size() << endl;
    cout << "# of non-bonded interactions: " << _nonbonded.size() << endl;

   _nframes = 0;

   // initialize non-bonded structures
   for (list<Property*>::iterator iter = _nonbonded.begin();
            iter != _nonbonded.end(); ++iter)
        AddInteraction(*iter);
};

interaction *Imc::AddInteraction(Property *p)
{
    string name = p->get("name").value();
    interaction_t *i = new interaction_t;

    _interactions[name] = i;
    // \todo check weather exists

    i->_step = p->get("step").as<double>();
    i->_min = p->get("min").as<double>();
    i->_max = p->get("max").as<double>();

    int n = (i->_max - i->_min) / i->_step;

    i->_current.Initialize(i->_min, i->_max, n);
    i->_average.Initialize(i->_min, i->_max, n);

    return *i;
}

void Imc::EndCG()
{
    map<string, interaction_t *>::iterator iter;
    for(iter=_interactions.begin(); iter!=_interactions.end(); ++iter) {
        cout << (iter->first) << endl;
        cout << iter->second->_average;
        delete iter->second;
    }
    _interactions.clear();
}

void Imc::LoadOptions(const string &file) {
    load_property_from_xml(_options, file);
    _bonded = _options.Select("cg.bonded");
    _nonbonded = _options.Select("cg.non-bonded");

}

void Imc::EvalConfiguration(Topology *top, Topology *top_atom) {
    _nframes++;
    DoNonbonded(top);
}

void Imc::DoNonbonded(Topology *top)
{
    for (list<Property*>::iterator iter = _nonbonded.begin();
            iter != _nonbonded.end(); ++iter) {
        string name = (*iter)->get("name").value();

        interaction_t &i = *_interactions[name];

        BeadList beads1, beads2;

        beads1.Generate(*top, (*iter)->get("type1").value());
        beads2.Generate(*top, (*iter)->get("type2").value());

        NBList nb;
        nb.setCutoff(i._max);

        if((*iter)->get("type1").value() == (*iter)->get("type2").value())
            nb.Generate(beads1);
        else
            nb.Generate(beads1, beads2);

        i._current.Clear();
        NBList::iterator pair_iter;

        for(pair_iter = nb.begin(); pair_iter!=nb.end();++pair_iter) {
                i._current.Process((*pair_iter)->dist());
        }
        i._average.data().y() += i._current.data().y();
    }
}<|endoftext|>


<commit_before>// $Id$

/*
Copyright (c) 2007-2010, Trustees of The Leland Stanford Junior University
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
Neither the name of the Stanford University nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/*network.cpp
 *
 *This class is the basis of the entire network, it contains, all the routers
 *channels in the network, and is extended by all the network topologies
 *
 */

#include <cassert>
#include <sstream>

#include "booksim.hpp"
#include "network.hpp"

Network::Network( const Configuration &config, const string & name ) :
  Module( 0, name )
{
  _size     = -1;
  _sources  = -1;
  _dests    = -1;
  _channels = -1;
}

Network::~Network( )
{
  for ( int r = 0; r < _size; ++r ) {
    if ( _routers[r] ) delete _routers[r];
  }
  for ( int s = 0; s < _sources; ++s ) {
    if ( _inject[s] ) delete _inject[s];
    if ( _inject_cred[s] ) delete _inject_cred[s];
  }
  for ( int d = 0; d < _dests; ++d ) {
    if ( _eject[d] ) delete _eject[d];
    if ( _eject_cred[d] ) delete _eject_cred[d];
  }
  for ( int c = 0; c < _channels; ++c ) {
    if ( _chan[c] ) delete _chan[c];
    if ( _chan_cred[c] ) delete _chan_cred[c];
  }
}

void Network::_Alloc( )
{
  assert( ( _size != -1 ) &&
	  ( _sources != -1 ) &&
	  ( _dests != -1 ) &&
	  ( _channels != -1 ) );

  _routers.resize(_size);
  gNodes = _sources;

  /*booksim used arrays of flits as the channels which makes have capacity of
   *one. To simulate channel latency, flitchannel class has been added
   *which are fifos with depth = channel latency and each cycle the channel
   *shifts by one
   *credit channels are the necessary counter part
   */
  _inject.resize(_sources);
  _inject_cred.resize(_sources);
  for ( int s = 0; s < _sources; ++s ) {
    ostringstream name;
    name.str(_name + "_fchan_ingress");
    name << s;
    _inject[s] = new FlitChannel(this, name.str());
    name.str(_name + "_cchan_ingress");
    name << s;
    _inject_cred[s] = new CreditChannel(this, name.str());
  }
  _eject.resize(_dests);
  _eject_cred.resize(_dests);
  for ( int d = 0; d < _dests; ++d ) {
    ostringstream name;
    name.str(_name + "_fchan_egress");
    name << d;
    _eject[d] = new FlitChannel(this, name.str());
    name.str(_name + "_cchan_egress");
    name << d;
    _eject_cred[d] = new CreditChannel(this, name.str());
  }
  _chan.resize(_channels);
  _chan_cred.resize(_channels);
  for ( int c = 0; c < _channels; ++c ) {
    ostringstream name;
    name.str(_name + "_fchan_");
    name << c;
    _chan[c] = new FlitChannel(this, name.str());
    name.str(_name + "_cchan_");
    name << c;
    _chan_cred[c] = new CreditChannel(this, name.str());
  }
}

int Network::NumSources( ) const
{
  return _sources;
}

int Network::NumDests( ) const
{
  return _dests;
}

void Network::ReadInputs( )
{
  for ( int r = 0; r < _size; ++r ) {
    _routers[r]->ReadInputs( );
  }
}

void Network::Evaluate( )
{
  for ( int r = 0; r < _size; ++r ) {
    _routers[r]->Evaluate( );
  }
}

void Network::WriteOutputs( )
{
  for ( int r = 0; r < _size; ++r ) {
    _routers[r]->WriteOutputs( );
  }
}

void Network::WriteFlit( Flit *f, int source )
{
  assert( ( source >= 0 ) && ( source < _sources ) );
  _inject[source]->Send(f);
}

Flit *Network::ReadFlit( int dest )
{
  assert( ( dest >= 0 ) && ( dest < _dests ) );
  return _eject[dest]->Receive();
}

/* new functions added for NOC
 */
Flit* Network::PeekFlit( int dest )
{
  assert( ( dest >= 0 ) && ( dest < _dests ) );
  return _eject[dest]->Peek( );
}

void Network::WriteCredit( Credit *c, int dest )
{
  assert( ( dest >= 0 ) && ( dest < _dests ) );
  _eject_cred[dest]->Send(c);
}

Credit *Network::ReadCredit( int source )
{
  assert( ( source >= 0 ) && ( source < _sources ) );
  return _inject_cred[source]->Receive();
}

/* new functions added for NOC
 */
Credit *Network::PeekCredit( int source )
{
  assert( ( source >= 0 ) && ( source < _sources ) );
  return _inject_cred[source]->Peek( );
}

void Network::InsertRandomFaults( const Configuration &config )
{
  Error( "InsertRandomFaults not implemented for this topology!" );
}

void Network::OutChannelFault( int r, int c, bool fault )
{
  assert( ( r >= 0 ) && ( r < _size ) );
  _routers[r]->OutChannelFault( c, fault );
}

double Network::Capacity( ) const
{
  return 1.0;
}

/* this function can be heavily modified to display any information
 * neceesary of the network, by default, call display on each router
 * and display the channel utilization rate
 */
void Network::Display( ) const
{
  for ( int r = 0; r < _size; ++r ) {
    _routers[r]->Display( );
  }
}
<commit_msg>fix channel names<commit_after>// $Id$

/*
Copyright (c) 2007-2010, Trustees of The Leland Stanford Junior University
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
Neither the name of the Stanford University nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/*network.cpp
 *
 *This class is the basis of the entire network, it contains, all the routers
 *channels in the network, and is extended by all the network topologies
 *
 */

#include <cassert>
#include <sstream>

#include "booksim.hpp"
#include "network.hpp"

Network::Network( const Configuration &config, const string & name ) :
  Module( 0, name )
{
  _size     = -1;
  _sources  = -1;
  _dests    = -1;
  _channels = -1;
}

Network::~Network( )
{
  for ( int r = 0; r < _size; ++r ) {
    if ( _routers[r] ) delete _routers[r];
  }
  for ( int s = 0; s < _sources; ++s ) {
    if ( _inject[s] ) delete _inject[s];
    if ( _inject_cred[s] ) delete _inject_cred[s];
  }
  for ( int d = 0; d < _dests; ++d ) {
    if ( _eject[d] ) delete _eject[d];
    if ( _eject_cred[d] ) delete _eject_cred[d];
  }
  for ( int c = 0; c < _channels; ++c ) {
    if ( _chan[c] ) delete _chan[c];
    if ( _chan_cred[c] ) delete _chan_cred[c];
  }
}

void Network::_Alloc( )
{
  assert( ( _size != -1 ) &&
	  ( _sources != -1 ) &&
	  ( _dests != -1 ) &&
	  ( _channels != -1 ) );

  _routers.resize(_size);
  gNodes = _sources;

  /*booksim used arrays of flits as the channels which makes have capacity of
   *one. To simulate channel latency, flitchannel class has been added
   *which are fifos with depth = channel latency and each cycle the channel
   *shifts by one
   *credit channels are the necessary counter part
   */
  _inject.resize(_sources);
  _inject_cred.resize(_sources);
  for ( int s = 0; s < _sources; ++s ) {
    ostringstream name;
    name << _name << "_fchan_ingress" << s;
    _inject[s] = new FlitChannel(this, name.str());
    name.str("");
    name << _name << "_cchan_ingress" << s;
    _inject_cred[s] = new CreditChannel(this, name.str());
  }
  _eject.resize(_dests);
  _eject_cred.resize(_dests);
  for ( int d = 0; d < _dests; ++d ) {
    ostringstream name;
    name << _name << "_fchan_egress" << d;
    _eject[d] = new FlitChannel(this, name.str());
    name.str("");
    name << _name << "_cchan_egress" << d;
    _eject_cred[d] = new CreditChannel(this, name.str());
  }
  _chan.resize(_channels);
  _chan_cred.resize(_channels);
  for ( int c = 0; c < _channels; ++c ) {
    ostringstream name;
    name << _name << "_fchan_" << c;
    _chan[c] = new FlitChannel(this, name.str());
    name.str("");
    name << _name << "_cchan_" << c;
    _chan_cred[c] = new CreditChannel(this, name.str());
  }
}

int Network::NumSources( ) const
{
  return _sources;
}

int Network::NumDests( ) const
{
  return _dests;
}

void Network::ReadInputs( )
{
  for ( int r = 0; r < _size; ++r ) {
    _routers[r]->ReadInputs( );
  }
}

void Network::Evaluate( )
{
  for ( int r = 0; r < _size; ++r ) {
    _routers[r]->Evaluate( );
  }
}

void Network::WriteOutputs( )
{
  for ( int r = 0; r < _size; ++r ) {
    _routers[r]->WriteOutputs( );
  }
}

void Network::WriteFlit( Flit *f, int source )
{
  assert( ( source >= 0 ) && ( source < _sources ) );
  _inject[source]->Send(f);
}

Flit *Network::ReadFlit( int dest )
{
  assert( ( dest >= 0 ) && ( dest < _dests ) );
  return _eject[dest]->Receive();
}

/* new functions added for NOC
 */
Flit* Network::PeekFlit( int dest )
{
  assert( ( dest >= 0 ) && ( dest < _dests ) );
  return _eject[dest]->Peek( );
}

void Network::WriteCredit( Credit *c, int dest )
{
  assert( ( dest >= 0 ) && ( dest < _dests ) );
  _eject_cred[dest]->Send(c);
}

Credit *Network::ReadCredit( int source )
{
  assert( ( source >= 0 ) && ( source < _sources ) );
  return _inject_cred[source]->Receive();
}

/* new functions added for NOC
 */
Credit *Network::PeekCredit( int source )
{
  assert( ( source >= 0 ) && ( source < _sources ) );
  return _inject_cred[source]->Peek( );
}

void Network::InsertRandomFaults( const Configuration &config )
{
  Error( "InsertRandomFaults not implemented for this topology!" );
}

void Network::OutChannelFault( int r, int c, bool fault )
{
  assert( ( r >= 0 ) && ( r < _size ) );
  _routers[r]->OutChannelFault( c, fault );
}

double Network::Capacity( ) const
{
  return 1.0;
}

/* this function can be heavily modified to display any information
 * neceesary of the network, by default, call display on each router
 * and display the channel utilization rate
 */
void Network::Display( ) const
{
  for ( int r = 0; r < _size; ++r ) {
    _routers[r]->Display( );
  }
}
<|endoftext|>


<commit_before>/*
 * This is part of the FL library, a C++ Bayesian filtering library
 * (https://github.com/filtering-library)
 *
 * Copyright (c) 2014 Jan Issac (jan.issac@gmail.com)
 * Copyright (c) 2014 Manuel Wuthrich (manuel.wuthrich@gmail.com)
 *
 * Max-Planck Institute for Intelligent Systems, AMD Lab
 * University of Southern California, CLMC Lab
 *
 * This Source Code Form is subject to the terms of the MIT License (MIT).
 * A copy of the license can be found in the LICENSE file distributed with this
 * source code.
 */

/**
 * \file gaussian_filter_kf_test.cpp
 * \date Febuary 2015
 * \author Jan Issac (jan.issac@gmail.com)
 */

#include <gtest/gtest.h>
#include "../typecast.hpp"

#include <Eigen/Dense>

#include "gaussian_filter_test_suite.hpp"

#include <fl/filter/gaussian/gaussian_filter_linear.hpp>

template <int StateDimension, int InputDimension, int ObsrvDimension>
struct KalmanFilterTestConfiguration
{
    enum: signed int
    {
        StateDim = StateDimension,
        InputDim = InputDimension,
        ObsrvDim = ObsrvDimension
    };

    template <typename ModelFactory>
    struct FilterDefinition
    {
        typedef fl::GaussianFilter<
                    typename ModelFactory::LinearStateTransition,
                    typename ModelFactory::LinearObservation
                > Type;
    };

    template <typename ModelFactory>
    static typename FilterDefinition<ModelFactory>::Type
    create_filter(ModelFactory&& factory)
    {
        return typename FilterDefinition<ModelFactory>::Type(
            factory.create_linear_state_model(),
            factory.create_observation_model());
    }
};

typedef ::testing::Types<
            fl::StaticTest<KalmanFilterTestConfiguration<3, 1, 2>>,
            fl::StaticTest<KalmanFilterTestConfiguration<3, 3, 10>>,
            fl::StaticTest<KalmanFilterTestConfiguration<10, 10, 20>>,

            fl::DynamicTest<KalmanFilterTestConfiguration<3, 1, 2>>,
            fl::DynamicTest<KalmanFilterTestConfiguration<3, 3, 10>>,
            fl::DynamicTest<KalmanFilterTestConfiguration<10, 10, 20>>
        > TestTypes;

INSTANTIATE_TYPED_TEST_CASE_P(KalmanFilterTest,
                              GaussianFilterTest,
                              TestTypes);
<commit_msg>Added FilterIterations argument<commit_after>/*
 * This is part of the FL library, a C++ Bayesian filtering library
 * (https://github.com/filtering-library)
 *
 * Copyright (c) 2014 Jan Issac (jan.issac@gmail.com)
 * Copyright (c) 2014 Manuel Wuthrich (manuel.wuthrich@gmail.com)
 *
 * Max-Planck Institute for Intelligent Systems, AMD Lab
 * University of Southern California, CLMC Lab
 *
 * This Source Code Form is subject to the terms of the MIT License (MIT).
 * A copy of the license can be found in the LICENSE file distributed with this
 * source code.
 */

/**
 * \file gaussian_filter_kf_test.cpp
 * \date Febuary 2015
 * \author Jan Issac (jan.issac@gmail.com)
 */

#include <gtest/gtest.h>
#include "../typecast.hpp"

#include <Eigen/Dense>

#include "gaussian_filter_test_suite.hpp"

#include <fl/filter/gaussian/gaussian_filter_linear.hpp>

template <
    int StateDimension,
    int InputDimension,
    int ObsrvDimension,
    int FilterIterations = 100
>
struct KalmanFilterTestConfiguration
{
    enum: signed int
    {
        StateDim = StateDimension,
        InputDim = InputDimension,
        ObsrvDim = ObsrvDimension,
        Iterations = FilterIterations
    };

    template <typename ModelFactory>
    struct FilterDefinition
    {
        typedef fl::GaussianFilter<
                    typename ModelFactory::LinearStateTransition,
                    typename ModelFactory::LinearObservation
                > Type;
    };

    template <typename ModelFactory>
    static typename FilterDefinition<ModelFactory>::Type
    create_filter(ModelFactory&& factory)
    {
        return typename FilterDefinition<ModelFactory>::Type(
            factory.create_linear_state_model(),
            factory.create_observation_model());
    }
};

typedef ::testing::Types<
            fl::StaticTest<KalmanFilterTestConfiguration<3, 1, 2>>,
            fl::StaticTest<KalmanFilterTestConfiguration<3, 3, 10>>,
            fl::StaticTest<KalmanFilterTestConfiguration<10, 10, 20>>,

            fl::DynamicTest<KalmanFilterTestConfiguration<3, 1, 2>>,
            fl::DynamicTest<KalmanFilterTestConfiguration<3, 3, 10>>,
            fl::DynamicTest<KalmanFilterTestConfiguration<10, 10, 20>>
        > TestTypes;

INSTANTIATE_TYPED_TEST_CASE_P(KalmanFilterTest,
                              GaussianFilterTest,
                              TestTypes);
<|endoftext|>


<commit_before>//#hdu 4018
#include <string>
#include <iostream>
#include <stdio.h>
int main(int argc, char const *argv[])
{
	char ch;

	while((ch=getchar())!=EOF){

		if(ch==':') break;
	}
	getchar();getchar();

	while((ch=getchar())!=EOF){

		if(ch==':') break;
		if(ch=='/') break;
		putchar(ch);
	}
	putchar('\n');
	while((ch=getchar())!=EOF)if(ch=='\n') break;

	return 0;
}<commit_msg>update uoj10571<commit_after>//#hdu 4018
#include <string>
#include <iostream>
#include <stdio.h>
int main(int argc, char const *argv[])
{
	char ch;
	while(1){
	while((ch=getchar())!=EOF){

		if(ch==':') break;
	}
	getchar();getchar();

	while((ch=getchar())!=EOF){

		if(ch==':') break;
		if(ch=='/') break;
		putchar(ch);
	}
	putchar('\n');
	while((ch=getchar())!=EOF)if(ch=='\n') break;
}
	return 0;
}<|endoftext|>