<commit_before>/**************************************************************************
** This file is part of LiteIDE
**
** Copyright (c) 2011-2013 LiteIDE Team. All rights reserved.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License as published by the Free Software Foundation; either
** version 2.1 of the License, or (at your option) any later version.
**
** This library 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
** Lesser General Public License for more details.
**
** In addition, as a special exception,  that plugins developed for LiteIDE,
** are allowed to remain closed sourced and can be distributed under any license .
** These rights are included in the file LGPL_EXCEPTION.txt in this package.
**
**************************************************************************/
// Module: fileutil.cpp
// Creator: visualfc <visualfc@gmail.com>

#include "fileutil.h"
#include "liteenvapi/liteenvapi.h"
#include <QFileInfo>
#include <QDir>
#include <QProcess>
#include <QDebug>

//lite_memory_check_begin
#if defined(WIN32) && defined(_MSC_VER) &&  defined(_DEBUG)
     #define _CRTDBG_MAP_ALLOC
     #include <stdlib.h>
     #include <crtdbg.h>
     #define DEBUG_NEW new( _NORMAL_BLOCK, __FILE__, __LINE__ )
     #define new DEBUG_NEW
#endif
//lite_memory_check_end

bool FileUtil::compareFile(const QString &fileName1, const QString &fileName2, bool canonical)
{
    if (fileName1.isEmpty() || fileName2.isEmpty()) {
        return false;
    }
    if (canonical) {
        return QFileInfo(fileName1).canonicalFilePath() == QFileInfo(fileName2).canonicalFilePath();
    }
    return QFileInfo(fileName1).filePath() == QFileInfo(fileName2).filePath();
}

QStringList FileUtil::removeFiles(const QStringList &files)
{
    QStringList result;
    foreach (QString file, files) {
        if (QFile::exists(file) && QFile::remove(file)) {
            result << file;
        }
    }
    return result;
}

QStringList FileUtil::removeWorkDir(const QString &workDir, const QStringList &filters)
{
    QStringList result;
    QDir dir(workDir);
    if (!dir.exists())
        return result;

    QFileInfoList dirs = dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);

    foreach (QFileInfo d, dirs) {
        removeWorkDir(d.filePath(),filters);
    }

    QFileInfoList files = dir.entryInfoList(filters,QDir::Files);
    foreach (QFileInfo f, files) {
        bool b = QFile::remove(f.filePath());
        if (b) {
            result << f.fileName();
        }
    }
    return result;
}

QMap<QString,QStringList> FileUtil::readFileContext(QIODevice *dev)
{
    QMap<QString,QStringList> contextMap;
    QStringList list;
    QString line;
    bool bnext = false;
    while (!dev->atEnd()) {
        QByteArray ar = dev->readLine().trimmed();
        if (!ar.isEmpty() && ar.right(1) == "\\") {
            bnext = true;
            ar[ar.length()-1] = ' ';
        } else {
            bnext = false;
        }
        line.push_back(ar);
        if (!bnext && !line.isEmpty()) {
            list.push_back(line);
            line.clear();
        }
    }

    if (!line.isEmpty()) {
        list.push_back(line);
    }

    foreach (QString line, list) {
        if (line.size() >= 1 && line.at(0) == '#')
            continue;
        QStringList v = line.split(QRegExp("\\+="),QString::SkipEmptyParts);
        if (v.count() == 1) {
            v = line.split(QRegExp("="),QString::SkipEmptyParts);
            if (v.count() == 2) {
                QStringList v2 = v.at(1).split(" ",QString::SkipEmptyParts);
                if (!v2.isEmpty()) {
                    contextMap[v.at(0).trimmed()] = v2;
                }
            }
        } else if (v.count() == 2) {
            QStringList v2 = v.at(1).split(" ",QString::SkipEmptyParts);
            if (!v2.isEmpty())
                contextMap[v.at(0).trimmed()].append(v2);
        }
    }
    return contextMap;
}

#ifdef Q_OS_WIN
QString FileUtil::canExec(QString fileName, QStringList exts)
{
    QFileInfo info(fileName);
    QString suffix = info.suffix();
    if (!suffix.isEmpty()) {
        suffix = "."+suffix;
        foreach(QString ext, exts) {
            if (suffix == ext && info.exists()) {
                return info.canonicalFilePath();
            }
        }
    }
    foreach(QString ext, exts) {
        QFileInfo info(fileName+ext);
        if (info.exists()) {
            return info.filePath();
        }
    }
    return QString();
}

QString FileUtil::lookPath(const QString &file, const QProcessEnvironment &env, bool bLocalPriority)
{
    QString fileName = file;
    QStringList exts;
    QString extenv = env.value("PATHEXT");
    if (!extenv.isEmpty()) {
        foreach(QString ext, extenv.split(';',QString::SkipEmptyParts)) {
            if (ext.isEmpty()) {
                continue;
            }
            if (ext[0] != '.') {
                ext= '.'+ext;
            }
            exts.append(ext.toLower());
        }
    }

    if (fileName.contains('\\') || fileName.contains('/')) {
        QString exec = canExec(fileName,exts);
        if (!exec.isEmpty()) {
            return exec;
        }
    }
    if (bLocalPriority) {
        QString exec = canExec(".\\"+fileName,exts);
        if (!exec.isEmpty()) {
            return exec;
        }
    }
    QString pathenv = env.value("PATH");
    if (pathenv.isEmpty()) {
        QString exec = canExec(".\\"+fileName,exts);
        if (!exec.isEmpty()) {
            return exec;
        }
    } else {
        foreach(QString dir,pathenv.split(';',QString::SkipEmptyParts)) {
            QFileInfo info(QDir(dir),fileName);
            QString exec = canExec(info.filePath(),exts);
            if (!exec.isEmpty()) {
                return exec;
            }
        }
    }
    return QString();
}

QString FileUtil::lookPathInDir(const QString &file, const QString &dir)
{
    QString fileName = file;
    QStringList exts;
    QString extenv =  QProcessEnvironment::systemEnvironment().value("PATHEXT");
    if (!extenv.isEmpty()) {
        foreach(QString ext, extenv.split(';',QString::SkipEmptyParts)) {
            if (ext.isEmpty()) {
                continue;
            }
            if (ext[0] != '.') {
                ext= '.'+ext;
            }
            exts.append(ext.toLower());
        }
    }

    if (fileName.contains('\\') || fileName.contains('/')) {
        QString exec = canExec(fileName,exts);
        if (!exec.isEmpty()) {
            return exec;
        }
    }
    QFileInfo info(QDir(dir),fileName);
    QString exec = canExec(info.filePath(),exts);
    if (!exec.isEmpty()) {
        return exec;
    }
    return QString();
}

#else
QString FileUtil::canExec(QString fileName, QStringList /*exts*/)
{
    QFileInfo info(fileName);
    if (info.exists() && info.isExecutable()) {
        return info.canonicalFilePath();
    }
    return QString();
}

QString FileUtil::lookPath(const QString &file, const QProcessEnvironment &env, bool bLocalPriority)
{
    QString fileName = file;
    if (fileName.contains('/')) {
        QString exec = canExec(fileName);
        if (!exec.isEmpty()) {
            return exec;
        }
    }
    if (bLocalPriority) {
        QString exec = canExec("./"+fileName);
        if (!exec.isEmpty()) {
            return exec;
        }
    }
    QString pathenv = env.value("PATH");
    foreach(QString dir,pathenv.split(':',QString::KeepEmptyParts)) {
        if (dir == "") {
            dir = ".";
        }
        QString exec = canExec(dir+"/"+file);
        if (!exec.isEmpty()) {
            return exec;
        }
    }
    return QString();
}

QString FileUtil::lookPathInDir(const QString &file, const QString &dir)
{
    QString fileName = file;
    if (fileName.contains('/')) {
        QString exec = canExec(fileName);
        if (!exec.isEmpty()) {
            return exec;
        }
    }
    QString exec = canExec(dir+"/"+file);
    if (!exec.isEmpty()) {
        return exec;
    }
    return QString();
}

#endif

QString FileUtil::findExecute(const QString &target)
{
    QStringList targetList;
#ifdef Q_OS_WIN
    targetList << target+".exe";
#endif
    targetList << target;
    foreach (QString fileName, targetList) {
        if (QFile::exists(fileName)) {
            QFileInfo info(fileName);
            if (info.isExecutable()) {
                return info.canonicalFilePath();
            }
        }
    }
    return QString();
}

GoExecute::GoExecute(const QString &cmdPath)
{
#ifdef Q_OS_WIN
    QString goexec = "goexec.exe";
#else
    QString goexec = "goexec";
#endif
    m_goexec = QFileInfo(QDir(cmdPath),goexec).absoluteFilePath();
}

bool GoExecute::isReady()
{
    return QFile::exists(m_goexec);
}

QString GoExecute::cmd() const
{
    return m_goexec;
}

bool GoExecute::exec(const QString &workPath, const QString &target, const QStringList &args)
{
#ifdef Q_OS_WIN
    QStringList iargs;
    if (!workPath.isEmpty()) {
        iargs << "-w" << workPath;
    }
    iargs << target << args;
    return QProcess::startDetached(m_goexec,iargs);
#else
    QStringList iargs;
    iargs << "-e" << m_goexec;
    if (!workPath.isEmpty()) {
        iargs << "-w" << workPath;
    }
    iargs << target << args;
    return QProcess::startDetached("/usr/bin/xterm",iargs);
#endif
}

QString FileUtil::lookupGoBin(const QString &bin, LiteApi::IApplication *app, bool bLiteAppPriority)
{
    if (bLiteAppPriority) {
        QString find = FileUtil::findExecute(app->applicationPath()+"/"+bin);
        if (!find.isEmpty()) {
            return find;
        }
    }
    QProcessEnvironment env = LiteApi::getCurrentEnvironment(app);
#ifdef Q_OS_WIN
    QString sep = ";";
#else
    QString sep = ":";
#endif

    QString goos = env.value("GOOS");
    if (goos.isEmpty()) {
        goos = LiteApi::getDefaultGOOS();
    }
    QString goarch = env.value("GOARCH");
    QString goroot = env.value("GOROOT");
    if (goroot.isEmpty()) {
        goroot = LiteApi::getDefaultGOROOT();
    }
    QStringList pathList;
    foreach (QString path, env.value("GOPATH").split(sep,QString::SkipEmptyParts)) {
        pathList.append(QDir::toNativeSeparators(path));
    }
    foreach (QString path, app->settings()->value("liteide/gopath").toStringList()) {
        pathList.append(QDir::toNativeSeparators(path));
    }
    pathList.removeDuplicates();
    env.insert("GOPATH",pathList.join(sep));

    if (!goroot.isEmpty()) {
        pathList.prepend(goroot);
    }

    QStringList binList;
    QString gobin = env.value("GOBIN");
    if (!gobin.isEmpty()) {
        binList.append(gobin);
    }
    foreach (QString path, pathList) {
        binList.append(QFileInfo(path,"bin").filePath());
        binList.append(QFileInfo(path,"bin/"+goos+"_"+goarch).filePath());
    }
    foreach(QString path, binList) {
        QString find = FileUtil::findExecute(path+"/"+bin);
        if (!find.isEmpty()) {
            return find;
        }
    }
    return FileUtil::lookupLiteBin(bin,app);
}

QString FileUtil::lookupLiteBin(const QString &bin, LiteApi::IApplication *app)
{
    QString find = FileUtil::findExecute(app->applicationPath()+"/"+bin);
    if (find.isEmpty()) {
        find = FileUtil::lookPath(bin,LiteApi::getGoEnvironment(app),true);
    }
    return find;
}

bool FileUtil::CopyDirectory(const QString &src, const QString &dest)
{
    QDir dir(src);
    foreach(QFileInfo info, dir.entryInfoList(QDir::Files)) {
        if (info.isFile() && !info.isSymLink()) {
            QFile in(info.filePath());
            if (!in.open(QFile::ReadOnly)) {
                return false;
            }
            QFile out(dest+"/"+info.fileName());
            if (!out.open(QFile::WriteOnly)) {
                return false;
            }
            out.write(in.readAll());
        }
    }
    return true;
}

<commit_msg>Fix for case sensitive path comparison on windows<commit_after>/**************************************************************************
** This file is part of LiteIDE
**
** Copyright (c) 2011-2013 LiteIDE Team. All rights reserved.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License as published by the Free Software Foundation; either
** version 2.1 of the License, or (at your option) any later version.
**
** This library 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
** Lesser General Public License for more details.
**
** In addition, as a special exception,  that plugins developed for LiteIDE,
** are allowed to remain closed sourced and can be distributed under any license .
** These rights are included in the file LGPL_EXCEPTION.txt in this package.
**
**************************************************************************/
// Module: fileutil.cpp
// Creator: visualfc <visualfc@gmail.com>

#include "fileutil.h"
#include "liteenvapi/liteenvapi.h"
#include <QFileInfo>
#include <QDir>
#include <QProcess>
#include <QDebug>

//lite_memory_check_begin
#if defined(WIN32) && defined(_MSC_VER) &&  defined(_DEBUG)
     #define _CRTDBG_MAP_ALLOC
     #include <stdlib.h>
     #include <crtdbg.h>
     #define DEBUG_NEW new( _NORMAL_BLOCK, __FILE__, __LINE__ )
     #define new DEBUG_NEW
#endif
//lite_memory_check_end

bool FileUtil::compareFile(const QString &fileName1, const QString &fileName2, bool canonical)
{
    if (fileName1.isEmpty() || fileName2.isEmpty()) {
        return false;
    }
    if (canonical) {
#if defined(WIN32)
        return (QFileInfo(fileName1).canonicalFilePath().compare(QFileInfo(fileName2).canonicalFilePath(), Qt::CaseInsensitive) == 0);
#else
        return QFileInfo(fileName1).canonicalFilePath() == QFileInfo(fileName2).canonicalFilePath();
#endif
    }
    return QFileInfo(fileName1).filePath() == QFileInfo(fileName2).filePath();
}

QStringList FileUtil::removeFiles(const QStringList &files)
{
    QStringList result;
    foreach (QString file, files) {
        if (QFile::exists(file) && QFile::remove(file)) {
            result << file;
        }
    }
    return result;
}

QStringList FileUtil::removeWorkDir(const QString &workDir, const QStringList &filters)
{
    QStringList result;
    QDir dir(workDir);
    if (!dir.exists())
        return result;

    QFileInfoList dirs = dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);

    foreach (QFileInfo d, dirs) {
        removeWorkDir(d.filePath(),filters);
    }

    QFileInfoList files = dir.entryInfoList(filters,QDir::Files);
    foreach (QFileInfo f, files) {
        bool b = QFile::remove(f.filePath());
        if (b) {
            result << f.fileName();
        }
    }
    return result;
}

QMap<QString,QStringList> FileUtil::readFileContext(QIODevice *dev)
{
    QMap<QString,QStringList> contextMap;
    QStringList list;
    QString line;
    bool bnext = false;
    while (!dev->atEnd()) {
        QByteArray ar = dev->readLine().trimmed();
        if (!ar.isEmpty() && ar.right(1) == "\\") {
            bnext = true;
            ar[ar.length()-1] = ' ';
        } else {
            bnext = false;
        }
        line.push_back(ar);
        if (!bnext && !line.isEmpty()) {
            list.push_back(line);
            line.clear();
        }
    }

    if (!line.isEmpty()) {
        list.push_back(line);
    }

    foreach (QString line, list) {
        if (line.size() >= 1 && line.at(0) == '#')
            continue;
        QStringList v = line.split(QRegExp("\\+="),QString::SkipEmptyParts);
        if (v.count() == 1) {
            v = line.split(QRegExp("="),QString::SkipEmptyParts);
            if (v.count() == 2) {
                QStringList v2 = v.at(1).split(" ",QString::SkipEmptyParts);
                if (!v2.isEmpty()) {
                    contextMap[v.at(0).trimmed()] = v2;
                }
            }
        } else if (v.count() == 2) {
            QStringList v2 = v.at(1).split(" ",QString::SkipEmptyParts);
            if (!v2.isEmpty())
                contextMap[v.at(0).trimmed()].append(v2);
        }
    }
    return contextMap;
}

#ifdef Q_OS_WIN
QString FileUtil::canExec(QString fileName, QStringList exts)
{
    QFileInfo info(fileName);
    QString suffix = info.suffix();
    if (!suffix.isEmpty()) {
        suffix = "."+suffix;
        foreach(QString ext, exts) {
            if (suffix == ext && info.exists()) {
                return info.canonicalFilePath();
            }
        }
    }
    foreach(QString ext, exts) {
        QFileInfo info(fileName+ext);
        if (info.exists()) {
            return info.filePath();
        }
    }
    return QString();
}

QString FileUtil::lookPath(const QString &file, const QProcessEnvironment &env, bool bLocalPriority)
{
    QString fileName = file;
    QStringList exts;
    QString extenv = env.value("PATHEXT");
    if (!extenv.isEmpty()) {
        foreach(QString ext, extenv.split(';',QString::SkipEmptyParts)) {
            if (ext.isEmpty()) {
                continue;
            }
            if (ext[0] != '.') {
                ext= '.'+ext;
            }
            exts.append(ext.toLower());
        }
    }

    if (fileName.contains('\\') || fileName.contains('/')) {
        QString exec = canExec(fileName,exts);
        if (!exec.isEmpty()) {
            return exec;
        }
    }
    if (bLocalPriority) {
        QString exec = canExec(".\\"+fileName,exts);
        if (!exec.isEmpty()) {
            return exec;
        }
    }
    QString pathenv = env.value("PATH");
    if (pathenv.isEmpty()) {
        QString exec = canExec(".\\"+fileName,exts);
        if (!exec.isEmpty()) {
            return exec;
        }
    } else {
        foreach(QString dir,pathenv.split(';',QString::SkipEmptyParts)) {
            QFileInfo info(QDir(dir),fileName);
            QString exec = canExec(info.filePath(),exts);
            if (!exec.isEmpty()) {
                return exec;
            }
        }
    }
    return QString();
}

QString FileUtil::lookPathInDir(const QString &file, const QString &dir)
{
    QString fileName = file;
    QStringList exts;
    QString extenv =  QProcessEnvironment::systemEnvironment().value("PATHEXT");
    if (!extenv.isEmpty()) {
        foreach(QString ext, extenv.split(';',QString::SkipEmptyParts)) {
            if (ext.isEmpty()) {
                continue;
            }
            if (ext[0] != '.') {
                ext= '.'+ext;
            }
            exts.append(ext.toLower());
        }
    }

    if (fileName.contains('\\') || fileName.contains('/')) {
        QString exec = canExec(fileName,exts);
        if (!exec.isEmpty()) {
            return exec;
        }
    }
    QFileInfo info(QDir(dir),fileName);
    QString exec = canExec(info.filePath(),exts);
    if (!exec.isEmpty()) {
        return exec;
    }
    return QString();
}

#else
QString FileUtil::canExec(QString fileName, QStringList /*exts*/)
{
    QFileInfo info(fileName);
    if (info.exists() && info.isExecutable()) {
        return info.canonicalFilePath();
    }
    return QString();
}

QString FileUtil::lookPath(const QString &file, const QProcessEnvironment &env, bool bLocalPriority)
{
    QString fileName = file;
    if (fileName.contains('/')) {
        QString exec = canExec(fileName);
        if (!exec.isEmpty()) {
            return exec;
        }
    }
    if (bLocalPriority) {
        QString exec = canExec("./"+fileName);
        if (!exec.isEmpty()) {
            return exec;
        }
    }
    QString pathenv = env.value("PATH");
    foreach(QString dir,pathenv.split(':',QString::KeepEmptyParts)) {
        if (dir == "") {
            dir = ".";
        }
        QString exec = canExec(dir+"/"+file);
        if (!exec.isEmpty()) {
            return exec;
        }
    }
    return QString();
}

QString FileUtil::lookPathInDir(const QString &file, const QString &dir)
{
    QString fileName = file;
    if (fileName.contains('/')) {
        QString exec = canExec(fileName);
        if (!exec.isEmpty()) {
            return exec;
        }
    }
    QString exec = canExec(dir+"/"+file);
    if (!exec.isEmpty()) {
        return exec;
    }
    return QString();
}

#endif

QString FileUtil::findExecute(const QString &target)
{
    QStringList targetList;
#ifdef Q_OS_WIN
    targetList << target+".exe";
#endif
    targetList << target;
    foreach (QString fileName, targetList) {
        if (QFile::exists(fileName)) {
            QFileInfo info(fileName);
            if (info.isExecutable()) {
                return info.canonicalFilePath();
            }
        }
    }
    return QString();
}

GoExecute::GoExecute(const QString &cmdPath)
{
#ifdef Q_OS_WIN
    QString goexec = "goexec.exe";
#else
    QString goexec = "goexec";
#endif
    m_goexec = QFileInfo(QDir(cmdPath),goexec).absoluteFilePath();
}

bool GoExecute::isReady()
{
    return QFile::exists(m_goexec);
}

QString GoExecute::cmd() const
{
    return m_goexec;
}

bool GoExecute::exec(const QString &workPath, const QString &target, const QStringList &args)
{
#ifdef Q_OS_WIN
    QStringList iargs;
    if (!workPath.isEmpty()) {
        iargs << "-w" << workPath;
    }
    iargs << target << args;
    return QProcess::startDetached(m_goexec,iargs);
#else
    QStringList iargs;
    iargs << "-e" << m_goexec;
    if (!workPath.isEmpty()) {
        iargs << "-w" << workPath;
    }
    iargs << target << args;
    return QProcess::startDetached("/usr/bin/xterm",iargs);
#endif
}

QString FileUtil::lookupGoBin(const QString &bin, LiteApi::IApplication *app, bool bLiteAppPriority)
{
    if (bLiteAppPriority) {
        QString find = FileUtil::findExecute(app->applicationPath()+"/"+bin);
        if (!find.isEmpty()) {
            return find;
        }
    }
    QProcessEnvironment env = LiteApi::getCurrentEnvironment(app);
#ifdef Q_OS_WIN
    QString sep = ";";
#else
    QString sep = ":";
#endif

    QString goos = env.value("GOOS");
    if (goos.isEmpty()) {
        goos = LiteApi::getDefaultGOOS();
    }
    QString goarch = env.value("GOARCH");
    QString goroot = env.value("GOROOT");
    if (goroot.isEmpty()) {
        goroot = LiteApi::getDefaultGOROOT();
    }
    QStringList pathList;
    foreach (QString path, env.value("GOPATH").split(sep,QString::SkipEmptyParts)) {
        pathList.append(QDir::toNativeSeparators(path));
    }
    foreach (QString path, app->settings()->value("liteide/gopath").toStringList()) {
        pathList.append(QDir::toNativeSeparators(path));
    }
    pathList.removeDuplicates();
    env.insert("GOPATH",pathList.join(sep));

    if (!goroot.isEmpty()) {
        pathList.prepend(goroot);
    }

    QStringList binList;
    QString gobin = env.value("GOBIN");
    if (!gobin.isEmpty()) {
        binList.append(gobin);
    }
    foreach (QString path, pathList) {
        binList.append(QFileInfo(path,"bin").filePath());
        binList.append(QFileInfo(path,"bin/"+goos+"_"+goarch).filePath());
    }
    foreach(QString path, binList) {
        QString find = FileUtil::findExecute(path+"/"+bin);
        if (!find.isEmpty()) {
            return find;
        }
    }
    return FileUtil::lookupLiteBin(bin,app);
}

QString FileUtil::lookupLiteBin(const QString &bin, LiteApi::IApplication *app)
{
    QString find = FileUtil::findExecute(app->applicationPath()+"/"+bin);
    if (find.isEmpty()) {
        find = FileUtil::lookPath(bin,LiteApi::getGoEnvironment(app),true);
    }
    return find;
}

bool FileUtil::CopyDirectory(const QString &src, const QString &dest)
{
    QDir dir(src);
    foreach(QFileInfo info, dir.entryInfoList(QDir::Files)) {
        if (info.isFile() && !info.isSymLink()) {
            QFile in(info.filePath());
            if (!in.open(QFile::ReadOnly)) {
                return false;
            }
            QFile out(dest+"/"+info.fileName());
            if (!out.open(QFile::WriteOnly)) {
                return false;
            }
            out.write(in.readAll());
        }
    }
    return true;
}

<|endoftext|>


<commit_before>#include "pbcontroller.h"

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <getopt.h>
#include <iostream>
#include <pwd.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <thread>
#include <unistd.h>

#include "colormanager.h"
#include "config.h"
#include "configcontainer.h"
#include "configexception.h"
#include "globals.h"
#include "keymap.h"
#include "logger.h"
#include "matcherexception.h"
#include "nullconfigactionhandler.h"
#include "pbview.h"
#include "poddlthread.h"
#include "queueloader.h"
#include "strprintf.h"
#include "utils.h"

using namespace newsboat;

static void ctrl_c_action(int sig)
{
	LOG(Level::DEBUG, "caugh signal %d", sig);
	Stfl::reset();
	::exit(EXIT_FAILURE);
}

namespace podboat {

/**
 * \brief Try to setup XDG style dirs.
 *
 * returns false, if that fails
 */
bool PbController::setup_dirs_xdg(const char* env_home)
{
	const char* env_xdg_config;
	const char* env_xdg_data;
	std::string xdg_config_dir;
	std::string xdg_data_dir;

	env_xdg_config = ::getenv("XDG_CONFIG_HOME");
	if (env_xdg_config) {
		xdg_config_dir = env_xdg_config;
	} else {
		xdg_config_dir = env_home;
		xdg_config_dir.append(NEWSBEUTER_PATH_SEP);
		xdg_config_dir.append(".config");
	}

	env_xdg_data = ::getenv("XDG_DATA_HOME");
	if (env_xdg_data) {
		xdg_data_dir = env_xdg_data;
	} else {
		xdg_data_dir = env_home;
		xdg_data_dir.append(NEWSBEUTER_PATH_SEP);
		xdg_data_dir.append(".local");
		xdg_data_dir.append(NEWSBEUTER_PATH_SEP);
		xdg_data_dir.append("share");
	}

	xdg_config_dir.append(NEWSBEUTER_PATH_SEP);
	xdg_config_dir.append(NEWSBOAT_SUBDIR_XDG);

	xdg_data_dir.append(NEWSBEUTER_PATH_SEP);
	xdg_data_dir.append(NEWSBOAT_SUBDIR_XDG);

	bool config_dir_exists =
		0 == access(xdg_config_dir.c_str(), R_OK | X_OK);

	if (!config_dir_exists) {
		std::cerr << strprintf::fmt(
				     _("XDG: configuration directory '%s' not "
				       "accessible, "
				       "using '%s' instead."),
				     xdg_config_dir,
				     config_dir)
			  << std::endl;

		return false;
	}

	/* Invariant: config dir exists.
	 *
	 * At this point, we're confident we'll be using XDG. We don't check if
	 * data dir exists, because if it doesn't we'll create it. */

	config_dir = xdg_config_dir;

	// create data directory if it doesn't exist
	int ret = utils::mkdir_parents(xdg_data_dir, 0700);
	if (ret && errno != EEXIST) {
		LOG(Level::CRITICAL,
			"Couldn't create `%s': (%i) %s",
			xdg_data_dir,
			errno,
			strerror(errno));
		::exit(EXIT_FAILURE);
	}

	/* in config */
	url_file = config_dir + std::string(NEWSBEUTER_PATH_SEP) + url_file;
	config_file =
		config_dir + std::string(NEWSBEUTER_PATH_SEP) + config_file;

	/* in data */
	cache_file =
		xdg_data_dir + std::string(NEWSBEUTER_PATH_SEP) + cache_file;
	lock_file = cache_file + LOCK_SUFFIX;
	queue_file =
		xdg_data_dir + std::string(NEWSBEUTER_PATH_SEP) + queue_file;
	searchfile = strprintf::fmt(
		"%s%shistory.search", xdg_data_dir, NEWSBEUTER_PATH_SEP);
	cmdlinefile = strprintf::fmt(
		"%s%shistory.cmdline", xdg_data_dir, NEWSBEUTER_PATH_SEP);

	return true;
}

PbController::PbController()
	: v(0)
	, config_file("config")
	, queue_file("queue")
	, cfg(0)
	, view_update_(true)
	, max_dls(1)
	, ql(0)
	, lock_file("pb-lock.pid")
{
	char* cfgdir;
	if (!(cfgdir = ::getenv("HOME"))) {
		struct passwd* spw = ::getpwuid(::getuid());
		if (spw) {
			cfgdir = spw->pw_dir;
		} else {
			std::cout << _("Fatal error: couldn't determine home "
				       "directory!")
				  << std::endl;
			std::cout << strprintf::fmt(
					     _("Please set the HOME "
					       "environment variable or add a "
					       "valid user for UID %u!"),
					     ::getuid())
				  << std::endl;
			::exit(EXIT_FAILURE);
		}
	}
	config_dir = cfgdir;

	if (setup_dirs_xdg(cfgdir))
		return;

	config_dir.append(NEWSBEUTER_PATH_SEP);
	config_dir.append(NEWSBOAT_CONFIG_SUBDIR);

	// create configuration directory if it doesn't exist
	int ret = ::mkdir(config_dir.c_str(), 0700);
	if (ret && errno != EEXIST) {
		std::cerr << strprintf::fmt(
				     _("Fatal error: couldn't create "
				       "configuration directory `%s': (%i) %s"),
				     config_dir,
				     errno,
				     std::strerror(errno))
			  << std::endl;
		::exit(EXIT_FAILURE);
	}

	config_file =
		config_dir + std::string(NEWSBEUTER_PATH_SEP) + config_file;
	queue_file = config_dir + std::string(NEWSBEUTER_PATH_SEP) + queue_file;
	lock_file = config_dir + std::string(NEWSBEUTER_PATH_SEP) + lock_file;
}

PbController::~PbController()
{
	delete cfg;
}

int PbController::run(int argc, char* argv[])
{
	int c;
	bool automatic_dl = false;

	::signal(SIGINT, ctrl_c_action);

	static const char getopt_str[] = "C:q:d:l:havV";
	static const struct option longopts[] = {
		{"config-file", required_argument, 0, 'C'},
		{"queue-file", required_argument, 0, 'q'},
		{"log-file", required_argument, 0, 'd'},
		{"log-level", required_argument, 0, 'l'},
		{"help", no_argument, 0, 'h'},
		{"autodownload", no_argument, 0, 'a'},
		{"version", no_argument, 0, 'v'},
		{0, 0, 0, 0}};

	while ((c = ::getopt_long(argc, argv, getopt_str, longopts, nullptr)) !=
		-1) {
		switch (c) {
		case ':':
		case '?':
			print_usage(argv[0]);
			return EXIT_FAILURE;
		case 'C':
			config_file = optarg;
			break;
		case 'q':
			queue_file = optarg;
			break;
		case 'a':
			automatic_dl = true;
			break;
		case 'd':
			Logger::set_logfile(optarg);
			break;
		case 'l': {
			Level l = static_cast<Level>(atoi(optarg));
			if (l > Level::NONE && l <= Level::DEBUG) {
				Logger::set_loglevel(l);
			} else {
				std::cerr << strprintf::fmt(_("%s: %d: invalid "
							      "loglevel value"),
						     argv[0],
						     static_cast<int>(l))
					  << std::endl;
				return EXIT_FAILURE;
			}
		} break;
		case 'h':
			print_usage(argv[0]);
			return EXIT_SUCCESS;
		}
	};

	std::cout << strprintf::fmt(
			     _("Starting %s %s..."), "podboat", utils::program_version())
		  << std::endl;

	fslock = std::unique_ptr<FsLock>(new FsLock());
	pid_t pid;
	if (!fslock->try_lock(lock_file, pid)) {
		std::cout << strprintf::fmt(
				     _("Error: an instance of %s is already "
				       "running (PID: %u)"),
				     "podboat",
				     pid)
			  << std::endl;
		return EXIT_FAILURE;
	}

	std::cout << _("Loading configuration...");
	std::cout.flush();

	ConfigParser cfgparser;
	cfg = new ConfigContainer();
	cfg->register_commands(cfgparser);
	ColorManager* colorman = new ColorManager();
	colorman->register_commands(cfgparser);

	KeyMap keys(KM_PODBOAT);
	cfgparser.register_handler("bind-key", &keys);
	cfgparser.register_handler("unbind-key", &keys);

	NullConfigActionHandler null_cah;
	cfgparser.register_handler("macro", &null_cah);
	cfgparser.register_handler("ignore-article", &null_cah);
	cfgparser.register_handler("always-download", &null_cah);
	cfgparser.register_handler("define-filter", &null_cah);
	cfgparser.register_handler("highlight", &null_cah);
	cfgparser.register_handler("highlight-article", &null_cah);
	cfgparser.register_handler("reset-unread-on-update", &null_cah);

	try {
		cfgparser.parse("/etc/newsboat/config");
		cfgparser.parse(config_file);
	} catch (const ConfigException& ex) {
		std::cout << ex.what() << std::endl;
		delete colorman;
		return EXIT_FAILURE;
	}

	if (colorman->colors_loaded())
		colorman->set_pb_colors(v);
	delete colorman;

	max_dls = cfg->get_configvalue_as_int("max-downloads");

	std::cout << _("done.") << std::endl;

	ql = new QueueLoader(queue_file, this);
	ql->reload(downloads_);

	v->set_keymap(&keys);

	v->run(automatic_dl);

	Stfl::reset();

	std::cout << _("Cleaning up queue...");
	std::cout.flush();

	ql->reload(downloads_);
	delete ql;

	std::cout << _("done.") << std::endl;

	return EXIT_SUCCESS;
}

void PbController::print_usage(const char* argv0)
{
	auto msg = strprintf::fmt(
		_("%s %s\nusage %s [-C <file>] [-q <file>] [-h]\n"),
		"podboat",
		utils::program_version(),
		argv0);
	std::cout << msg;

	struct Arg {
		const char name;
		const std::string longname;
		const std::string params;
		const std::string desc;
	};

	static const std::vector<Arg> args = {
		{'C',
			"config-file",
			_s("<configfile>"),
			_s("read configuration from <configfile>")},
		{'q',
			"queue-file",
			_s("<queuefile>"),
			_s("use <queuefile> as queue file")},
		{'a', "autodownload", "", _s("start download on startup")},
		{'l',
			"log-level",
			_s("<loglevel>"),
			_s("write a log with a certain loglevel (valid values: "
			   "1 to "
			   "6)")},
		{'d',
			"log-file",
			_s("<logfile>"),
			_s("use <logfile> as output log file")},
		{'h', "help", "", _s("this help")}};

	for (const auto& a : args) {
		std::string longcolumn("-");
		longcolumn += a.name;
		longcolumn += ", --" + a.longname;
		longcolumn += a.params.size() > 0 ? "=" + a.params : "";
		std::cout << "\t" << longcolumn;
		for (unsigned int j = 0; j < utils::gentabs(longcolumn); j++) {
			std::cout << "\t";
		}
		std::cout << a.desc << std::endl;
	}
}

std::string PbController::get_dlpath()
{
	return cfg->get_configvalue("download-path");
}

std::string PbController::get_formatstr()
{
	return cfg->get_configvalue("podlist-format");
}

unsigned int PbController::downloads_in_progress()
{
	unsigned int count = 0;
	for (const auto& dl : downloads_) {
		if (dl.status() == DlStatus::DOWNLOADING)
			++count;
	}
	return count;
}

unsigned int PbController::get_maxdownloads()
{
	return max_dls;
}

void PbController::reload_queue(bool remove_unplayed)
{
	if (ql) {
		ql->reload(downloads_, remove_unplayed);
	}
}

double PbController::get_total_kbps()
{
	double result = 0.0;
	for (const auto& dl : downloads_) {
		if (dl.status() == DlStatus::DOWNLOADING) {
			result += dl.kbps();
		}
	}
	return result;
}

void PbController::start_downloads()
{
	int dl2start = get_maxdownloads() - downloads_in_progress();
	for (auto& download : downloads_) {
		if (dl2start == 0)
			break;

		if (download.status() == DlStatus::QUEUED) {
			std::thread t{PodDlThread(&download, cfg)};
			--dl2start;
			t.detach();
		}
	}
}

void PbController::increase_parallel_downloads()
{
	++max_dls;
}

void PbController::decrease_parallel_downloads()
{
	if (max_dls > 1)
		--max_dls;
}

void PbController::play_file(const std::string& file)
{
	std::string cmdline;
	std::string player = cfg->get_configvalue("player");
	if (player == "")
		return;
	cmdline.append(player);
	cmdline.append(" '");
	cmdline.append(utils::replace_all(file, "'", "'\\''"));
	cmdline.append("'");
	Stfl::reset();
	utils::run_interactively(cmdline, "PbController::play_file");
}

} // namespace podboat
<commit_msg>drop errno is EEXIST condition when calling mkdir_parents<commit_after>#include "pbcontroller.h"

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <getopt.h>
#include <iostream>
#include <pwd.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <thread>
#include <unistd.h>

#include "colormanager.h"
#include "config.h"
#include "configcontainer.h"
#include "configexception.h"
#include "globals.h"
#include "keymap.h"
#include "logger.h"
#include "matcherexception.h"
#include "nullconfigactionhandler.h"
#include "pbview.h"
#include "poddlthread.h"
#include "queueloader.h"
#include "strprintf.h"
#include "utils.h"

using namespace newsboat;

static void ctrl_c_action(int sig)
{
	LOG(Level::DEBUG, "caugh signal %d", sig);
	Stfl::reset();
	::exit(EXIT_FAILURE);
}

namespace podboat {

/**
 * \brief Try to setup XDG style dirs.
 *
 * returns false, if that fails
 */
bool PbController::setup_dirs_xdg(const char* env_home)
{
	const char* env_xdg_config;
	const char* env_xdg_data;
	std::string xdg_config_dir;
	std::string xdg_data_dir;

	env_xdg_config = ::getenv("XDG_CONFIG_HOME");
	if (env_xdg_config) {
		xdg_config_dir = env_xdg_config;
	} else {
		xdg_config_dir = env_home;
		xdg_config_dir.append(NEWSBEUTER_PATH_SEP);
		xdg_config_dir.append(".config");
	}

	env_xdg_data = ::getenv("XDG_DATA_HOME");
	if (env_xdg_data) {
		xdg_data_dir = env_xdg_data;
	} else {
		xdg_data_dir = env_home;
		xdg_data_dir.append(NEWSBEUTER_PATH_SEP);
		xdg_data_dir.append(".local");
		xdg_data_dir.append(NEWSBEUTER_PATH_SEP);
		xdg_data_dir.append("share");
	}

	xdg_config_dir.append(NEWSBEUTER_PATH_SEP);
	xdg_config_dir.append(NEWSBOAT_SUBDIR_XDG);

	xdg_data_dir.append(NEWSBEUTER_PATH_SEP);
	xdg_data_dir.append(NEWSBOAT_SUBDIR_XDG);

	bool config_dir_exists =
		0 == access(xdg_config_dir.c_str(), R_OK | X_OK);

	if (!config_dir_exists) {
		std::cerr << strprintf::fmt(
				     _("XDG: configuration directory '%s' not "
				       "accessible, "
				       "using '%s' instead."),
				     xdg_config_dir,
				     config_dir)
			  << std::endl;

		return false;
	}

	/* Invariant: config dir exists.
	 *
	 * At this point, we're confident we'll be using XDG. We don't check if
	 * data dir exists, because if it doesn't we'll create it. */

	config_dir = xdg_config_dir;

	// create data directory if it doesn't exist
	int ret = utils::mkdir_parents(xdg_data_dir, 0700);
	if (ret == -1) {
		LOG(Level::CRITICAL,
			"Couldn't create `%s'",
			xdg_data_dir);
		::exit(EXIT_FAILURE);
	}

	/* in config */
	url_file = config_dir + std::string(NEWSBEUTER_PATH_SEP) + url_file;
	config_file =
		config_dir + std::string(NEWSBEUTER_PATH_SEP) + config_file;

	/* in data */
	cache_file =
		xdg_data_dir + std::string(NEWSBEUTER_PATH_SEP) + cache_file;
	lock_file = cache_file + LOCK_SUFFIX;
	queue_file =
		xdg_data_dir + std::string(NEWSBEUTER_PATH_SEP) + queue_file;
	searchfile = strprintf::fmt(
		"%s%shistory.search", xdg_data_dir, NEWSBEUTER_PATH_SEP);
	cmdlinefile = strprintf::fmt(
		"%s%shistory.cmdline", xdg_data_dir, NEWSBEUTER_PATH_SEP);

	return true;
}

PbController::PbController()
	: v(0)
	, config_file("config")
	, queue_file("queue")
	, cfg(0)
	, view_update_(true)
	, max_dls(1)
	, ql(0)
	, lock_file("pb-lock.pid")
{
	char* cfgdir;
	if (!(cfgdir = ::getenv("HOME"))) {
		struct passwd* spw = ::getpwuid(::getuid());
		if (spw) {
			cfgdir = spw->pw_dir;
		} else {
			std::cout << _("Fatal error: couldn't determine home "
				       "directory!")
				  << std::endl;
			std::cout << strprintf::fmt(
					     _("Please set the HOME "
					       "environment variable or add a "
					       "valid user for UID %u!"),
					     ::getuid())
				  << std::endl;
			::exit(EXIT_FAILURE);
		}
	}
	config_dir = cfgdir;

	if (setup_dirs_xdg(cfgdir))
		return;

	config_dir.append(NEWSBEUTER_PATH_SEP);
	config_dir.append(NEWSBOAT_CONFIG_SUBDIR);

	// create configuration directory if it doesn't exist
	int ret = ::mkdir(config_dir.c_str(), 0700);
	if (ret && errno != EEXIST) {
		std::cerr << strprintf::fmt(
				     _("Fatal error: couldn't create "
				       "configuration directory `%s': (%i) %s"),
				     config_dir,
				     errno,
				     std::strerror(errno))
			  << std::endl;
		::exit(EXIT_FAILURE);
	}

	config_file =
		config_dir + std::string(NEWSBEUTER_PATH_SEP) + config_file;
	queue_file = config_dir + std::string(NEWSBEUTER_PATH_SEP) + queue_file;
	lock_file = config_dir + std::string(NEWSBEUTER_PATH_SEP) + lock_file;
}

PbController::~PbController()
{
	delete cfg;
}

int PbController::run(int argc, char* argv[])
{
	int c;
	bool automatic_dl = false;

	::signal(SIGINT, ctrl_c_action);

	static const char getopt_str[] = "C:q:d:l:havV";
	static const struct option longopts[] = {
		{"config-file", required_argument, 0, 'C'},
		{"queue-file", required_argument, 0, 'q'},
		{"log-file", required_argument, 0, 'd'},
		{"log-level", required_argument, 0, 'l'},
		{"help", no_argument, 0, 'h'},
		{"autodownload", no_argument, 0, 'a'},
		{"version", no_argument, 0, 'v'},
		{0, 0, 0, 0}};

	while ((c = ::getopt_long(argc, argv, getopt_str, longopts, nullptr)) !=
		-1) {
		switch (c) {
		case ':':
		case '?':
			print_usage(argv[0]);
			return EXIT_FAILURE;
		case 'C':
			config_file = optarg;
			break;
		case 'q':
			queue_file = optarg;
			break;
		case 'a':
			automatic_dl = true;
			break;
		case 'd':
			Logger::set_logfile(optarg);
			break;
		case 'l': {
			Level l = static_cast<Level>(atoi(optarg));
			if (l > Level::NONE && l <= Level::DEBUG) {
				Logger::set_loglevel(l);
			} else {
				std::cerr << strprintf::fmt(_("%s: %d: invalid "
							      "loglevel value"),
						     argv[0],
						     static_cast<int>(l))
					  << std::endl;
				return EXIT_FAILURE;
			}
		} break;
		case 'h':
			print_usage(argv[0]);
			return EXIT_SUCCESS;
		}
	};

	std::cout << strprintf::fmt(
			     _("Starting %s %s..."), "podboat", utils::program_version())
		  << std::endl;

	fslock = std::unique_ptr<FsLock>(new FsLock());
	pid_t pid;
	if (!fslock->try_lock(lock_file, pid)) {
		std::cout << strprintf::fmt(
				     _("Error: an instance of %s is already "
				       "running (PID: %u)"),
				     "podboat",
				     pid)
			  << std::endl;
		return EXIT_FAILURE;
	}

	std::cout << _("Loading configuration...");
	std::cout.flush();

	ConfigParser cfgparser;
	cfg = new ConfigContainer();
	cfg->register_commands(cfgparser);
	ColorManager* colorman = new ColorManager();
	colorman->register_commands(cfgparser);

	KeyMap keys(KM_PODBOAT);
	cfgparser.register_handler("bind-key", &keys);
	cfgparser.register_handler("unbind-key", &keys);

	NullConfigActionHandler null_cah;
	cfgparser.register_handler("macro", &null_cah);
	cfgparser.register_handler("ignore-article", &null_cah);
	cfgparser.register_handler("always-download", &null_cah);
	cfgparser.register_handler("define-filter", &null_cah);
	cfgparser.register_handler("highlight", &null_cah);
	cfgparser.register_handler("highlight-article", &null_cah);
	cfgparser.register_handler("reset-unread-on-update", &null_cah);

	try {
		cfgparser.parse("/etc/newsboat/config");
		cfgparser.parse(config_file);
	} catch (const ConfigException& ex) {
		std::cout << ex.what() << std::endl;
		delete colorman;
		return EXIT_FAILURE;
	}

	if (colorman->colors_loaded())
		colorman->set_pb_colors(v);
	delete colorman;

	max_dls = cfg->get_configvalue_as_int("max-downloads");

	std::cout << _("done.") << std::endl;

	ql = new QueueLoader(queue_file, this);
	ql->reload(downloads_);

	v->set_keymap(&keys);

	v->run(automatic_dl);

	Stfl::reset();

	std::cout << _("Cleaning up queue...");
	std::cout.flush();

	ql->reload(downloads_);
	delete ql;

	std::cout << _("done.") << std::endl;

	return EXIT_SUCCESS;
}

void PbController::print_usage(const char* argv0)
{
	auto msg = strprintf::fmt(
		_("%s %s\nusage %s [-C <file>] [-q <file>] [-h]\n"),
		"podboat",
		utils::program_version(),
		argv0);
	std::cout << msg;

	struct Arg {
		const char name;
		const std::string longname;
		const std::string params;
		const std::string desc;
	};

	static const std::vector<Arg> args = {
		{'C',
			"config-file",
			_s("<configfile>"),
			_s("read configuration from <configfile>")},
		{'q',
			"queue-file",
			_s("<queuefile>"),
			_s("use <queuefile> as queue file")},
		{'a', "autodownload", "", _s("start download on startup")},
		{'l',
			"log-level",
			_s("<loglevel>"),
			_s("write a log with a certain loglevel (valid values: "
			   "1 to "
			   "6)")},
		{'d',
			"log-file",
			_s("<logfile>"),
			_s("use <logfile> as output log file")},
		{'h', "help", "", _s("this help")}};

	for (const auto& a : args) {
		std::string longcolumn("-");
		longcolumn += a.name;
		longcolumn += ", --" + a.longname;
		longcolumn += a.params.size() > 0 ? "=" + a.params : "";
		std::cout << "\t" << longcolumn;
		for (unsigned int j = 0; j < utils::gentabs(longcolumn); j++) {
			std::cout << "\t";
		}
		std::cout << a.desc << std::endl;
	}
}

std::string PbController::get_dlpath()
{
	return cfg->get_configvalue("download-path");
}

std::string PbController::get_formatstr()
{
	return cfg->get_configvalue("podlist-format");
}

unsigned int PbController::downloads_in_progress()
{
	unsigned int count = 0;
	for (const auto& dl : downloads_) {
		if (dl.status() == DlStatus::DOWNLOADING)
			++count;
	}
	return count;
}

unsigned int PbController::get_maxdownloads()
{
	return max_dls;
}

void PbController::reload_queue(bool remove_unplayed)
{
	if (ql) {
		ql->reload(downloads_, remove_unplayed);
	}
}

double PbController::get_total_kbps()
{
	double result = 0.0;
	for (const auto& dl : downloads_) {
		if (dl.status() == DlStatus::DOWNLOADING) {
			result += dl.kbps();
		}
	}
	return result;
}

void PbController::start_downloads()
{
	int dl2start = get_maxdownloads() - downloads_in_progress();
	for (auto& download : downloads_) {
		if (dl2start == 0)
			break;

		if (download.status() == DlStatus::QUEUED) {
			std::thread t{PodDlThread(&download, cfg)};
			--dl2start;
			t.detach();
		}
	}
}

void PbController::increase_parallel_downloads()
{
	++max_dls;
}

void PbController::decrease_parallel_downloads()
{
	if (max_dls > 1)
		--max_dls;
}

void PbController::play_file(const std::string& file)
{
	std::string cmdline;
	std::string player = cfg->get_configvalue("player");
	if (player == "")
		return;
	cmdline.append(player);
	cmdline.append(" '");
	cmdline.append(utils::replace_all(file, "'", "'\\''"));
	cmdline.append("'");
	Stfl::reset();
	utils::run_interactively(cmdline, "PbController::play_file");
}

} // namespace podboat
<|endoftext|>


<commit_before>#include "AudioProcessor.h"

#include "AudioDevice.h"

#include <QAudioOutput>

extern "C" {
#include "gba-thread.h"
}

using namespace QGBA;

AudioProcessor::AudioProcessor(QObject* parent)
	: QObject(parent)
	, m_audioOutput(nullptr)
	, m_device(nullptr)
{
}

void AudioProcessor::setInput(GBAThread* input) {
	m_context = input;
	if (m_device) {
		m_device->setInput(input);
		if (m_audioOutput) {
			m_device->setFormat(m_audioOutput->format());
		}
	}
}

void AudioProcessor::start() {
	if (!m_device) {
		m_device = new AudioDevice(this);
	}

	if (!m_audioOutput) {
		QAudioFormat format;
		format.setSampleRate(44100);
		format.setChannelCount(2);
		format.setSampleSize(16);
		format.setCodec("audio/pcm");
		format.setByteOrder(QAudioFormat::LittleEndian);
		format.setSampleType(QAudioFormat::SignedInt);

		m_audioOutput = new QAudioOutput(format, this);
	}

	m_device->setInput(m_context);
	m_device->setFormat(m_audioOutput->format());
	m_audioOutput->setBufferSize(m_context->audioBuffers * 4);

	m_audioOutput->start(m_device);
}

void AudioProcessor::pause() {
	if (m_audioOutput) {
		m_audioOutput->stop();
	}
}

void AudioProcessor::setBufferSamples(int samples) {
	if (m_audioOutput) {
		QAudioFormat format = m_audioOutput->format();
		m_audioOutput->setBufferSize(samples * format.channelCount() * format.sampleSize() / 8);
	}
}

void AudioProcessor::inputParametersChanged() {
	if (m_device) {
		m_device->setFormat(m_audioOutput->format());
	}
}
<commit_msg>Qt: Reset audio output when changing sample size<commit_after>#include "AudioProcessor.h"

#include "AudioDevice.h"

#include <QAudioOutput>

extern "C" {
#include "gba-thread.h"
}

using namespace QGBA;

AudioProcessor::AudioProcessor(QObject* parent)
	: QObject(parent)
	, m_audioOutput(nullptr)
	, m_device(nullptr)
{
}

void AudioProcessor::setInput(GBAThread* input) {
	m_context = input;
	if (m_device) {
		m_device->setInput(input);
		if (m_audioOutput) {
			m_device->setFormat(m_audioOutput->format());
		}
	}
}

void AudioProcessor::start() {
	if (!m_device) {
		m_device = new AudioDevice(this);
	}

	if (!m_audioOutput) {
		QAudioFormat format;
		format.setSampleRate(44100);
		format.setChannelCount(2);
		format.setSampleSize(16);
		format.setCodec("audio/pcm");
		format.setByteOrder(QAudioFormat::LittleEndian);
		format.setSampleType(QAudioFormat::SignedInt);

		m_audioOutput = new QAudioOutput(format, this);
	}

	m_device->setInput(m_context);
	m_device->setFormat(m_audioOutput->format());
	m_audioOutput->setBufferSize(m_context->audioBuffers * 4);

	m_audioOutput->start(m_device);
}

void AudioProcessor::pause() {
	if (m_audioOutput) {
		m_audioOutput->stop();
	}
}

void AudioProcessor::setBufferSamples(int samples) {
	if (m_audioOutput) {
		m_audioOutput->stop();
		m_audioOutput->setBufferSize(samples * 4);
		m_audioOutput->start(m_device);
	}
}

void AudioProcessor::inputParametersChanged() {
	if (m_device) {
		m_device->setFormat(m_audioOutput->format());
	}
}
<|endoftext|>


<commit_before>#include "IR.h"
#include "ParallelRVar.h"
#include "IRMutator.h"
#include "Debug.h"
#include "CSE.h"
#include "Simplify.h"
#include "IROperator.h"

namespace Halide {
namespace Internal {

using std::string;
using std::vector;
using std::map;

/** Find all calls arguments to the given function. Note that we don't
 * pick up lets for simplicity. This makes the comparison
 * conservative, because the let variables become unknowns. */
class FindLoads : public IRVisitor {
    using IRVisitor::visit;

    const string &func;

    void visit(const Call *op) {
        if (op->name == func && op->call_type == Call::Halide) {
            loads.push_back(op->args);
        }
        IRVisitor::visit(op);
    }

public:
    FindLoads(const string &f) : func(f) {}

    vector<vector<Expr> > loads;
};

/** Rename all free variables to unique new names. */
class RenameFreeVars : public IRMutator {
    using IRMutator::visit;

    map<string, string> new_names;

    void visit(const Variable *op) {
        if (!op->param.defined() && !op->image.defined()) {
            expr = Variable::make(op->type, get_new_name(op->name));
        }
    }

public:
    string get_new_name(const string &s) {
        map<string, string>::iterator iter = new_names.find(s);
        if (iter != new_names.end()) {
            return iter->second;
        } else {
            string new_name = s + "$_";
            new_names[s] = new_name;
            return new_name;
        }

    }

};

bool can_parallelize_rvar(const string &v,
                          const string &f,
                          const ReductionDefinition &r) {
    FindLoads find(f);
    for (size_t i = 0; i < r.values.size(); i++) {
        r.values[i].accept(&find);
    }

    // Make an expr representing the store done by a different thread.
    RenameFreeVars renamer;
    vector<Expr> other_store(r.args.size());
    for (size_t i = 0; i < r.args.size(); i++) {
        other_store[i] = renamer.mutate(r.args[i]);
    }

    // Construct an expression which is true when the two threads are
    // in fact two different threads. We'll use this liberally in the
    // following conditions to give the simplifier the best chance.
    Expr distinct_v = (Variable::make(Int(32), v) !=
                       Variable::make(Int(32), renamer.get_new_name(v)));

    // Construct an expression which is true if there's a collision
    // between this thread's store and the other thread's store.
    Expr hazard = const_true();
    for (size_t i = 0; i < r.args.size(); i++) {
        hazard = hazard && (distinct_v && (r.args[i] == other_store[i]));
    }

    // Add expressions that are true if there's a collision between
    // the other thread's store and this thread's loads.
    for (size_t i = 0; i < find.loads.size(); i++) {
        internal_assert(find.loads[i].size() == other_store.size());
        Expr check = const_true();
        for (size_t j = 0; j < find.loads[i].size(); j++) {
            check = check && (distinct_v && (find.loads[i][j] == other_store[j]));
        }
        hazard = hazard || check;
    }

    // Make a scope representing the bounds of the reduction domain
    Scope<Interval> bounds;
    if (r.domain.defined()) {
        for (size_t i = 0; i < r.domain.domain().size(); i++) {
            const ReductionVariable &rv = r.domain.domain()[i];
            Interval in = Interval(rv.min, simplify(rv.min + rv.extent - 1));
            bounds.push(rv.var, in);
            bounds.push(renamer.get_new_name(rv.var), in);
        }
    }

    debug(3) << "Attempting to falsify: " << hazard << "\n";
    hazard = simplify(hazard, false, bounds);
    debug(3) << "Simplified to: " << hazard << "\n";

    return is_zero(hazard);
}

}
}
<commit_msg>Fix bug in RenameFreeVars mutator<commit_after>#include "IR.h"
#include "ParallelRVar.h"
#include "IRMutator.h"
#include "Debug.h"
#include "CSE.h"
#include "Simplify.h"
#include "IROperator.h"

namespace Halide {
namespace Internal {

using std::string;
using std::vector;
using std::map;

/** Find all calls arguments to the given function. Note that we don't
 * pick up lets for simplicity. This makes the comparison
 * conservative, because the let variables become unknowns. */
class FindLoads : public IRVisitor {
    using IRVisitor::visit;

    const string &func;

    void visit(const Call *op) {
        if (op->name == func && op->call_type == Call::Halide) {
            loads.push_back(op->args);
        }
        IRVisitor::visit(op);
    }

public:
    FindLoads(const string &f) : func(f) {}

    vector<vector<Expr> > loads;
};

/** Rename all free variables to unique new names. */
class RenameFreeVars : public IRMutator {
    using IRMutator::visit;

    map<string, string> new_names;

    void visit(const Variable *op) {
        if (!op->param.defined() && !op->image.defined()) {
            expr = Variable::make(op->type, get_new_name(op->name));
        } else {
            expr = op;
        }
    }

public:
    string get_new_name(const string &s) {
        map<string, string>::iterator iter = new_names.find(s);
        if (iter != new_names.end()) {
            return iter->second;
        } else {
            string new_name = s + "$_";
            new_names[s] = new_name;
            return new_name;
        }

    }

};

bool can_parallelize_rvar(const string &v,
                          const string &f,
                          const ReductionDefinition &r) {
    FindLoads find(f);
    for (size_t i = 0; i < r.values.size(); i++) {
        r.values[i].accept(&find);
    }

    // Make an expr representing the store done by a different thread.
    RenameFreeVars renamer;
    vector<Expr> other_store(r.args.size());
    for (size_t i = 0; i < r.args.size(); i++) {
        other_store[i] = renamer.mutate(r.args[i]);
    }

    // Construct an expression which is true when the two threads are
    // in fact two different threads. We'll use this liberally in the
    // following conditions to give the simplifier the best chance.
    Expr distinct_v = (Variable::make(Int(32), v) !=
                       Variable::make(Int(32), renamer.get_new_name(v)));

    // Construct an expression which is true if there's a collision
    // between this thread's store and the other thread's store.
    Expr hazard = const_true();
    for (size_t i = 0; i < r.args.size(); i++) {
        hazard = hazard && (distinct_v && (r.args[i] == other_store[i]));
    }

    // Add expressions that are true if there's a collision between
    // the other thread's store and this thread's loads.
    for (size_t i = 0; i < find.loads.size(); i++) {
        internal_assert(find.loads[i].size() == other_store.size());
        Expr check = const_true();
        for (size_t j = 0; j < find.loads[i].size(); j++) {
            check = check && (distinct_v && (find.loads[i][j] == other_store[j]));
        }
        hazard = hazard || check;
    }

    // Make a scope representing the bounds of the reduction domain
    Scope<Interval> bounds;
    if (r.domain.defined()) {
        for (size_t i = 0; i < r.domain.domain().size(); i++) {
            const ReductionVariable &rv = r.domain.domain()[i];
            Interval in = Interval(rv.min, simplify(rv.min + rv.extent - 1));
            bounds.push(rv.var, in);
            bounds.push(renamer.get_new_name(rv.var), in);
        }
    }

    debug(3) << "Attempting to falsify: " << hazard << "\n";
    hazard = simplify(hazard, false, bounds);
    debug(3) << "Simplified to: " << hazard << "\n";

    return is_zero(hazard);
}

}
}
<|endoftext|>


<commit_before>#include "Points/Savers.hh"
#include <fstream>

PolylinePloterSaver::PolylinePloterSaver()
: in(this)
, filename_input(this)
{
  name = "PolylinePloterSaver";
  filename_input.connect(filename_manual);
}

void PolylinePloterSaver::compute()
{
  logger.log(Logger::Level::Verbose)<<"Filename: "<<filename_input.get_data();

  std::ofstream out;
  out.open(filename_input.get_data());
  if (!out.is_open())
  {
    logger.log(Logger::Level::Error)<<"Could not save the file! "<<filename_input.get_data();
    return;
  }

  auto& input = in.get_data();
  sf::Vector2f size = sf::Vector2f(input.size)/(float)input.scale;

  logger.log(Logger::Level::Verbose)<<"Number of points saved: "<<input.pts.size();

  for (auto e : input.pts)
  {
    e-=size/2.f;
    e/=(float)input.scale;
    out<<(int)e.x<<" "<<(int)e.y<<"\n";
  }

  out.close();
}

PolylineGcodeSaver::PolylineGcodeSaver()
: in(this)
, filename_input(this)
{
  name = "PolylineGcodeSaver";
  filename_input.connect(filename_manual);
}

void PolylineGcodeSaver::compute()
{
  logger.log(Logger::Level::Verbose)<<"Filename: "<<filename_input.get_data();

  std::ofstream out;
  out.open(filename_input.get_data());
  if (!out.is_open())
  {
    logger.log(Logger::Level::Error)<<"Could not save the file! "<<filename_input.get_data();
    return;
  }

  auto& input = in.get_data();
  logger.log(Logger::Level::Verbose)<<"Number of points saved: "<<input.pts.size();

  out<<"m107\n";
  out<<"g1 f700.00\n";
  out<<"g90\n";
  for (auto e : input.pts)
  {
    e/=(float)input.scale*10.f;
    out<<"g1 x"<<e.x<<" y"<<e.y<<"\n";
  }
  out<<"m106\n";

  out.close();
}

PolylineSVGSaver::PolylineSVGSaver()
: in(this)
, filename_input(this)
{
  name = "PolylineSVGSaver";
  filename_input.connect(filename_manual);
}

void PolylineSVGSaver::compute()
{
  logger.log(Logger::Level::Verbose)<<"Filename: "<<filename_input.get_data();

  std::ofstream out;
  out.open(filename_input.get_data());
  if (!out.is_open())
  {
    logger.log(Logger::Level::Error)<<"Could not save the file! "<<filename_input.get_data();
    return;
  }

  auto& input = in.get_data();
  sf::Vector2f size = sf::Vector2f(input.size)/(float)input.scale;
  auto start = input.pts[0]/(float)(10.f*input.scale);

  logger.log(Logger::Level::Verbose)<<"Number of points saved: "<<input.pts.size();

  out
    << "<?xml version=\"1.0\" standalone=\"no\"?>\n"
    << "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n"
    << "\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n"
    << "<svg height=\""<<size.y/10.f<<"mm\" width=\""<<size.x/10.f<<"mm\" "
    << "xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" "
    << "viewBox=\"0 0 "<<size.x/10.f<<" "<<size.y/10.f<<"\""<<">\n"
    << "<path d=\"M "<<start.x<<" "<<start.y<<"\n";

  for (size_t i=0; i<input.pts.size(); i++)
  {
    auto cur = input.pts[i]/(float)(10.f*input.scale);
    auto nxt = input.pts[std::min((size_t)i+1, input.pts.size()-1)]/(float)(10.f*input.scale);
    nxt = (nxt+cur)/2.f;
    out<<"Q "<<cur.x<<" "<<cur.y<<", "<<nxt.x<<" "<<nxt.y<<"\n";
    if (i%1000 == 0)
    {
      out<< "\" fill=\"none\" stroke=\"black\" stroke-width=\"0.4\"/>";
      out<< "<path d=\"M "<<nxt.x<<" "<<nxt.y<<"\n";
    }
  }

  out<< "\" fill=\"none\" stroke=\"black\" stroke-width=\"0.4\"/></svg>\n";

  out.close();
}
<commit_msg>fixed the gcode<commit_after>#include "Points/Savers.hh"
#include <fstream>

PolylinePloterSaver::PolylinePloterSaver()
: in(this)
, filename_input(this)
{
  name = "PolylinePloterSaver";
  filename_input.connect(filename_manual);
}

void PolylinePloterSaver::compute()
{
  logger.log(Logger::Level::Verbose)<<"Filename: "<<filename_input.get_data();

  std::ofstream out;
  out.open(filename_input.get_data());
  if (!out.is_open())
  {
    logger.log(Logger::Level::Error)<<"Could not save the file! "<<filename_input.get_data();
    return;
  }

  auto& input = in.get_data();
  sf::Vector2f size = sf::Vector2f(input.size)/(float)input.scale;

  logger.log(Logger::Level::Verbose)<<"Number of points saved: "<<input.pts.size();

  for (auto e : input.pts)
  {
    e-=size/2.f;
    e/=(float)input.scale;
    out<<(int)e.x<<" "<<(int)e.y<<"\n";
  }

  out.close();
}

PolylineGcodeSaver::PolylineGcodeSaver()
: in(this)
, filename_input(this)
{
  name = "PolylineGcodeSaver";
  filename_input.connect(filename_manual);
}

void PolylineGcodeSaver::compute()
{
  logger.log(Logger::Level::Verbose)<<"Filename: "<<filename_input.get_data();

  std::ofstream out;
  out.open(filename_input.get_data());
  if (!out.is_open())
  {
    logger.log(Logger::Level::Error)<<"Could not save the file! "<<filename_input.get_data();
    return;
  }

  auto& input = in.get_data();
  logger.log(Logger::Level::Verbose)<<"Number of points saved: "<<input.pts.size();

  out<<"M107\n";
  out<<"G90\n";
  out<<"G21\n";
  out<<"G1 f700.00\n";
  out<<"G4 P0\n";
  for (auto e : input.pts)
  {
    e/=(float)input.scale*10.f;
    out<<"G1 x"<<e.x<<" y"<<e.y<<"\n";
  }
  out<<"M106\n";

  out.close();
}

PolylineSVGSaver::PolylineSVGSaver()
: in(this)
, filename_input(this)
{
  name = "PolylineSVGSaver";
  filename_input.connect(filename_manual);
}

void PolylineSVGSaver::compute()
{
  logger.log(Logger::Level::Verbose)<<"Filename: "<<filename_input.get_data();

  std::ofstream out;
  out.open(filename_input.get_data());
  if (!out.is_open())
  {
    logger.log(Logger::Level::Error)<<"Could not save the file! "<<filename_input.get_data();
    return;
  }

  auto& input = in.get_data();
  sf::Vector2f size = sf::Vector2f(input.size)/(float)input.scale;
  auto start = input.pts[0]/(float)(10.f*input.scale);

  logger.log(Logger::Level::Verbose)<<"Number of points saved: "<<input.pts.size();

  out
    << "<?xml version=\"1.0\" standalone=\"no\"?>\n"
    << "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n"
    << "\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n"
    << "<svg height=\""<<size.y/10.f<<"mm\" width=\""<<size.x/10.f<<"mm\" "
    << "xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" "
    << "viewBox=\"0 0 "<<size.x/10.f<<" "<<size.y/10.f<<"\""<<">\n"
    << "<path d=\"M "<<start.x<<" "<<start.y<<"\n";

  for (size_t i=0; i<input.pts.size(); i++)
  {
    auto cur = input.pts[i]/(float)(10.f*input.scale);
    auto nxt = input.pts[std::min((size_t)i+1, input.pts.size()-1)]/(float)(10.f*input.scale);
    nxt = (nxt+cur)/2.f;
    out<<"Q "<<cur.x<<" "<<cur.y<<", "<<nxt.x<<" "<<nxt.y<<"\n";
    if (i%1000 == 0)
    {
      out<< "\" fill=\"none\" stroke=\"black\" stroke-width=\"0.4\"/>";
      out<< "<path d=\"M "<<nxt.x<<" "<<nxt.y<<"\n";
    }
  }

  out<< "\" fill=\"none\" stroke=\"black\" stroke-width=\"0.4\"/></svg>\n";

  out.close();
}
<|endoftext|>


<commit_before>//
//  ScatterPlots.cpp
//  PlaySPLOM
//
//  Created by Chris Sattinger on 12/10/15.
//  Copyright 2015 Chris Sattinger
//
//

#include "ScatterPlots.hpp"
#include <vector>
#include <set>
#include "ofMain.h"
#include "mapping.hpp"

void ScatterPlots::draw() {
    // always set color to white before drawing an FBO to main
    ofSetColor(255, 255, 255);
    plotterFbo.draw(0, 0);

    if (!brush.hoveringBox.isIdentityBox()) {
        ofPushMatrix();
        // unflip opengl so that origin is bottom left, going up
        glTranslated(0, plotterFbo.getHeight(), 0);
        glScalef(1, -1, 1);
        {
            // hovering box
            if (!brush.hoveringBox.isNull()) {
                ofNoFill();
                auto boxFrame = boxFrameAt(brush.hoveringBox);
                ofSetColor(brush.engaged ? engagedFrameColor : hoverFrameColor);
                ofDrawRectangle(boxFrame);
                auto counterPartFrame = boxFrameAt(brush.hoveringBox.n, brush.hoveringBox.m);
                ofDrawRectangle(counterPartFrame);
                // fill the two identity boxes dark with white label
                if (brush.engaged) {
                    ofFill();
                    ofSetColor(inverseBoxColor);
                    auto boxM = boxFrameAt(brush.hoveringBox.m, brush.hoveringBox.m);
                    ofDrawRectangle(boxM);
                    auto boxN = boxFrameAt(brush.hoveringBox.n, brush.hoveringBox.n);
                    ofDrawRectangle(boxN);
                    // labels
                    ofSetColor(inverseTextColor);
                    ofDrawBitmapString(titles[brush.hoveringBox.m], boxM.x + gutter, boxM.y + boxFrame.height / 2);
                    ofDrawBitmapString(titles[brush.hoveringBox.n], boxN.x + gutter, boxN.y + boxFrame.height / 2);
                }
            }
            brush.draw();
            highlightPoints(brush.pointsUnderBrush,
                            brush.engaged ? engagedBrushColor : hoverPointColor,
                            brush.engaged);
        }
        ofPopMatrix();
    }
}

void ScatterPlots::redrawPlotter() {
    plotterFbo.begin();
    ofClear(plotterBackground.r, plotterBackground.b, plotterBackground.g, plotterBackground.a);

    ofPushMatrix();
    ofPushStyle();
    {
        // unflip opengl so that origin is bottom left, going up
        glTranslated(0, plotterFbo.getHeight(), 0);
        glScalef(1, -1, 1);

        ofSetCircleResolution(pointRadius * 4);
        // auto&& access by reference
        for (auto &box : boxes) {
            if (box.m != box.n) {
              // border
              ofSetColor(borderColor);
              ofNoFill();
              ofDrawRectangle(box.frame);

              ofSetColor(pointColor);
              ofFill();
              ofPushMatrix(); {
                  ofTranslate(box.frame.x, box.frame.y);
                  for (auto &point : box.points) {
                      ofDrawCircle(
                                   point.x * box.frame.width,
                                   point.y * box.frame.height,
                                   pointRadius);
                  }
                  // label each combo box (temporary)
                  char label[20];
                  snprintf(label, sizeof(label), "%d,%d", box.m, box.n);
                  ofSetColor(labelColor);
                  ofDrawBitmapString(label, gutter, gutter);
              } ofPopMatrix();
            } else {
                // identity box: draw the label
                ofSetColor(labelColor);
                ofPushMatrix();
                ofTranslate(box.frame.x, box.frame.y);
                ofDrawBitmapString(titles[box.m], gutter, box.frame.height / 2);
                ofPopMatrix();
            }
        }
    }
    ofPopStyle();
    ofPopMatrix();
    plotterFbo.end();
}

void ScatterPlots::highlightPoints(const set<int> &points, const ofColor &color, bool fill) {
    ofSetColor(color);
    if (fill) {
        ofFill();
    } else {
        ofNoFill();
    }
    ofSetCircleResolution(pointRadius * 4);
    for (auto &box : boxes) {
        if (box.m != box.n) {
            ofPushMatrix(); {
                ofTranslate(box.frame.x, box.frame.y);
                for (auto p : points) {
                    ofDrawCircle(
                                 box.points[p].x * box.frame.width,
                                 box.points[p].y * box.frame.height,
                                 pointRadius);
                }
            } ofPopMatrix();
        }
    }
}

void ScatterPlots::setFrame(ofRectangle rect) {
    frame = rect;
    updateBoxSizes();
    if (plotterFbo.isAllocated()) {
        plotterFbo.clear();
    }
    plotterFbo.allocate(rect.width, rect.height, GL_RGBA);  // 32F_ARB
    redrawPlotter();
}

void ScatterPlots::updateBoxSizes() {
    if (numDimensions > 0) {
        boxWidth = (frame.width - gutter) / numDimensions;
        boxHeight = (frame.height - gutter) / numDimensions;
    } else {
        boxWidth = frame.width - gutter;
        boxHeight = frame.height - gutter;
    }
    if (boxWidth < boxHeight) {
        boxHeight = boxWidth;
    } else {
        boxWidth = boxHeight;
    }
    // center them in the frame
    auto leftMargin = (frame.width -  (boxWidth * numDimensions)) / 2;
    // and move them up the top
    auto bottomMargin = (frame.height -  (boxHeight * numDimensions));
    for (auto &box : boxes) {
        box.frame.x = box.m * boxWidth + gutter + leftMargin;
        box.frame.y = (numDimensions - box.n - 1) * boxHeight + bottomMargin;
        box.frame.width = boxWidth - gutter;
        box.frame.height = boxHeight - gutter;
    }
}

void ScatterPlots::setData(const DataSource& dataSource) {
    numDimensions = dataSource.numDimensions;
    boxes.clear();
    titles = dataSource.titles;

    // create boxes with normalized point sets
    for (int m = 0; m < numDimensions; m++) {
        for (int n = 0; n < numDimensions; n++) {
            Box box = Box(m, n);
            for (auto point : dataSource.points) {
                auto x = linlin(point[m],
                  dataSource.mins[m],
                  dataSource.maxes[m]);
                auto y = linlin(point[n],
                  dataSource.mins[n],
                  dataSource.maxes[n]);
                ofPoint normalizedPoint = ofPoint(x, y);
                box.points.push_back(normalizedPoint);
            }
            boxes.push_back(box);
        }
    }
    updateBoxSizes();
    redrawPlotter();
}

BoxCoordinates ScatterPlots::boxForPoint(int x, int y) {
    // TODO(crucialfelix): calculate don't iterate
    for (auto box : boxes) {
        if (box.frame.inside(x, y)) {
            return BoxCoordinates(box.m, box.n);
        }
    }
    // null
    return BoxCoordinates();
}

ofRectangle ScatterPlots::boxFrameAt(const BoxCoordinates &coords) {
    // TODO(crucialfelix): use a map
    for (auto box : boxes) {
        if (box.m == coords.m && box.n == coords.n) {
            return box.frame;
        }
    }
    return ofRectangle();
}

ofRectangle ScatterPlots::boxFrameAt(int m, int n) {
    // TODO(crucialfelix): use a map
    for (auto box : boxes) {
        if (box.m == m && box.n == n) {
            return box.frame;
        }
    }
    return ofRectangle();
}

vector<ofPoint> ScatterPlots::normalizedPointsAtBox(const BoxCoordinates &coords) {
    // TODO(crucialfelix): use a map
    for (auto box : boxes) {
        if (box.m == coords.m && box.n == coords.n) {
            return box.points;
        }
    }
    // empty set
    return vector<ofPoint>();
}
<commit_msg>push/pop style so the noFill doesn't infect datGui drawing<commit_after>//
//  ScatterPlots.cpp
//  PlaySPLOM
//
//  Created by Chris Sattinger on 12/10/15.
//  Copyright 2015 Chris Sattinger
//

#include "ScatterPlots.hpp"
#include <vector>
#include <set>
#include "ofMain.h"
#include "mapping.hpp"

void ScatterPlots::draw() {
    // always set color to white before drawing an FBO to main
    ofSetColor(255, 255, 255);
    plotterFbo.draw(0, 0);

    if (!brush.hoveringBox.isIdentityBox()) {
        ofPushMatrix();
        ofPushStyle();
        // unflip opengl so that origin is bottom left, going up
        glTranslated(0, plotterFbo.getHeight(), 0);
        glScalef(1, -1, 1);
        {
            // hovering box
            if (!brush.hoveringBox.isNull()) {
                ofNoFill();
                auto boxFrame = boxFrameAt(brush.hoveringBox);
                ofSetColor(brush.engaged ? engagedFrameColor : hoverFrameColor);
                ofDrawRectangle(boxFrame);
                auto counterPartFrame = boxFrameAt(brush.hoveringBox.n, brush.hoveringBox.m);
                ofDrawRectangle(counterPartFrame);
                // fill the two identity boxes dark with white label
                if (brush.engaged) {
                    ofFill();
                    ofSetColor(inverseBoxColor);
                    auto boxM = boxFrameAt(brush.hoveringBox.m, brush.hoveringBox.m);
                    ofDrawRectangle(boxM);
                    auto boxN = boxFrameAt(brush.hoveringBox.n, brush.hoveringBox.n);
                    ofDrawRectangle(boxN);
                    // labels
                    ofSetColor(inverseTextColor);
                    ofDrawBitmapString(titles[brush.hoveringBox.m], boxM.x + gutter, boxM.y + boxFrame.height / 2);
                    ofDrawBitmapString(titles[brush.hoveringBox.n], boxN.x + gutter, boxN.y + boxFrame.height / 2);
                }
            }
            brush.draw();
            highlightPoints(brush.pointsUnderBrush,
                            brush.engaged ? engagedBrushColor : hoverPointColor,
                            brush.engaged);
        }
        ofPopStyle();
        ofPopMatrix();
    }
}

void ScatterPlots::redrawPlotter() {
    plotterFbo.begin();
    ofClear(plotterBackground.r, plotterBackground.b, plotterBackground.g, plotterBackground.a);

    ofPushMatrix();
    ofPushStyle();
    {
        // unflip opengl so that origin is bottom left, going up
        glTranslated(0, plotterFbo.getHeight(), 0);
        glScalef(1, -1, 1);

        ofSetCircleResolution(pointRadius * 4);
        // auto&& access by reference
        for (auto &box : boxes) {
            if (box.m != box.n) {
              // border
              ofSetColor(borderColor);
              ofNoFill();
              ofDrawRectangle(box.frame);

              ofSetColor(pointColor);
              ofFill();
              ofPushMatrix(); {
                  ofTranslate(box.frame.x, box.frame.y);
                  for (auto &point : box.points) {
                      ofDrawCircle(
                                   point.x * box.frame.width,
                                   point.y * box.frame.height,
                                   pointRadius);
                  }
                  // label each combo box (temporary)
                  char label[20];
                  snprintf(label, sizeof(label), "%d,%d", box.m, box.n);
                  ofSetColor(labelColor);
                  ofDrawBitmapString(label, gutter, gutter);
              } ofPopMatrix();
            } else {
                // identity box: draw the label
                ofSetColor(labelColor);
                ofPushMatrix();
                ofTranslate(box.frame.x, box.frame.y);
                ofDrawBitmapString(titles[box.m], gutter, box.frame.height / 2);
                ofPopMatrix();
            }
        }
    }
    ofPopStyle();
    ofPopMatrix();
    plotterFbo.end();
}

void ScatterPlots::highlightPoints(const set<int> &points, const ofColor &color, bool fill) {
    ofPushStyle();
    ofSetColor(color);
    if (fill) {
        ofFill();
    } else {
        ofNoFill();
    }
    ofSetCircleResolution(pointRadius * 4);
    for (auto &box : boxes) {
        if (box.m != box.n) {
            ofPushMatrix(); {
                ofTranslate(box.frame.x, box.frame.y);
                for (auto p : points) {
                    ofDrawCircle(
                                 box.points[p].x * box.frame.width,
                                 box.points[p].y * box.frame.height,
                                 pointRadius);
                }
            } ofPopMatrix();
        }
    }
    ofPopStyle();
}

void ScatterPlots::setFrame(ofRectangle rect) {
    frame = rect;
    updateBoxSizes();
    if (plotterFbo.isAllocated()) {
        plotterFbo.clear();
    }
    plotterFbo.allocate(rect.width, rect.height, GL_RGBA);  // 32F_ARB
    redrawPlotter();
}

void ScatterPlots::updateBoxSizes() {
    if (numDimensions > 0) {
        boxWidth = (frame.width - gutter) / numDimensions;
        boxHeight = (frame.height - gutter) / numDimensions;
    } else {
        boxWidth = frame.width - gutter;
        boxHeight = frame.height - gutter;
    }
    if (boxWidth < boxHeight) {
        boxHeight = boxWidth;
    } else {
        boxWidth = boxHeight;
    }
    // center them in the frame
    auto leftMargin = (frame.width -  (boxWidth * numDimensions)) / 2;
    // and move them up the top
    auto bottomMargin = (frame.height -  (boxHeight * numDimensions));
    for (auto &box : boxes) {
        box.frame.x = box.m * boxWidth + gutter + leftMargin;
        box.frame.y = (numDimensions - box.n - 1) * boxHeight + bottomMargin;
        box.frame.width = boxWidth - gutter;
        box.frame.height = boxHeight - gutter;
    }
}

void ScatterPlots::setData(const DataSource& dataSource) {
    numDimensions = dataSource.numDimensions;
    boxes.clear();
    titles = dataSource.titles;

    // create boxes with normalized point sets
    for (int m = 0; m < numDimensions; m++) {
        for (int n = 0; n < numDimensions; n++) {
            Box box = Box(m, n);
            for (auto point : dataSource.points) {
                auto x = linlin(point[m],
                  dataSource.mins[m],
                  dataSource.maxes[m]);
                auto y = linlin(point[n],
                  dataSource.mins[n],
                  dataSource.maxes[n]);
                ofPoint normalizedPoint = ofPoint(x, y);
                box.points.push_back(normalizedPoint);
            }
            boxes.push_back(box);
        }
    }
    updateBoxSizes();
    redrawPlotter();
}

BoxCoordinates ScatterPlots::boxForPoint(int x, int y) {
    // TODO(crucialfelix): calculate don't iterate
    for (auto box : boxes) {
        if (box.frame.inside(x, y)) {
            return BoxCoordinates(box.m, box.n);
        }
    }
    // null
    return BoxCoordinates();
}

ofRectangle ScatterPlots::boxFrameAt(const BoxCoordinates &coords) {
    // TODO(crucialfelix): use a map
    for (auto box : boxes) {
        if (box.m == coords.m && box.n == coords.n) {
            return box.frame;
        }
    }
    return ofRectangle();
}

ofRectangle ScatterPlots::boxFrameAt(int m, int n) {
    // TODO(crucialfelix): use a map
    for (auto box : boxes) {
        if (box.m == m && box.n == n) {
            return box.frame;
        }
    }
    return ofRectangle();
}

vector<ofPoint> ScatterPlots::normalizedPointsAtBox(const BoxCoordinates &coords) {
    // TODO(crucialfelix): use a map
    for (auto box : boxes) {
        if (box.m == coords.m && box.n == coords.n) {
            return box.points;
        }
    }
    // empty set
    return vector<ofPoint>();
}
<|endoftext|>


<commit_before>/**
 * The Seeks proxy and plugin framework are part of the SEEKS project.
 * Copyright (C) 2009 Emmanuel Benazera, juban@free.fr
 *
 * 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 "plugin.h"
#include "mem_utils.h"
#include "interceptor_plugin.h"
#include "action_plugin.h"
#include "filter_plugin.h"
#include "plugin_manager.h" // to get access to the factory.
#include "errlog.h"
#include "urlmatch.h"
#include "loaders.h"
#include "miscutil.h"

namespace sp
{
  plugin::plugin()
      :_interceptor_plugin(NULL),_action_plugin(NULL),_filter_plugin(NULL)
  {
  }

  plugin::plugin(const std::string &config_filename)
      : _config_filename(config_filename),
      _interceptor_plugin(NULL),_action_plugin(NULL),
      _filter_plugin(NULL)
  {
  }

  plugin::~plugin()
  {
    if (_interceptor_plugin)
      delete _interceptor_plugin;
    if (_action_plugin)
      delete _action_plugin;
    if (_filter_plugin)
      delete _filter_plugin;

    for (size_t i=0; i<_cgi_dispatchers.size(); i++)
      delete _cgi_dispatchers.at(i);

    if (_configuration)
      delete _configuration;
  }

  std::string plugin::print() const
  {
    std::string res,s;
    if (_interceptor_plugin)
      res = _interceptor_plugin->print();
    if (_action_plugin)
      res += _action_plugin->print();
    if (_filter_plugin)
      res += _filter_plugin->print();
    return res;
  }

} /* end of namespace. */
<commit_msg>fixed configuration initialization in high level plugin class<commit_after>/**
 * The Seeks proxy and plugin framework are part of the SEEKS project.
 * Copyright (C) 2009 Emmanuel Benazera, juban@free.fr
 *
 * 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 "plugin.h"
#include "mem_utils.h"
#include "interceptor_plugin.h"
#include "action_plugin.h"
#include "filter_plugin.h"
#include "plugin_manager.h" // to get access to the factory.
#include "errlog.h"
#include "urlmatch.h"
#include "loaders.h"
#include "miscutil.h"

namespace sp
{
  plugin::plugin()
    :_configuration(NULL),_interceptor_plugin(NULL),_action_plugin(NULL),_filter_plugin(NULL)
  {
  }

  plugin::plugin(const std::string &config_filename)
    : _config_filename(config_filename),_configuration(NULL),
      _interceptor_plugin(NULL),_action_plugin(NULL),
      _filter_plugin(NULL)
  {
  }

  plugin::~plugin()
  {
    if (_interceptor_plugin)
      delete _interceptor_plugin;
    if (_action_plugin)
      delete _action_plugin;
    if (_filter_plugin)
      delete _filter_plugin;

    for (size_t i=0; i<_cgi_dispatchers.size(); i++)
      delete _cgi_dispatchers.at(i);

    if (_configuration)
      delete _configuration;
  }

  std::string plugin::print() const
  {
    std::string res,s;
    if (_interceptor_plugin)
      res = _interceptor_plugin->print();
    if (_action_plugin)
      res += _action_plugin->print();
    if (_filter_plugin)
      res += _filter_plugin->print();
    return res;
  }

} /* end of namespace. */
<|endoftext|>


<commit_before>#include "HalideRuntime.h"

extern "C" {

#ifdef BITS_64
#define WIN32API
#else
#define WIN32API __stdcall
#endif

WIN32API void *LoadLibraryA(const char *);
WIN32API void *GetProcAddress(void *, const char *);
WIN32API unsigned SetErrorMode(unsigned);
#define SEM_FAILCRITICALERRORS 0x0001
#define SEM_NOOPENFILEERRORBOX 0x8000

}  // extern "C"

namespace Halide { namespace Runtime { namespace Internal {

WEAK void *halide_get_symbol_impl(const char *name) {
    return GetProcAddress(NULL, name);
}

WEAK void *halide_load_library_impl(const char *name) {
    // Suppress dialogoe windows during library open.
    unsigned oldMode = SetErrorMode(0);
    SetErrorMode(oldMode | SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
    void * Lib = LoadLibraryA(name);
    SetErrorMode(oldMode);
    return Lib;
}

WEAK void *halide_get_library_symbol_impl(void *lib, const char *name) {
    return GetProcAddress(lib, name);
}

WEAK halide_get_symbol_t custom_get_symbol = halide_get_symbol_impl;
WEAK halide_load_library_t custom_load_library = halide_load_library_impl;
WEAK halide_get_library_symbol_t custom_get_library_symbol = halide_get_library_symbol_impl;

}}} // namespace Halide::Runtime::Internal

extern "C" {

WEAK halide_get_symbol_t halide_set_custom_get_symbol(halide_get_symbol_t f) {
    halide_get_symbol_t result = custom_get_symbol;
    custom_get_symbol = f;
    return result;
}

WEAK halide_load_library_t halide_set_custom_load_library(halide_load_library_t f) {
    halide_load_library_t result = custom_load_library;
    custom_load_library = f;
    return result;
}

WEAK halide_get_library_symbol_t halide_set_custom_get_library_symbol(halide_get_library_symbol_t f) {
    halide_get_library_symbol_t result = custom_get_library_symbol;
    custom_get_library_symbol = f;
    return result;
}

WEAK void *halide_get_symbol(const char *name) {
    return custom_get_symbol(name);
}

WEAK void *halide_load_library(const char *name) {
    return custom_load_library(name);
}

WEAK void *halide_get_library_symbol(void *lib, const char *name) {
    return custom_get_library_symbol(lib, name);
}

}  // extern "C"
<commit_msg>review comments<commit_after>#include "HalideRuntime.h"

extern "C" {

#ifdef BITS_64
#define WIN32API
#else
#define WIN32API __stdcall
#endif

WIN32API void *LoadLibraryA(const char *);
WIN32API void *GetProcAddress(void *, const char *);
WIN32API unsigned SetErrorMode(unsigned);
#define SEM_FAILCRITICALERRORS 0x0001
#define SEM_NOOPENFILEERRORBOX 0x8000

}  // extern "C"

namespace Halide { namespace Runtime { namespace Internal {

WEAK void *halide_get_symbol_impl(const char *name) {
    return GetProcAddress(NULL, name);
}

WEAK void *halide_load_library_impl(const char *name) {
    // Suppress dialog windows during library open.
    unsigned old_mode = SetErrorMode(0);
    SetErrorMode(old_mode | SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
    void *lib = LoadLibraryA(name);
    SetErrorMode(old_mode);
    return lib;
}

WEAK void *halide_get_library_symbol_impl(void *lib, const char *name) {
    return GetProcAddress(lib, name);
}

WEAK halide_get_symbol_t custom_get_symbol = halide_get_symbol_impl;
WEAK halide_load_library_t custom_load_library = halide_load_library_impl;
WEAK halide_get_library_symbol_t custom_get_library_symbol = halide_get_library_symbol_impl;

}}} // namespace Halide::Runtime::Internal

extern "C" {

WEAK halide_get_symbol_t halide_set_custom_get_symbol(halide_get_symbol_t f) {
    halide_get_symbol_t result = custom_get_symbol;
    custom_get_symbol = f;
    return result;
}

WEAK halide_load_library_t halide_set_custom_load_library(halide_load_library_t f) {
    halide_load_library_t result = custom_load_library;
    custom_load_library = f;
    return result;
}

WEAK halide_get_library_symbol_t halide_set_custom_get_library_symbol(halide_get_library_symbol_t f) {
    halide_get_library_symbol_t result = custom_get_library_symbol;
    custom_get_library_symbol = f;
    return result;
}

WEAK void *halide_get_symbol(const char *name) {
    return custom_get_symbol(name);
}

WEAK void *halide_load_library(const char *name) {
    return custom_load_library(name);
}

WEAK void *halide_get_library_symbol(void *lib, const char *name) {
    return custom_get_library_symbol(lib, name);
}

}  // extern "C"
<|endoftext|>


<commit_before>// Copyright (c) 2010 Satoshi Nakamoto
// Copyright (c) 2009-2018 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <rpc/protocol.h>

#include <random.h>
#include <tinyformat.h>
#include <util.h>
#include <utilstrencodings.h>
#include <utiltime.h>
#include <version.h>

#include <fstream>

/**
 * JSON-RPC protocol.  Bitcoin speaks version 1.0 for maximum compatibility,
 * but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
 * unspecified (HTTP errors and contents of 'error').
 *
 * 1.0 spec: http://json-rpc.org/wiki/specification
 * 1.2 spec: http://jsonrpc.org/historical/json-rpc-over-http.html
 */

UniValue JSONRPCRequestObj(const std::string& strMethod, const UniValue& params, const UniValue& id)
{
    UniValue request(UniValue::VOBJ);
    request.pushKV("method", strMethod);
    request.pushKV("params", params);
    request.pushKV("id", id);
    return request;
}

UniValue JSONRPCReplyObj(const UniValue& result, const UniValue& error, const UniValue& id)
{
    UniValue reply(UniValue::VOBJ);
    if (!error.isNull())
        reply.pushKV("result", NullUniValue);
    else
        reply.pushKV("result", result);
    reply.pushKV("error", error);
    reply.pushKV("id", id);
    return reply;
}

std::string JSONRPCReply(const UniValue& result, const UniValue& error, const UniValue& id)
{
    UniValue reply = JSONRPCReplyObj(result, error, id);
    return reply.write() + "\n";
}

UniValue JSONRPCError(int code, const std::string& message)
{
    UniValue error(UniValue::VOBJ);
    error.pushKV("code", code);
    error.pushKV("message", message);
    return error;
}

/** Username used when cookie authentication is in use (arbitrary, only for
 * recognizability in debugging/logging purposes)
 */
static const std::string COOKIEAUTH_USER = "__cookie__";
/** Default name for auth cookie file */
static const std::string COOKIEAUTH_FILE = ".cookie";

/** Get name of RPC authentication cookie file */
static fs::path GetAuthCookieFile(bool temp=false)
{
    std::string arg = gArgs.GetArg("-rpccookiefile", COOKIEAUTH_FILE);
    if (temp) {
        arg += ".tmp";
    }
    return AbsPathForConfigVal(fs::path(arg));
}

bool GenerateAuthCookie(std::string *cookie_out)
{
    const size_t COOKIE_SIZE = 32;
    unsigned char rand_pwd[COOKIE_SIZE];
    GetRandBytes(rand_pwd, COOKIE_SIZE);
    std::string cookie = COOKIEAUTH_USER + ":" + HexStr(rand_pwd, rand_pwd+COOKIE_SIZE);

    /** the umask determines what permissions are used to create this file -
     * these are set to 077 in init.cpp unless overridden with -sysperms.
     */
    std::ofstream file;
    fs::path filepath_tmp = GetAuthCookieFile(true);
    file.open(filepath_tmp.string().c_str());
    if (!file.is_open()) {
        LogPrintf("Unable to open cookie authentication file %s for writing\n", filepath_tmp.string());
        return false;
    }
    file << cookie;
    file.close();

    fs::path filepath = GetAuthCookieFile(false);
    if (!RenameOver(filepath_tmp, filepath)) {
        LogPrintf("Unable to rename cookie authentication file %s to %s\n", filepath_tmp.string(), filepath.string());
        return false;
    }
    LogPrintf("Generated RPC authentication cookie %s\n", filepath.string());

    if (cookie_out)
        *cookie_out = cookie;
    return true;
}

bool GetAuthCookie(std::string *cookie_out)
{
    std::ifstream file;
    std::string cookie;
    fs::path filepath = GetAuthCookieFile();
    file.open(filepath.string().c_str());
    if (!file.is_open())
        return false;
    std::getline(file, cookie);
    file.close();

    if (cookie_out)
        *cookie_out = cookie;
    return true;
}

//
// ELEMENTS:

/** Default name for mainchain auth cookie file */
static const std::string MAINCHAIN_COOKIEAUTH_FILE = "regtest/.cookie";
/** Get name mainchain RPC authentication cookie file */
static fs::path GetMainchainAuthCookieFile()
{
    boost::filesystem::path path(gArgs.GetArg("-mainchainrpccookiefile", MAINCHAIN_COOKIEAUTH_FILE));
    if (!path.is_complete()) path = GetDataDir(false) / path;
    return path;
}

bool GetMainchainAuthCookie(std::string *cookie_out)
{
    std::ifstream file;
    std::string cookie;

    boost::filesystem::path filepath = GetMainchainAuthCookieFile();
    file.open(filepath.string().c_str());
    if (!file.is_open())
        return false;
    std::getline(file, cookie);
    file.close();

    if (cookie_out)
        *cookie_out = cookie;
    return true;
}

// END ELEMENTS
//

void DeleteAuthCookie()
{
    try {
        fs::remove(GetAuthCookieFile());
    } catch (const fs::filesystem_error& e) {
        LogPrintf("%s: Unable to remove random auth cookie file: %s\n", __func__, fsbridge::get_filesystem_error_message(e));
    }
}

std::vector<UniValue> JSONRPCProcessBatchReply(const UniValue &in, size_t num)
{
    if (!in.isArray()) {
        throw std::runtime_error("Batch must be an array");
    }
    std::vector<UniValue> batch(num);
    for (size_t i=0; i<in.size(); ++i) {
        const UniValue &rec = in[i];
        if (!rec.isObject()) {
            throw std::runtime_error("Batch member must be object");
        }
        size_t id = rec["id"].get_int();
        if (id >= num) {
            throw std::runtime_error("Batch member id larger than size");
        }
        batch[id] = rec;
    }
    return batch;
}
<commit_msg>Default to mainnet cookie for liquidv1<commit_after>// Copyright (c) 2010 Satoshi Nakamoto
// Copyright (c) 2009-2018 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <rpc/protocol.h>

#include <random.h>
#include <tinyformat.h>
#include <util.h>
#include <utilstrencodings.h>
#include <utiltime.h>
#include <version.h>

#include <fstream>

/**
 * JSON-RPC protocol.  Bitcoin speaks version 1.0 for maximum compatibility,
 * but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
 * unspecified (HTTP errors and contents of 'error').
 *
 * 1.0 spec: http://json-rpc.org/wiki/specification
 * 1.2 spec: http://jsonrpc.org/historical/json-rpc-over-http.html
 */

UniValue JSONRPCRequestObj(const std::string& strMethod, const UniValue& params, const UniValue& id)
{
    UniValue request(UniValue::VOBJ);
    request.pushKV("method", strMethod);
    request.pushKV("params", params);
    request.pushKV("id", id);
    return request;
}

UniValue JSONRPCReplyObj(const UniValue& result, const UniValue& error, const UniValue& id)
{
    UniValue reply(UniValue::VOBJ);
    if (!error.isNull())
        reply.pushKV("result", NullUniValue);
    else
        reply.pushKV("result", result);
    reply.pushKV("error", error);
    reply.pushKV("id", id);
    return reply;
}

std::string JSONRPCReply(const UniValue& result, const UniValue& error, const UniValue& id)
{
    UniValue reply = JSONRPCReplyObj(result, error, id);
    return reply.write() + "\n";
}

UniValue JSONRPCError(int code, const std::string& message)
{
    UniValue error(UniValue::VOBJ);
    error.pushKV("code", code);
    error.pushKV("message", message);
    return error;
}

/** Username used when cookie authentication is in use (arbitrary, only for
 * recognizability in debugging/logging purposes)
 */
static const std::string COOKIEAUTH_USER = "__cookie__";
/** Default name for auth cookie file */
static const std::string COOKIEAUTH_FILE = ".cookie";

/** Get name of RPC authentication cookie file */
static fs::path GetAuthCookieFile(bool temp=false)
{
    std::string arg = gArgs.GetArg("-rpccookiefile", COOKIEAUTH_FILE);
    if (temp) {
        arg += ".tmp";
    }
    return AbsPathForConfigVal(fs::path(arg));
}

bool GenerateAuthCookie(std::string *cookie_out)
{
    const size_t COOKIE_SIZE = 32;
    unsigned char rand_pwd[COOKIE_SIZE];
    GetRandBytes(rand_pwd, COOKIE_SIZE);
    std::string cookie = COOKIEAUTH_USER + ":" + HexStr(rand_pwd, rand_pwd+COOKIE_SIZE);

    /** the umask determines what permissions are used to create this file -
     * these are set to 077 in init.cpp unless overridden with -sysperms.
     */
    std::ofstream file;
    fs::path filepath_tmp = GetAuthCookieFile(true);
    file.open(filepath_tmp.string().c_str());
    if (!file.is_open()) {
        LogPrintf("Unable to open cookie authentication file %s for writing\n", filepath_tmp.string());
        return false;
    }
    file << cookie;
    file.close();

    fs::path filepath = GetAuthCookieFile(false);
    if (!RenameOver(filepath_tmp, filepath)) {
        LogPrintf("Unable to rename cookie authentication file %s to %s\n", filepath_tmp.string(), filepath.string());
        return false;
    }
    LogPrintf("Generated RPC authentication cookie %s\n", filepath.string());

    if (cookie_out)
        *cookie_out = cookie;
    return true;
}

bool GetAuthCookie(std::string *cookie_out)
{
    std::ifstream file;
    std::string cookie;
    fs::path filepath = GetAuthCookieFile();
    file.open(filepath.string().c_str());
    if (!file.is_open())
        return false;
    std::getline(file, cookie);
    file.close();

    if (cookie_out)
        *cookie_out = cookie;
    return true;
}

//
// ELEMENTS:

/** Default name for mainchain auth cookie file */
static const std::string MAINCHAIN_COOKIEAUTH_FILE = "regtest/.cookie";
/** Get name mainchain RPC authentication cookie file */
static fs::path GetMainchainAuthCookieFile()
{
    std::string cookie_file = MAINCHAIN_COOKIEAUTH_FILE;
    // Bitcoin mainnet exception
    if (gArgs.GetChainName() == "liquidv1") {
        cookie_file = ".cookie";
    }
    boost::filesystem::path path(gArgs.GetArg("-mainchainrpccookiefile", cookie_file));
    if (!path.is_complete()) path = GetDataDir(false) / path;
    return path;
}

bool GetMainchainAuthCookie(std::string *cookie_out)
{
    std::ifstream file;
    std::string cookie;

    boost::filesystem::path filepath = GetMainchainAuthCookieFile();
    file.open(filepath.string().c_str());
    if (!file.is_open())
        return false;
    std::getline(file, cookie);
    file.close();

    if (cookie_out)
        *cookie_out = cookie;
    return true;
}

// END ELEMENTS
//

void DeleteAuthCookie()
{
    try {
        fs::remove(GetAuthCookieFile());
    } catch (const fs::filesystem_error& e) {
        LogPrintf("%s: Unable to remove random auth cookie file: %s\n", __func__, fsbridge::get_filesystem_error_message(e));
    }
}

std::vector<UniValue> JSONRPCProcessBatchReply(const UniValue &in, size_t num)
{
    if (!in.isArray()) {
        throw std::runtime_error("Batch must be an array");
    }
    std::vector<UniValue> batch(num);
    for (size_t i=0; i<in.size(); ++i) {
        const UniValue &rec = in[i];
        if (!rec.isObject()) {
            throw std::runtime_error("Batch member must be object");
        }
        size_t id = rec["id"].get_int();
        if (id >= num) {
            throw std::runtime_error("Batch member id larger than size");
        }
        batch[id] = rec;
    }
    return batch;
}
<|endoftext|>