<commit_before>/**
 * pugixml parser - version 1.2
 * --------------------------------------------------------
 * Copyright (C) 2006-2012, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
 * Report bugs and download new versions at http://pugixml.org/
 *
 * This library is distributed under the MIT License. See notice at the end
 * of this file.
 *
 * This work is based on the pugxml parser, which is:
 * Copyright (C) 2003, by Kristen Wegner (kristen@tima.net)
 */

#ifndef HEADER_PUGICONFIG_HPP
#define HEADER_PUGICONFIG_HPP

// Uncomment this to enable wchar_t mode
// #define PUGIXML_WCHAR_MODE

// Uncomment this to disable XPath
// #define PUGIXML_NO_XPATH

// Uncomment this to disable STL
// #define PUGIXML_NO_STL

// Uncomment this to disable exceptions
// #define PUGIXML_NO_EXCEPTIONS

// Set this to control attributes for public classes/functions, i.e.:
// #define PUGIXML_API __declspec(dllexport) // to export all public symbols from DLL
// #define PUGIXML_CLASS __declspec(dllimport) // to import all classes from DLL
// #define PUGIXML_FUNCTION __fastcall // to set calling conventions to all public functions to fastcall
// In absence of PUGIXML_CLASS/PUGIXML_FUNCTION definitions PUGIXML_API is used instead

// Uncomment this to switch to header-only version
// #define PUGIXML_HEADER_ONLY
// #include "pugixml.cpp"

// Tune these constants to adjust memory-related behavior
// #define PUGIXML_MEMORY_PAGE_SIZE 32768
// #define PUGIXML_MEMORY_OUTPUT_STACK 10240
// #define PUGIXML_MEMORY_XPATH_PAGE_SIZE 4096

#endif

/**
 * Copyright (c) 2006-2012 Arseny Kapoulkine
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */
<commit_msg>Fix PUGIXML_MEMORY_* constants for header-only mode<commit_after>/**
 * pugixml parser - version 1.2
 * --------------------------------------------------------
 * Copyright (C) 2006-2012, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
 * Report bugs and download new versions at http://pugixml.org/
 *
 * This library is distributed under the MIT License. See notice at the end
 * of this file.
 *
 * This work is based on the pugxml parser, which is:
 * Copyright (C) 2003, by Kristen Wegner (kristen@tima.net)
 */

#ifndef HEADER_PUGICONFIG_HPP
#define HEADER_PUGICONFIG_HPP

// Uncomment this to enable wchar_t mode
// #define PUGIXML_WCHAR_MODE

// Uncomment this to disable XPath
// #define PUGIXML_NO_XPATH

// Uncomment this to disable STL
// #define PUGIXML_NO_STL

// Uncomment this to disable exceptions
// #define PUGIXML_NO_EXCEPTIONS

// Set this to control attributes for public classes/functions, i.e.:
// #define PUGIXML_API __declspec(dllexport) // to export all public symbols from DLL
// #define PUGIXML_CLASS __declspec(dllimport) // to import all classes from DLL
// #define PUGIXML_FUNCTION __fastcall // to set calling conventions to all public functions to fastcall
// In absence of PUGIXML_CLASS/PUGIXML_FUNCTION definitions PUGIXML_API is used instead

// Tune these constants to adjust memory-related behavior
// #define PUGIXML_MEMORY_PAGE_SIZE 32768
// #define PUGIXML_MEMORY_OUTPUT_STACK 10240
// #define PUGIXML_MEMORY_XPATH_PAGE_SIZE 4096

// Uncomment this to switch to header-only version
// #define PUGIXML_HEADER_ONLY
// #include "pugixml.cpp"

#endif

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


<commit_before>#include "guiutil.h"
#include "bitcoinaddressvalidator.h"
#include "walletmodel.h"
#include "bitcoinunits.h"
#include "util.h"
#include "init.h"

#include <QString>
#include <QDateTime>
#include <QDoubleValidator>
#include <QFont>
#include <QLineEdit>
#include <QUrl>
#include <QTextDocument> // For Qt::escape
#include <QAbstractItemView>
#include <QApplication>
#include <QClipboard>
#include <QFileDialog>
#include <QDesktopServices>
#include <QThread>

#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>

#ifdef WIN32
#ifdef _WIN32_WINNT
#undef _WIN32_WINNT
#endif
#define _WIN32_WINNT 0x0501
#ifdef _WIN32_IE
#undef _WIN32_IE
#endif
#define _WIN32_IE 0x0501
#define WIN32_LEAN_AND_MEAN 1
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include "shlwapi.h"
#include "shlobj.h"
#include "shellapi.h"
#endif

namespace GUIUtil {

QString dateTimeStr(const QDateTime &date)
{
    return date.date().toString(Qt::SystemLocaleShortDate) + QString(" ") + date.toString("hh:mm");
}

QString dateTimeStr(qint64 nTime)
{
    return dateTimeStr(QDateTime::fromTime_t((qint32)nTime));
}

QFont bitcoinAddressFont()
{
    QFont font("Monospace");
#if QT_VERSION >= 0x040800
    font.setStyleHint(QFont::Monospace);
#else
    font.setStyleHint(QFont::TypeWriter);
#endif
    return font;
}

void setupAddressWidget(QLineEdit *widget, QWidget *parent)
{
    widget->setMaxLength(BitcoinAddressValidator::MaxAddressLength);
    widget->setValidator(new BitcoinAddressValidator(parent));
    widget->setFont(bitcoinAddressFont());
}

void setupAmountWidget(QLineEdit *widget, QWidget *parent)
{
    QDoubleValidator *amountValidator = new QDoubleValidator(parent);
    amountValidator->setDecimals(8);
    amountValidator->setBottom(0.0);
    widget->setValidator(amountValidator);
    widget->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
}

bool parseBitcoinURI(const QUrl &uri, SendCoinsRecipient *out)
{
    // NovaCoin: check prefix
    if(uri.scheme() != QString("Munne"))
        return false;

    SendCoinsRecipient rv;
    rv.address = uri.path();
    rv.amount = 0;
    QList<QPair<QString, QString> > items = uri.queryItems();
    for (QList<QPair<QString, QString> >::iterator i = items.begin(); i != items.end(); i++)
    {
        bool fShouldReturnFalse = false;
        if (i->first.startsWith("req-"))
        {
            i->first.remove(0, 4);
            fShouldReturnFalse = true;
        }

        if (i->first == "label")
        {
            rv.label = i->second;
            fShouldReturnFalse = false;
        }
        else if (i->first == "amount")
        {
            if(!i->second.isEmpty())
            {
                if(!BitcoinUnits::parse(BitcoinUnits::BTC, i->second, &rv.amount))
                {
                    return false;
                }
            }
            fShouldReturnFalse = false;
        }

        if (fShouldReturnFalse)
            return false;
    }
    if(out)
    {
        *out = rv;
    }
    return true;
}

bool parseBitcoinURI(QString uri, SendCoinsRecipient *out)
{
    // Convert Munne:// to Munne:
    //
    //    Cannot handle this later, because bitcoin:// will cause Qt to see the part after // as host,
    //    which will lower-case it (and thus invalidate the address).
    if(uri.startsWith("Munne://"))
    {
        uri.replace(0, 12, "Munne:");
    }
    QUrl uriInstance(uri);
    return parseBitcoinURI(uriInstance, out);
}

QString HtmlEscape(const QString& str, bool fMultiLine)
{
    QString escaped = Qt::escape(str);
    if(fMultiLine)
    {
        escaped = escaped.replace("\n", "
\n");
    }
    return escaped;
}

QString HtmlEscape(const std::string& str, bool fMultiLine)
{
    return HtmlEscape(QString::fromStdString(str), fMultiLine);
}

void copyEntryData(QAbstractItemView *view, int column, int role)
{
    if(!view || !view->selectionModel())
        return;
    QModelIndexList selection = view->selectionModel()->selectedRows(column);

    if(!selection.isEmpty())
    {
        // Copy first item
        QApplication::clipboard()->setText(selection.at(0).data(role).toString());
    }
}

QString getSaveFileName(QWidget *parent, const QString &caption,
                                 const QString &dir,
                                 const QString &filter,
                                 QString *selectedSuffixOut)
{
    QString selectedFilter;
    QString myDir;
    if(dir.isEmpty()) // Default to user documents location
    {
        myDir = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation);
    }
    else
    {
        myDir = dir;
    }
    QString result = QFileDialog::getSaveFileName(parent, caption, myDir, filter, &selectedFilter);

    /* Extract first suffix from filter pattern "Description (*.foo)" or "Description (*.foo *.bar ...) */
    QRegExp filter_re(".* \\(\\*\\.(.*)[ \\)]");
    QString selectedSuffix;
    if(filter_re.exactMatch(selectedFilter))
    {
        selectedSuffix = filter_re.cap(1);
    }

    /* Add suffix if needed */
    QFileInfo info(result);
    if(!result.isEmpty())
    {
        if(info.suffix().isEmpty() && !selectedSuffix.isEmpty())
        {
            /* No suffix specified, add selected suffix */
            if(!result.endsWith("."))
                result.append(".");
            result.append(selectedSuffix);
        }
    }

    /* Return selected suffix if asked to */
    if(selectedSuffixOut)
    {
        *selectedSuffixOut = selectedSuffix;
    }
    return result;
}

Qt::ConnectionType blockingGUIThreadConnection()
{
    if(QThread::currentThread() != QCoreApplication::instance()->thread())
    {
        return Qt::BlockingQueuedConnection;
    }
    else
    {
        return Qt::DirectConnection;
    }
}

bool checkPoint(const QPoint &p, const QWidget *w)
{
    QWidget *atW = qApp->widgetAt(w->mapToGlobal(p));
    if (!atW) return false;
    return atW->topLevelWidget() == w;
}

bool isObscured(QWidget *w)
{
    return !(checkPoint(QPoint(0, 0), w)
        && checkPoint(QPoint(w->width() - 1, 0), w)
        && checkPoint(QPoint(0, w->height() - 1), w)
        && checkPoint(QPoint(w->width() - 1, w->height() - 1), w)
        && checkPoint(QPoint(w->width() / 2, w->height() / 2), w));
}

void openDebugLogfile()
{
    boost::filesystem::path pathDebug = GetDataDir() / "debug.log";

    /* Open debug.log with the associated application */
    if (boost::filesystem::exists(pathDebug))
        QDesktopServices::openUrl(QUrl::fromLocalFile(QString::fromStdString(pathDebug.string())));
}

ToolTipToRichTextFilter::ToolTipToRichTextFilter(int size_threshold, QObject *parent) :
    QObject(parent), size_threshold(size_threshold)
{

}

bool ToolTipToRichTextFilter::eventFilter(QObject *obj, QEvent *evt)
{
    if(evt->type() == QEvent::ToolTipChange)
    {
        QWidget *widget = static_cast<QWidget*>(obj);
        QString tooltip = widget->toolTip();
        if(tooltip.size() > size_threshold && !tooltip.startsWith("<qt>") && !Qt::mightBeRichText(tooltip))
        {
            // Prefix <qt/> to make sure Qt detects this as rich text
            // Escape the current message as HTML and replace \n by

            tooltip = "<qt>" + HtmlEscape(tooltip, true) + "<qt/>";
            widget->setToolTip(tooltip);
            return true;
        }
    }
    return QObject::eventFilter(obj, evt);
}

#ifdef WIN32
boost::filesystem::path static StartupShortcutPath()
{
    return GetSpecialFolderPath(CSIDL_STARTUP) / "Munne.lnk";
}

bool GetStartOnSystemStartup()
{
    // check for Bitcoin.lnk
    return boost::filesystem::exists(StartupShortcutPath());
}

bool SetStartOnSystemStartup(bool fAutoStart)
{
    // If the shortcut exists already, remove it for updating
    boost::filesystem::remove(StartupShortcutPath());

    if (fAutoStart)
    {
        CoInitialize(NULL);

        // Get a pointer to the IShellLink interface.
        IShellLink* psl = NULL;
        HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL,
                                CLSCTX_INPROC_SERVER, IID_IShellLink,
                                reinterpret_cast<void**>(&psl));

        if (SUCCEEDED(hres))
        {
            // Get the current executable path
            TCHAR pszExePath[MAX_PATH];
            GetModuleFileName(NULL, pszExePath, sizeof(pszExePath));

            TCHAR pszArgs[5] = TEXT("-min");

            // Set the path to the shortcut target
            psl->SetPath(pszExePath);
            PathRemoveFileSpec(pszExePath);
            psl->SetWorkingDirectory(pszExePath);
            psl->SetShowCmd(SW_SHOWMINNOACTIVE);
            psl->SetArguments(pszArgs);

            // Query IShellLink for the IPersistFile interface for
            // saving the shortcut in persistent storage.
            IPersistFile* ppf = NULL;
            hres = psl->QueryInterface(IID_IPersistFile,
                                       reinterpret_cast<void**>(&ppf));
            if (SUCCEEDED(hres))
            {
                WCHAR pwsz[MAX_PATH];
                // Ensure that the string is ANSI.
                MultiByteToWideChar(CP_ACP, 0, StartupShortcutPath().string().c_str(), -1, pwsz, MAX_PATH);
                // Save the link by calling IPersistFile::Save.
                hres = ppf->Save(pwsz, TRUE);
                ppf->Release();
                psl->Release();
                CoUninitialize();
                return true;
            }
            psl->Release();
        }
        CoUninitialize();
        return false;
    }
    return true;
}

#elif defined(LINUX)

// Follow the Desktop Application Autostart Spec:
//  http://standards.freedesktop.org/autostart-spec/autostart-spec-latest.html

boost::filesystem::path static GetAutostartDir()
{
    namespace fs = boost::filesystem;

    char* pszConfigHome = getenv("XDG_CONFIG_HOME");
    if (pszConfigHome) return fs::path(pszConfigHome) / "autostart";
    char* pszHome = getenv("HOME");
    if (pszHome) return fs::path(pszHome) / ".config" / "autostart";
    return fs::path();
}

boost::filesystem::path static GetAutostartFilePath()
{
    return GetAutostartDir() / "Munne.desktop";
}

bool GetStartOnSystemStartup()
{
    boost::filesystem::ifstream optionFile(GetAutostartFilePath());
    if (!optionFile.good())
        return false;
    // Scan through file for "Hidden=true":
    std::string line;
    while (!optionFile.eof())
    {
        getline(optionFile, line);
        if (line.find("Hidden") != std::string::npos &&
            line.find("true") != std::string::npos)
            return false;
    }
    optionFile.close();

    return true;
}

bool SetStartOnSystemStartup(bool fAutoStart)
{
    if (!fAutoStart)
        boost::filesystem::remove(GetAutostartFilePath());
    else
    {
        char pszExePath[MAX_PATH+1];
        memset(pszExePath, 0, sizeof(pszExePath));
        if (readlink("/proc/self/exe", pszExePath, sizeof(pszExePath)-1) == -1)
            return false;

        boost::filesystem::create_directories(GetAutostartDir());

        boost::filesystem::ofstream optionFile(GetAutostartFilePath(), std::ios_base::out|std::ios_base::trunc);
        if (!optionFile.good())
            return false;
        // Write a bitcoin.desktop file to the autostart directory:
        optionFile << "[Desktop Entry]\n";
        optionFile << "Type=Application\n";
        optionFile << "Name=Munne\n";
        optionFile << "Exec=" << pszExePath << " -min\n";
        optionFile << "Terminal=false\n";
        optionFile << "Hidden=false\n";
        optionFile.close();
    }
    return true;
}
#else

// TODO: OSX startup stuff; see:
// https://developer.apple.com/library/mac/#documentation/MacOSX/Conceptual/BPSystemStartup/Articles/CustomLogin.html

bool GetStartOnSystemStartup() { return false; }
bool SetStartOnSystemStartup(bool fAutoStart) { return false; }

#endif

HelpMessageBox::HelpMessageBox(QWidget *parent) :
    QMessageBox(parent)
{
    header = tr("Munne-Qt") + " " + tr("version") + " " +
        QString::fromStdString(FormatFullVersion()) + "\n\n" +
        tr("Usage:") + "\n" +
        "  Munne-qt [" + tr("command-line options") + "]                     " + "\n";

    coreOptions = QString::fromStdString(HelpMessage());

    uiOptions = tr("UI options") + ":\n" +
        "  -lang=<lang>           " + tr("Set language, for example \"de_DE\" (default: system locale)") + "\n" +
        "  -min                   " + tr("Start minimized") + "\n" +
        "  -splash                " + tr("Show splash screen on startup (default: 1)") + "\n";

    setWindowTitle(tr("Munne-Qt"));
    setTextFormat(Qt::PlainText);
    // setMinimumWidth is ignored for QMessageBox so put in non-breaking spaces to make it wider.
    setText(header + QString(QChar(0x2003)).repeated(50));
    setDetailedText(coreOptions + "\n" + uiOptions);
}

void HelpMessageBox::printToConsole()
{
    // On other operating systems, the expected action is to print the message to the console.
    QString strUsage = header + "\n" + coreOptions + "\n" + uiOptions;
    fprintf(stdout, "%s", strUsage.toStdString().c_str());
}

void HelpMessageBox::showOrPrint()
{
#if defined(WIN32)
        // On Windows, show a message box, as there is no stderr/stdout in windowed applications
        exec();
#else
        // On other operating systems, print help text to console
        printToConsole();
#endif
}

} // namespace GUIUtil

<commit_msg>[Qt] Fix Start bitcoin on system login<commit_after>#include "guiutil.h"
#include "bitcoinaddressvalidator.h"
#include "walletmodel.h"
#include "bitcoinunits.h"
#include "util.h"
#include "init.h"

#include <QString>
#include <QDateTime>
#include <QDoubleValidator>
#include <QFont>
#include <QLineEdit>
#include <QUrl>
#include <QTextDocument> // For Qt::escape
#include <QAbstractItemView>
#include <QApplication>
#include <QClipboard>
#include <QFileDialog>
#include <QDesktopServices>
#include <QThread>

#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>

#ifdef WIN32
#ifdef _WIN32_WINNT
#undef _WIN32_WINNT
#endif
#define _WIN32_WINNT 0x0501
#ifdef _WIN32_IE
#undef _WIN32_IE
#endif
#define _WIN32_IE 0x0501
#define WIN32_LEAN_AND_MEAN 1
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include "shlwapi.h"
#include "shlobj.h"
#include "shellapi.h"
#endif

namespace GUIUtil {

QString dateTimeStr(const QDateTime &date)
{
    return date.date().toString(Qt::SystemLocaleShortDate) + QString(" ") + date.toString("hh:mm");
}

QString dateTimeStr(qint64 nTime)
{
    return dateTimeStr(QDateTime::fromTime_t((qint32)nTime));
}

QFont bitcoinAddressFont()
{
    QFont font("Monospace");
#if QT_VERSION >= 0x040800
    font.setStyleHint(QFont::Monospace);
#else
    font.setStyleHint(QFont::TypeWriter);
#endif
    return font;
}

void setupAddressWidget(QLineEdit *widget, QWidget *parent)
{
    widget->setMaxLength(BitcoinAddressValidator::MaxAddressLength);
    widget->setValidator(new BitcoinAddressValidator(parent));
    widget->setFont(bitcoinAddressFont());
}

void setupAmountWidget(QLineEdit *widget, QWidget *parent)
{
    QDoubleValidator *amountValidator = new QDoubleValidator(parent);
    amountValidator->setDecimals(8);
    amountValidator->setBottom(0.0);
    widget->setValidator(amountValidator);
    widget->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
}

bool parseBitcoinURI(const QUrl &uri, SendCoinsRecipient *out)
{
    // NovaCoin: check prefix
    if(uri.scheme() != QString("Munne"))
        return false;

    SendCoinsRecipient rv;
    rv.address = uri.path();
    rv.amount = 0;
    QList<QPair<QString, QString> > items = uri.queryItems();
    for (QList<QPair<QString, QString> >::iterator i = items.begin(); i != items.end(); i++)
    {
        bool fShouldReturnFalse = false;
        if (i->first.startsWith("req-"))
        {
            i->first.remove(0, 4);
            fShouldReturnFalse = true;
        }

        if (i->first == "label")
        {
            rv.label = i->second;
            fShouldReturnFalse = false;
        }
        else if (i->first == "amount")
        {
            if(!i->second.isEmpty())
            {
                if(!BitcoinUnits::parse(BitcoinUnits::BTC, i->second, &rv.amount))
                {
                    return false;
                }
            }
            fShouldReturnFalse = false;
        }

        if (fShouldReturnFalse)
            return false;
    }
    if(out)
    {
        *out = rv;
    }
    return true;
}

bool parseBitcoinURI(QString uri, SendCoinsRecipient *out)
{
    // Convert Munne:// to Munne:
    //
    //    Cannot handle this later, because bitcoin:// will cause Qt to see the part after // as host,
    //    which will lower-case it (and thus invalidate the address).
    if(uri.startsWith("Munne://"))
    {
        uri.replace(0, 12, "Munne:");
    }
    QUrl uriInstance(uri);
    return parseBitcoinURI(uriInstance, out);
}

QString HtmlEscape(const QString& str, bool fMultiLine)
{
    QString escaped = Qt::escape(str);
    if(fMultiLine)
    {
        escaped = escaped.replace("\n", "
\n");
    }
    return escaped;
}

QString HtmlEscape(const std::string& str, bool fMultiLine)
{
    return HtmlEscape(QString::fromStdString(str), fMultiLine);
}

void copyEntryData(QAbstractItemView *view, int column, int role)
{
    if(!view || !view->selectionModel())
        return;
    QModelIndexList selection = view->selectionModel()->selectedRows(column);

    if(!selection.isEmpty())
    {
        // Copy first item
        QApplication::clipboard()->setText(selection.at(0).data(role).toString());
    }
}

QString getSaveFileName(QWidget *parent, const QString &caption,
                                 const QString &dir,
                                 const QString &filter,
                                 QString *selectedSuffixOut)
{
    QString selectedFilter;
    QString myDir;
    if(dir.isEmpty()) // Default to user documents location
    {
        myDir = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation);
    }
    else
    {
        myDir = dir;
    }
    QString result = QFileDialog::getSaveFileName(parent, caption, myDir, filter, &selectedFilter);

    /* Extract first suffix from filter pattern "Description (*.foo)" or "Description (*.foo *.bar ...) */
    QRegExp filter_re(".* \\(\\*\\.(.*)[ \\)]");
    QString selectedSuffix;
    if(filter_re.exactMatch(selectedFilter))
    {
        selectedSuffix = filter_re.cap(1);
    }

    /* Add suffix if needed */
    QFileInfo info(result);
    if(!result.isEmpty())
    {
        if(info.suffix().isEmpty() && !selectedSuffix.isEmpty())
        {
            /* No suffix specified, add selected suffix */
            if(!result.endsWith("."))
                result.append(".");
            result.append(selectedSuffix);
        }
    }

    /* Return selected suffix if asked to */
    if(selectedSuffixOut)
    {
        *selectedSuffixOut = selectedSuffix;
    }
    return result;
}

Qt::ConnectionType blockingGUIThreadConnection()
{
    if(QThread::currentThread() != QCoreApplication::instance()->thread())
    {
        return Qt::BlockingQueuedConnection;
    }
    else
    {
        return Qt::DirectConnection;
    }
}

bool checkPoint(const QPoint &p, const QWidget *w)
{
    QWidget *atW = qApp->widgetAt(w->mapToGlobal(p));
    if (!atW) return false;
    return atW->topLevelWidget() == w;
}

bool isObscured(QWidget *w)
{
    return !(checkPoint(QPoint(0, 0), w)
        && checkPoint(QPoint(w->width() - 1, 0), w)
        && checkPoint(QPoint(0, w->height() - 1), w)
        && checkPoint(QPoint(w->width() - 1, w->height() - 1), w)
        && checkPoint(QPoint(w->width() / 2, w->height() / 2), w));
}

void openDebugLogfile()
{
    boost::filesystem::path pathDebug = GetDataDir() / "debug.log";

    /* Open debug.log with the associated application */
    if (boost::filesystem::exists(pathDebug))
        QDesktopServices::openUrl(QUrl::fromLocalFile(QString::fromStdString(pathDebug.string())));
}

ToolTipToRichTextFilter::ToolTipToRichTextFilter(int size_threshold, QObject *parent) :
    QObject(parent), size_threshold(size_threshold)
{

}

bool ToolTipToRichTextFilter::eventFilter(QObject *obj, QEvent *evt)
{
    if(evt->type() == QEvent::ToolTipChange)
    {
        QWidget *widget = static_cast<QWidget*>(obj);
        QString tooltip = widget->toolTip();
        if(tooltip.size() > size_threshold && !tooltip.startsWith("<qt>") && !Qt::mightBeRichText(tooltip))
        {
            // Prefix <qt/> to make sure Qt detects this as rich text
            // Escape the current message as HTML and replace \n by

            tooltip = "<qt>" + HtmlEscape(tooltip, true) + "<qt/>";
            widget->setToolTip(tooltip);
            return true;
        }
    }
    return QObject::eventFilter(obj, evt);
}

#ifdef WIN32
boost::filesystem::path static StartupShortcutPath()
{
    return GetSpecialFolderPath(CSIDL_STARTUP) / "Munne.lnk";
}

bool GetStartOnSystemStartup()
{
    // check for Bitcoin.lnk
    return boost::filesystem::exists(StartupShortcutPath());
}

bool SetStartOnSystemStartup(bool fAutoStart)
{
    // If the shortcut exists already, remove it for updating
    boost::filesystem::remove(StartupShortcutPath());

    if (fAutoStart)
    {
        CoInitialize(NULL);

        // Get a pointer to the IShellLink interface.
        IShellLink* psl = NULL;
        HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL,
                                CLSCTX_INPROC_SERVER, IID_IShellLink,
                                reinterpret_cast<void**>(&psl));

        if (SUCCEEDED(hres))
        {
            // Get the current executable path
            TCHAR pszExePath[MAX_PATH];
            GetModuleFileName(NULL, pszExePath, sizeof(pszExePath));

            TCHAR pszArgs[5] = TEXT("-min");

            // Set the path to the shortcut target
            psl->SetPath(pszExePath);
            PathRemoveFileSpec(pszExePath);
            psl->SetWorkingDirectory(pszExePath);
            psl->SetShowCmd(SW_SHOWMINNOACTIVE);
            psl->SetArguments(pszArgs);

            // Query IShellLink for the IPersistFile interface for
            // saving the shortcut in persistent storage.
            IPersistFile* ppf = NULL;
            hres = psl->QueryInterface(IID_IPersistFile,
                                       reinterpret_cast<void**>(&ppf));
            if (SUCCEEDED(hres))
            {
                WCHAR pwsz[MAX_PATH];
                // Ensure that the string is ANSI.
                MultiByteToWideChar(CP_ACP, 0, StartupShortcutPath().string().c_str(), -1, pwsz, MAX_PATH);
                // Save the link by calling IPersistFile::Save.
                hres = ppf->Save(pwsz, TRUE);
                ppf->Release();
                psl->Release();
                CoUninitialize();
                return true;
            }
            psl->Release();
        }
        CoUninitialize();
        return false;
    }
    return true;
}

#elif defined(Q_OS_LINUX)

// Follow the Desktop Application Autostart Spec:
//  http://standards.freedesktop.org/autostart-spec/autostart-spec-latest.html

boost::filesystem::path static GetAutostartDir()
{
    namespace fs = boost::filesystem;

    char* pszConfigHome = getenv("XDG_CONFIG_HOME");
    if (pszConfigHome) return fs::path(pszConfigHome) / "autostart";
    char* pszHome = getenv("HOME");
    if (pszHome) return fs::path(pszHome) / ".config" / "autostart";
    return fs::path();
}

boost::filesystem::path static GetAutostartFilePath()
{
    return GetAutostartDir() / "Munne.desktop";
}

bool GetStartOnSystemStartup()
{
    boost::filesystem::ifstream optionFile(GetAutostartFilePath());
    if (!optionFile.good())
        return false;
    // Scan through file for "Hidden=true":
    std::string line;
    while (!optionFile.eof())
    {
        getline(optionFile, line);
        if (line.find("Hidden") != std::string::npos &&
            line.find("true") != std::string::npos)
            return false;
    }
    optionFile.close();

    return true;
}

bool SetStartOnSystemStartup(bool fAutoStart)
{
    if (!fAutoStart)
        boost::filesystem::remove(GetAutostartFilePath());
    else
    {
        char pszExePath[MAX_PATH+1];
        memset(pszExePath, 0, sizeof(pszExePath));
        if (readlink("/proc/self/exe", pszExePath, sizeof(pszExePath)-1) == -1)
            return false;

        boost::filesystem::create_directories(GetAutostartDir());

        boost::filesystem::ofstream optionFile(GetAutostartFilePath(), std::ios_base::out|std::ios_base::trunc);
        if (!optionFile.good())
            return false;
        // Write a bitcoin.desktop file to the autostart directory:
        optionFile << "[Desktop Entry]\n";
        optionFile << "Type=Application\n";
        optionFile << "Name=Munne\n";
        optionFile << "Exec=" << pszExePath << " -min\n";
        optionFile << "Terminal=false\n";
        optionFile << "Hidden=false\n";
        optionFile.close();
    }
    return true;
}
#else

// TODO: OSX startup stuff; see:
// https://developer.apple.com/library/mac/#documentation/MacOSX/Conceptual/BPSystemStartup/Articles/CustomLogin.html

bool GetStartOnSystemStartup() { return false; }
bool SetStartOnSystemStartup(bool fAutoStart) { return false; }

#endif

HelpMessageBox::HelpMessageBox(QWidget *parent) :
    QMessageBox(parent)
{
    header = tr("Munne-Qt") + " " + tr("version") + " " +
        QString::fromStdString(FormatFullVersion()) + "\n\n" +
        tr("Usage:") + "\n" +
        "  Munne-qt [" + tr("command-line options") + "]                     " + "\n";

    coreOptions = QString::fromStdString(HelpMessage());

    uiOptions = tr("UI options") + ":\n" +
        "  -lang=<lang>           " + tr("Set language, for example \"de_DE\" (default: system locale)") + "\n" +
        "  -min                   " + tr("Start minimized") + "\n" +
        "  -splash                " + tr("Show splash screen on startup (default: 1)") + "\n";

    setWindowTitle(tr("Munne-Qt"));
    setTextFormat(Qt::PlainText);
    // setMinimumWidth is ignored for QMessageBox so put in non-breaking spaces to make it wider.
    setText(header + QString(QChar(0x2003)).repeated(50));
    setDetailedText(coreOptions + "\n" + uiOptions);
}

void HelpMessageBox::printToConsole()
{
    // On other operating systems, the expected action is to print the message to the console.
    QString strUsage = header + "\n" + coreOptions + "\n" + uiOptions;
    fprintf(stdout, "%s", strUsage.toStdString().c_str());
}

void HelpMessageBox::showOrPrint()
{
#if defined(WIN32)
        // On Windows, show a message box, as there is no stderr/stdout in windowed applications
        exec();
#else
        // On other operating systems, print help text to console
        printToConsole();
#endif
}

} // namespace GUIUtil

<|endoftext|>


<commit_before>/*
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.

Author: Leonardo de Moura
*/
#include <iostream>
#include <fstream>
#include <signal.h>
#include <cstdlib>
#include <getopt.h>
#include <string>
#include "util/stackinfo.h"
#include "util/debug.h"
#include "util/interrupt.h"
#include "util/script_state.h"
#include "kernel/printer.h"
#include "library/io_state.h"
#include "library/kernel_bindings.h"
#include "frontends/lean/parser.h"
#include "frontends/lean/frontend.h"
#include "frontends/lua/register_modules.h"
#include "shell/lua_repl.h"
#include "version.h"
#include "githash.h" // NOLINT

using lean::shell;
using lean::frontend;
using lean::parser;
using lean::script_state;
using lean::unreachable_reached;
using lean::invoke_debugger;
using lean::notify_assertion_violation;

enum class input_kind { Unspecified, Lean, Lua };

static void on_ctrl_c(int ) {
    lean::request_interrupt();
}

static void display_header(std::ostream & out) {
    out << "Lean (version " << LEAN_VERSION_MAJOR << "." << LEAN_VERSION_MINOR << ", commit " << std::string(g_githash).substr(0, 12) << ")\n";
}

static void display_help(std::ostream & out) {
    display_header(out);
    std::cout << "Input format:\n";
    std::cout << "  --lean         use parser for Lean default input format for files,\n";
    std::cout << "                 with unknown extension (default)\n";
    std::cout << "  --lua          use Lua parser for files with unknown extension\n";
    std::cout << "Miscellaneous:\n";
    std::cout << "  --help -h      display this message\n";
    std::cout << "  --version -v   display version number\n";
    std::cout << "  --githash      display the git commit hash number used to build this binary\n";
    std::cout << "  --luahook=num  how often the Lua interpreter checks the interrupted flag,\n";
    std::cout << "                 it is useful for interrupting non-terminating user scripts,\n";
    std::cout << "                 0 means 'do not check'.\n";
}

static char const * get_file_extension(char const * fname) {
    if (fname == 0)
        return 0;
    char const * last_dot = 0;
    while (true) {
        char const * tmp = strchr(fname, '.');
        if (tmp == 0) {
            return last_dot;
        }
        last_dot  = tmp + 1;
        fname = last_dot;
    }
}

static struct option g_long_options[] = {
    {"version",    no_argument,       0, 'v'},
    {"help",       no_argument,       0, 'h'},
    {"lean",       no_argument,       0, 'l'},
    {"lua",        no_argument,       0, 'u'},
    {"luahook",    required_argument, 0, 'c'},
    {"githash",    no_argument,       0, 'g'},
    {0, 0, 0, 0}
};

int main(int argc, char ** argv) {
    lean::save_stack_info();
    lean::register_modules();
    input_kind default_k = input_kind::Lean; // default
    while (true) {
        int c = getopt_long(argc, argv, "lugvhc:012", g_long_options, &optind);
        if (c == -1)
            break; // end of command line
        switch (c) {
        case 'v':
            display_header(std::cout);
            return 0;
        case 'g':
            std::cout << g_githash << "\n";
            return 0;
        case 'h':
            display_help(std::cout);
            return 0;
        case 'l':
            default_k = input_kind::Lean;
            break;
        case 'u':
            default_k = input_kind::Lua;
            break;
        case 'c':
            script_state::set_check_interrupt_freq(atoi(optarg));
            break;
        default:
            std::cerr << "Unknown command line option\n";
            display_help(std::cerr);
            return 1;
        }
    }
    if (optind >= argc) {
        display_header(std::cout);
        signal(SIGINT, on_ctrl_c);
        if (default_k == input_kind::Lean) {
            #if defined(LEAN_WINDOWS)
            std::cout << "Type 'Exit.' to exit or 'Help.' for help."<< std::endl;
            #else
            std::cout << "Type Ctrl-D or 'Exit.' to exit or 'Help.' for help."<< std::endl;
            #endif
            frontend f;
            script_state S;
            shell sh(f, &S);
            return sh() ? 0 : 1;
        } else {
            lean_assert(default_k == input_kind::Lua);
            script_state S;
            S.dostring(g_lua_repl);
        }
    } else {
        frontend f;
        script_state S;
        bool ok = true;
        for (int i = optind; i < argc; i++) {
            char const * ext = get_file_extension(argv[i]);
            input_kind k     = default_k;
            if (ext) {
                if (strcmp(ext, "lean") == 0) {
                    k = input_kind::Lean;
                } else if (strcmp(ext, "lua") == 0) {
                    k = input_kind::Lua;
                }
            }
            if (k == input_kind::Lean) {
                std::ifstream in(argv[i]);
                parser p(f, in, &S, false, false);
                if (!p())
                    ok = false;
            } else if (k == input_kind::Lua) {
                try {
                    S.dofile(argv[i]);
                } catch (lean::exception & ex) {
                    std::cerr << ex.what() << std::endl;
                    ok = false;
                }
            } else {
                lean_unreachable(); // LCOV_EXCL_LINE
            }
        }
        return ok ? 0 : 1;
    }
}
<commit_msg>feat(shell): add command line option to set thread stack size (only available if using Boost)<commit_after>/*
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.

Author: Leonardo de Moura
*/
#include <iostream>
#include <fstream>
#include <signal.h>
#include <cstdlib>
#include <getopt.h>
#include <string>
#include "util/stackinfo.h"
#include "util/debug.h"
#include "util/interrupt.h"
#include "util/script_state.h"
#include "util/thread.h"
#include "kernel/printer.h"
#include "library/io_state.h"
#include "library/kernel_bindings.h"
#include "frontends/lean/parser.h"
#include "frontends/lean/frontend.h"
#include "frontends/lua/register_modules.h"
#include "shell/lua_repl.h"
#include "version.h"
#include "githash.h" // NOLINT

using lean::shell;
using lean::frontend;
using lean::parser;
using lean::script_state;
using lean::unreachable_reached;
using lean::invoke_debugger;
using lean::notify_assertion_violation;

enum class input_kind { Unspecified, Lean, Lua };

static void on_ctrl_c(int ) {
    lean::request_interrupt();
}

static void display_header(std::ostream & out) {
    out << "Lean (version " << LEAN_VERSION_MAJOR << "." << LEAN_VERSION_MINOR << ", commit " << std::string(g_githash).substr(0, 12) << ")\n";
}

static void display_help(std::ostream & out) {
    display_header(out);
    std::cout << "Input format:\n";
    std::cout << "  --lean            use parser for Lean default input format for files,\n";
    std::cout << "                    with unknown extension (default)\n";
    std::cout << "  --lua             use Lua parser for files with unknown extension\n";
    std::cout << "Miscellaneous:\n";
    std::cout << "  --help -h         display this message\n";
    std::cout << "  --version -v      display version number\n";
    std::cout << "  --githash         display the git commit hash number used to build this binary\n";
    std::cout << "  --luahook=num -c  how often the Lua interpreter checks the interrupted flag,\n";
    std::cout << "                    it is useful for interrupting non-terminating user scripts,\n";
    std::cout << "                    0 means 'do not check'.\n";
#if defined(LEAN_USE_BOOST)
    std::cout << "  --tstack=num -s   thread stack size in Kb\n";
#endif
}

static char const * get_file_extension(char const * fname) {
    if (fname == 0)
        return 0;
    char const * last_dot = 0;
    while (true) {
        char const * tmp = strchr(fname, '.');
        if (tmp == 0) {
            return last_dot;
        }
        last_dot  = tmp + 1;
        fname = last_dot;
    }
}

static struct option g_long_options[] = {
    {"version",    no_argument,       0, 'v'},
    {"help",       no_argument,       0, 'h'},
    {"lean",       no_argument,       0, 'l'},
    {"lua",        no_argument,       0, 'u'},
    {"luahook",    required_argument, 0, 'c'},
    {"githash",    no_argument,       0, 'g'},
#if defined(LEAN_USE_BOOST)
    {"tstack",     required_argument, 0, 's'},
#endif
    {0, 0, 0, 0}
};

int main(int argc, char ** argv) {
    lean::save_stack_info();
    lean::register_modules();
    input_kind default_k = input_kind::Lean; // default
    while (true) {
        int c = getopt_long(argc, argv, "lugvhc:012s:012", g_long_options, &optind);
        if (c == -1)
            break; // end of command line
        switch (c) {
        case 'v':
            display_header(std::cout);
            return 0;
        case 'g':
            std::cout << g_githash << "\n";
            return 0;
        case 'h':
            display_help(std::cout);
            return 0;
        case 'l':
            default_k = input_kind::Lean;
            break;
        case 'u':
            default_k = input_kind::Lua;
            break;
        case 'c':
            script_state::set_check_interrupt_freq(atoi(optarg));
            break;
        case 's':
            lean::set_thread_stack_size(atoi(optarg)*1024);
            break;
        default:
            std::cerr << "Unknown command line option\n";
            display_help(std::cerr);
            return 1;
        }
    }
    if (optind >= argc) {
        display_header(std::cout);
        signal(SIGINT, on_ctrl_c);
        if (default_k == input_kind::Lean) {
            #if defined(LEAN_WINDOWS)
            std::cout << "Type 'Exit.' to exit or 'Help.' for help."<< std::endl;
            #else
            std::cout << "Type Ctrl-D or 'Exit.' to exit or 'Help.' for help."<< std::endl;
            #endif
            frontend f;
            script_state S;
            shell sh(f, &S);
            return sh() ? 0 : 1;
        } else {
            lean_assert(default_k == input_kind::Lua);
            script_state S;
            S.dostring(g_lua_repl);
        }
    } else {
        frontend f;
        script_state S;
        bool ok = true;
        for (int i = optind; i < argc; i++) {
            char const * ext = get_file_extension(argv[i]);
            input_kind k     = default_k;
            if (ext) {
                if (strcmp(ext, "lean") == 0) {
                    k = input_kind::Lean;
                } else if (strcmp(ext, "lua") == 0) {
                    k = input_kind::Lua;
                }
            }
            if (k == input_kind::Lean) {
                std::ifstream in(argv[i]);
                parser p(f, in, &S, false, false);
                if (!p())
                    ok = false;
            } else if (k == input_kind::Lua) {
                try {
                    S.dofile(argv[i]);
                } catch (lean::exception & ex) {
                    std::cerr << ex.what() << std::endl;
                    ok = false;
                }
            } else {
                lean_unreachable(); // LCOV_EXCL_LINE
            }
        }
        return ok ? 0 : 1;
    }
}
<|endoftext|>


<commit_before>/*! @file simulation.cpp
    @brief Implementation of Simulation class
    @defgroup params Parameters
*/
#include "simulation.hpp"
#include "cell.hpp"

#include <wtl/debug.hpp>
#include <wtl/iostr.hpp>
#include <wtl/getopt.hpp>
#include <wtl/zfstream.hpp>
#include <sfmt.hpp>

#include <boost/filesystem.hpp>

#include <cstdlib>
#include <algorithm>

namespace tumopp {

namespace fs = boost::filesystem;
namespace po = boost::program_options;

//! Options description for general purpose
inline po::options_description general_desc() {HERE;
    po::options_description description("General");
    description.add_options()
        ("help,h", po::bool_switch(), "print this help")
        ("verbose,v", po::bool_switch(), "verbose output")
        ("test", po::value<int>()->default_value(0)->implicit_value(1));
    return description;
}

//! Program options
/*! @ingroup params
    @return Program options description

    Command line option | Symbol         | Variable
    ------------------- | -------------- | -------------------------
    `-N,--max`          | \f$N_\max\f$   | Simulation::MAX_SIZE
    `-T,--plateau`      | -              | Simulation::PLATEAU_TIME
    `-w,--write`        | -              | Simulation::WRITE_TO_FILES
    `-o,--out_dir`      | -              | Simulation::OUT_DIR
    `--seed`            | -              | Simulation::SEED
*/
po::options_description Simulation::options_desc() {HERE;
    po::options_description description("Simulation");
    description.add_options()
        ("max,N", po::value(&MAX_SIZE)->default_value(MAX_SIZE))
        ("plateau,T", po::value(&PLATEAU_TIME)->default_value(PLATEAU_TIME))
        ("write,w", po::bool_switch(&WRITE_TO_FILES))
        ("out_dir,o", po::value(&OUT_DIR)->default_value(OUT_DIR))
        ("seed", po::value(&SEED)->default_value(SEED));
    description.add(Cell::opt_description());
    description.add(Tissue::opt_description());
    return description;
}

po::options_description Simulation::positional_desc() {HERE;
    po::options_description description("Positional");
    description.add_options()
        ("nsam", po::value(&NSAM)->default_value(NSAM))
        ("howmany", po::value(&HOWMANY)->default_value(HOWMANY));
    return description;
}

[[noreturn]] void Simulation::help_and_exit() {HERE;
    auto description = general_desc();
    description.add(options_desc());
    // do not print positional arguments as options
    std::cout << "Usage: tumopp [options] nsam howmany\n" << std::endl;
    description.print(std::cout);
    throw wtl::ExitSuccess();
}

//! Unit test for each class
inline void test(const int flg) {HERE;
    switch (flg) {
      case 0:
        break;
      case 1:
        Cell::test();
        Tissue::test();
        throw wtl::ExitSuccess();
      default:
        throw std::runtime_error("Unknown argument for --test");
    }
}

Simulation::Simulation(const std::vector<std::string>& arguments) {HERE;
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.precision(15);
    std::cerr.precision(6);
    COMMAND_ARGS = wtl::str_join(arguments, " ");
    OUT_DIR = wtl::strftime("tumopp_%Y%m%d_%H%M_") + std::to_string(::getpid());

    auto description = general_desc();
    description.add(options_desc());
    description.add(positional_desc());
    po::positional_options_description positional;
    positional.add("nsam", 1)
              .add("howmany", 1);
    po::variables_map vm;
    po::store(po::command_line_parser(arguments).
              options(description).
              positional(positional).run(), vm);
    if (vm["help"].as<bool>()) {help_and_exit();}
    po::notify(vm);
    Cell::init_distributions();
    wtl::sfmt().seed(SEED);

    CONFIG_STRING = wtl::flags_into_string(vm);
    if (vm["verbose"].as<bool>()) {
        std::cerr << wtl::iso8601datetime() << std::endl;
        std::cerr << CONFIG_STRING << std::endl;
    }
    test(vm["test"].as<int>());
    if (NSAM > vm["max"].as<size_t>()) {
        std::ostringstream oss;
        oss << "NSAM=" << NSAM
            << " is larger than final tumor size "
            << vm["max"].as<size_t>();
        throw std::runtime_error(oss.str());
    }
    OUT_DIR = fs::system_complete(OUT_DIR).string();
}

void Simulation::run() {HERE;
    for (size_t i=0; i<10; ++i) {
        if (tissue_.grow(MAX_SIZE, PLATEAU_TIME)) break;
    }
    if (tissue_.size() != MAX_SIZE) {
        std::cerr << "Warning: tissue_.size() " << tissue_.size() << std::endl;
    }
}

void Simulation::write() const {HERE;
    std::cout << "tumopp " << COMMAND_ARGS << "\n" << SEED << "\n";

    if (Tissue::DIMENSIONS() == 3U) {
        for (size_t i=0; i<HOWMANY; ++i) {
            tissue_.write_segsites(std::cout, tissue_.sample_section(NSAM));
        }
    } else {
        for (size_t i=0; i<HOWMANY; ++i) {
            tissue_.write_segsites(std::cout, tissue_.sample_random(NSAM));
        }
    }

    if (WRITE_TO_FILES) {
        DCERR("mkdir && cd to " << OUT_DIR << std::endl);
        fs::create_directory(OUT_DIR);
        fs::current_path(OUT_DIR);
        wtl::opfstream{"program_options.conf"} << CONFIG_STRING;
        wtl::ozfstream{"population.tsv.gz"}
            << tissue_.specimens();
        wtl::ozfstream{"snapshots.tsv.gz"}
            << tissue_.snapshots();
        wtl::ozfstream{"drivers.tsv.gz"}
            << tissue_.drivers();
        wtl::ozfstream{"distance.tsv.gz"}
            << tissue_.pairwise_distance(std::min(200UL, tissue_.size() / 2U));
        std::cerr << wtl::iso8601datetime() << std::endl;
    }
}

} // namespace tumopp
<commit_msg>Remove wtl::opfstream<commit_after>/*! @file simulation.cpp
    @brief Implementation of Simulation class
    @defgroup params Parameters
*/
#include "simulation.hpp"
#include "cell.hpp"

#include <wtl/debug.hpp>
#include <wtl/iostr.hpp>
#include <wtl/getopt.hpp>
#include <wtl/zfstream.hpp>
#include <sfmt.hpp>

#include <boost/filesystem.hpp>

#include <cstdlib>
#include <algorithm>

namespace tumopp {

namespace fs = boost::filesystem;
namespace po = boost::program_options;

//! Options description for general purpose
inline po::options_description general_desc() {HERE;
    po::options_description description("General");
    description.add_options()
        ("help,h", po::bool_switch(), "print this help")
        ("verbose,v", po::bool_switch(), "verbose output")
        ("test", po::value<int>()->default_value(0)->implicit_value(1));
    return description;
}

//! Program options
/*! @ingroup params
    @return Program options description

    Command line option | Symbol         | Variable
    ------------------- | -------------- | -------------------------
    `-N,--max`          | \f$N_\max\f$   | Simulation::MAX_SIZE
    `-T,--plateau`      | -              | Simulation::PLATEAU_TIME
    `-w,--write`        | -              | Simulation::WRITE_TO_FILES
    `-o,--out_dir`      | -              | Simulation::OUT_DIR
    `--seed`            | -              | Simulation::SEED
*/
po::options_description Simulation::options_desc() {HERE;
    po::options_description description("Simulation");
    description.add_options()
        ("max,N", po::value(&MAX_SIZE)->default_value(MAX_SIZE))
        ("plateau,T", po::value(&PLATEAU_TIME)->default_value(PLATEAU_TIME))
        ("write,w", po::bool_switch(&WRITE_TO_FILES))
        ("out_dir,o", po::value(&OUT_DIR)->default_value(OUT_DIR))
        ("seed", po::value(&SEED)->default_value(SEED));
    description.add(Cell::opt_description());
    description.add(Tissue::opt_description());
    return description;
}

po::options_description Simulation::positional_desc() {HERE;
    po::options_description description("Positional");
    description.add_options()
        ("nsam", po::value(&NSAM)->default_value(NSAM))
        ("howmany", po::value(&HOWMANY)->default_value(HOWMANY));
    return description;
}

[[noreturn]] void Simulation::help_and_exit() {HERE;
    auto description = general_desc();
    description.add(options_desc());
    // do not print positional arguments as options
    std::cout << "Usage: tumopp [options] nsam howmany\n" << std::endl;
    description.print(std::cout);
    throw wtl::ExitSuccess();
}

//! Unit test for each class
inline void test(const int flg) {HERE;
    switch (flg) {
      case 0:
        break;
      case 1:
        Cell::test();
        Tissue::test();
        throw wtl::ExitSuccess();
      default:
        throw std::runtime_error("Unknown argument for --test");
    }
}

Simulation::Simulation(const std::vector<std::string>& arguments) {HERE;
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.precision(15);
    std::cerr.precision(6);
    COMMAND_ARGS = wtl::str_join(arguments, " ");
    OUT_DIR = wtl::strftime("tumopp_%Y%m%d_%H%M_") + std::to_string(::getpid());

    auto description = general_desc();
    description.add(options_desc());
    description.add(positional_desc());
    po::positional_options_description positional;
    positional.add("nsam", 1)
              .add("howmany", 1);
    po::variables_map vm;
    po::store(po::command_line_parser(arguments).
              options(description).
              positional(positional).run(), vm);
    if (vm["help"].as<bool>()) {help_and_exit();}
    po::notify(vm);
    Cell::init_distributions();
    wtl::sfmt().seed(SEED);

    CONFIG_STRING = wtl::flags_into_string(vm);
    if (vm["verbose"].as<bool>()) {
        std::cerr << wtl::iso8601datetime() << std::endl;
        std::cerr << CONFIG_STRING << std::endl;
    }
    test(vm["test"].as<int>());
    if (NSAM > vm["max"].as<size_t>()) {
        std::ostringstream oss;
        oss << "NSAM=" << NSAM
            << " is larger than final tumor size "
            << vm["max"].as<size_t>();
        throw std::runtime_error(oss.str());
    }
    OUT_DIR = fs::system_complete(OUT_DIR).string();
}

void Simulation::run() {HERE;
    for (size_t i=0; i<10; ++i) {
        if (tissue_.grow(MAX_SIZE, PLATEAU_TIME)) break;
    }
    if (tissue_.size() != MAX_SIZE) {
        std::cerr << "Warning: tissue_.size() " << tissue_.size() << std::endl;
    }
}

void Simulation::write() const {HERE;
    std::cout << "tumopp " << COMMAND_ARGS << "\n" << SEED << "\n";

    if (Tissue::DIMENSIONS() == 3U) {
        for (size_t i=0; i<HOWMANY; ++i) {
            tissue_.write_segsites(std::cout, tissue_.sample_section(NSAM));
        }
    } else {
        for (size_t i=0; i<HOWMANY; ++i) {
            tissue_.write_segsites(std::cout, tissue_.sample_random(NSAM));
        }
    }

    if (WRITE_TO_FILES) {
        DCERR("mkdir && cd to " << OUT_DIR << std::endl);
        fs::create_directory(OUT_DIR);
        fs::current_path(OUT_DIR);
        wtl::make_ofs("program_options.conf") << CONFIG_STRING;
        wtl::ozfstream{"population.tsv.gz"}
            << tissue_.specimens();
        wtl::ozfstream{"snapshots.tsv.gz"}
            << tissue_.snapshots();
        wtl::ozfstream{"drivers.tsv.gz"}
            << tissue_.drivers();
        wtl::ozfstream{"distance.tsv.gz"}
            << tissue_.pairwise_distance(std::min(200UL, tissue_.size() / 2U));
        std::cerr << wtl::iso8601datetime() << std::endl;
    }
}

} // namespace tumopp
<|endoftext|>


<commit_before>/*
    Copyright (c) 2012, Russell Hay <me@russellhay.com>

    Permission to use, copy, modify, and/or distribute this software for any
    purpose with or without fee is hereby granted, provided that the above
    copyright notice and this permission notice appear in all copies.

    THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#define BUILDING_NODE_EXTENSION

#include "spi_binding.h"

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/spi/spidev.h>
#include <v8.h>
#include <node.h>
#include <node_buffer.h>

using namespace v8;
using namespace node;

extern "C" {
  void init (Handle<Object> target) {
    Spi::Initialize(target);
  }

  NODE_MODULE(_spi, init);
}

Persistent<Function> Spi::constructor;

void Spi::Initialize(Handle<Object> target) {
  HandleScope scope;

  // var t = function() {};
  Local<FunctionTemplate> t = FunctionTemplate::New(New);

  // t = function _spi() {};
  t->SetClassName(String::NewSymbol("_spi"));
  t->InstanceTemplate()->SetInternalFieldCount(1);

  // t.prototype.open = open;
  t->PrototypeTemplate()->Set(String::NewSymbol("open"),
                              FunctionTemplate::New(Open)->GetFunction());
  // t.prototype.close = close;
  t->PrototypeTemplate()->Set(String::NewSymbol("close"),
                              FunctionTemplate::New(Close)->GetFunction());

  // t.prototype.transfer = transfer;
  t->PrototypeTemplate()->Set(String::NewSymbol("transfer"),
                              FunctionTemplate::New(Transfer)->GetFunction());

  // t.prototype.mode = GetSetMode;
  t->PrototypeTemplate()->Set(String::NewSymbol("mode"),
                              FunctionTemplate::New(GetSetMode)->GetFunction());

  // t.prototype.chipSelect = GetSetChipSelect;
  t->PrototypeTemplate()->Set(String::NewSymbol("chipSelect"),
                              FunctionTemplate::New(GetSetChipSelect)->GetFunction());

  // t.prototype.bitsPerWord = GetSetBitsPerWord;
  t->PrototypeTemplate()->Set(String::NewSymbol("size"),
                              FunctionTemplate::New(GetSetBitsPerWord)->GetFunction());

  // t.prototype.bitOrder = GetSetBitOrder;
  t->PrototypeTemplate()->Set(String::NewSymbol("bitOrder"),
                              FunctionTemplate::New(GetSetBitOrder)->GetFunction());

  // t.prototype.maxSpeed = GetSetMaxSpeed;
  t->PrototypeTemplate()->Set(String::NewSymbol("maxSpeed"),
                              FunctionTemplate::New(GetSetMaxSpeed)->GetFunction());

  // t.prototype.halfDuplex = GetSet3Wire;
  t->PrototypeTemplate()->Set(String::NewSymbol("halfDuplex"),
                              FunctionTemplate::New(GetSet3Wire)->GetFunction());

  // t.prototype.delay = GetSetDelay;
  t->PrototypeTemplate()->Set(String::NewSymbol("delay"),
  			      FunctionTemplate::New(GetSetDelay)->GetFunction());

  // t.prototype.loopback = GetSetLoop;
  t->PrototypeTemplate()->Set(String::NewSymbol("loopback"),
                              FunctionTemplate::New(GetSetLoop)->GetFunction());

  // var constructor = t; // in context of new.
  constructor = Persistent<Function>::New(t->GetFunction());

  // exports._spi = constructor;
  target->Set(String::NewSymbol("_spi"), constructor);

  /* Should be change here.

	  // SPI modes
	  NODE_DEFINE_CONSTANT(target, SPI_MODE_0);
	  NODE_DEFINE_CONSTANT(target, SPI_MODE_1);
	  NODE_DEFINE_CONSTANT(target, SPI_MODE_2);
	  NODE_DEFINE_CONSTANT(target, SPI_MODE_3);

	  // Logic Level High for Chip Select
	  NODE_DEFINE_CONSTANT(target, SPI_CS_HIGH);

	  // No Chip Select
	  NODE_DEFINE_CONSTANT(target, SPI_NO_CS);
  */
  /* From:
  	_spi = {
  		SPI_MODE_0: 0
  	, SPI_MODE_1: 1
  	, SPI_MODE_2: 2
  	, SPI_MODE_3: 3

  	, SPI_NO_CS: 64
  	, SPI_CS_HIGH: 4
  	};
  */
  /* To:
  	var spi = require('spi');

  	spi.MODE_0 == 0;
  	spi.MODE_1 == 1;
  	spi.MODE_2 == 2;
  	spi.MODE_3 == 3;

  	spi.CS_LOW == 0;
  	spi.CS_HIGH == 4;
  	spi.NO_CS == 64;
  */

  // Expose constants
  target->Set(v8::String::NewSymbol("MODE_0"), v8::Integer::New(SPI_MODE_0));
  target->Set(v8::String::NewSymbol("MODE_1"), v8::Integer::New(SPI_MODE_1));
  target->Set(v8::String::NewSymbol("MODE_2"), v8::Integer::New(SPI_MODE_2));
  target->Set(v8::String::NewSymbol("MODE_3"), v8::Integer::New(SPI_MODE_3));

  target->Set(v8::String::NewSymbol("NO_CS"), v8::Integer::New(SPI_NO_CS));
  target->Set(v8::String::NewSymbol("CS_LOW"), v8::Integer::New(0));
  target->Set(v8::String::NewSymbol("CS_HIGH"), v8::Integer::New(SPI_CS_HIGH));

  target->Set(v8::String::NewSymbol("ORDER_MSB"), v8::Boolean::New(false));
  target->Set(v8::String::NewSymbol("ORDER_LSB"), v8::Boolean::New(true));
}

// new Spi(string device)
//Handle<Value> Spi::New(const Arguments& args) {
SPI_FUNC_IMPL(New) {
  Spi* spi = new Spi();
  spi->Wrap(args.This());

  return args.This();
}

// TODO: Make Non-blocking once basic functionality is proven
Handle<Value> Spi::Open(const Arguments& args) {
  FUNCTION_PREAMBLE;
  REQ_ARGS(1);
  ASSERT_NOT_OPEN;

  String::Utf8Value device(args[0]->ToString());
  int retval = 0;

  self->m_fd = open(*device, O_RDWR); // Blocking!
  if (self->m_fd < 0) {
    return ThrowException(Exception::Error(String::New("Unable to open device")));
  }

  SET_IOCTL_VALUE(self->m_fd, SPI_IOC_WR_MODE, self->m_mode);
  SET_IOCTL_VALUE(self->m_fd, SPI_IOC_RD_MODE, self->m_mode);
  SET_IOCTL_VALUE(self->m_fd, SPI_IOC_WR_BITS_PER_WORD, self->m_bits_per_word);
  SET_IOCTL_VALUE(self->m_fd, SPI_IOC_RD_BITS_PER_WORD, self->m_bits_per_word);
  SET_IOCTL_VALUE(self->m_fd, SPI_IOC_WR_MAX_SPEED_HZ, self->m_max_speed);
  SET_IOCTL_VALUE(self->m_fd, SPI_IOC_RD_MAX_SPEED_HZ, self->m_max_speed);

  FUNCTION_CHAIN;
}

Handle<Value> Spi::Close(const Arguments &args) {
  FUNCTION_PREAMBLE;
  ONLY_IF_OPEN;

  close(self->m_fd);
  self->m_fd = -1;

  FUNCTION_CHAIN;
}

// tranfer(write_buffer, read_buffer);
Handle<Value> Spi::Transfer(const Arguments &args) {
  FUNCTION_PREAMBLE;
  ASSERT_OPEN;
  REQ_ARGS(2);

  if ((args[0]->IsNull()) && (args[1]->IsNull())) {
    return ERROR("Both buffers cannot be null");
  }

  char *write_buffer = NULL;
  char *read_buffer = NULL;
  size_t write_length = -1;
  size_t read_length = -1;
  Local<Object> write_buffer_obj;
  Local<Object> read_buffer_obj;

  if (Buffer::HasInstance(args[0])) {
    write_buffer_obj = args[0]->ToObject();
    write_buffer = Buffer::Data(write_buffer_obj);
    write_length = Buffer::Length(write_buffer_obj);
  }

  if (Buffer::HasInstance(args[1])) {
    read_buffer_obj = args[1]->ToObject();
    read_buffer = Buffer::Data(read_buffer_obj);
    read_length = Buffer::Length(read_buffer_obj);
  }

  if (write_length > 0 && read_length > 0 && write_length != read_length) {
    return ERROR("Read and write buffers MUST be the same length");
  }

  Handle<Value> retval = self->full_duplex_transfer(write_buffer, read_buffer,
                                MAX(write_length, read_length),
                                self->m_max_speed, self->m_delay, self->m_bits_per_word);

  if (!retval->IsUndefined()) {
    return retval;
  }

  FUNCTION_CHAIN;
}

Handle<Value> Spi::full_duplex_transfer(char *write, char *read, size_t length, uint32_t speed, uint16_t delay, uint8_t bits) {
  struct spi_ioc_transfer data = {
	  (unsigned long)write,
	  (unsigned long)read,
	  length,
	  speed,
	  delay, // Still unsure ... just expose to options.
	  bits,
  };

  int ret = ioctl(this->m_fd, SPI_IOC_MESSAGE(1), &data);

  if (ret == 1) {
    return ERROR("Unable to send SPI message");
  }

  return v8::Integer::New(ret);
}

// This overrides any of the OTHER set functions since modes are predefined
// sets of options.
SPI_FUNC_IMPL(GetSetMode) {
  FUNCTION_PREAMBLE;
  GETTER(1, Number::New(self->m_mode));
  REQ_INT_ARG(0, in_mode);
  ASSERT_NOT_OPEN;

  if (in_mode == SPI_MODE_0 || in_mode == SPI_MODE_1 ||
      in_mode == SPI_MODE_2 || in_mode == SPI_MODE_3) {
    self->m_mode = in_mode;
  } else {
    ThrowException(Exception::RangeError(String::New(
      "Argument 1 must be one of the SPI_MODE_X constants"
    )));
  }
  FUNCTION_CHAIN;
}
SPI_FUNC_IMPL(GetSetChipSelect) {
  FUNCTION_PREAMBLE;
  GETTER(1, Number::New(self->m_mode&(SPI_CS_HIGH|SPI_NO_CS)));
  REQ_INT_ARG(0, in_value);
  ASSERT_NOT_OPEN;

  switch(in_value) {
    case SPI_CS_HIGH:
      self->m_mode |= SPI_CS_HIGH;
      self->m_mode &= ~SPI_NO_CS;
      break;
    case SPI_NO_CS:
      self->m_mode |= SPI_NO_CS;
      self->m_mode &= ~SPI_CS_HIGH;
      break;
    default:
      self->m_mode &= ~(SPI_NO_CS|SPI_CS_HIGH);
      break;
  }

  FUNCTION_CHAIN;
}

SPI_FUNC_IMPL(GetSetBitsPerWord) {
  FUNCTION_PREAMBLE;
  GETTER(1, Number::New(self->m_bits_per_word));
  REQ_INT_ARG_GT(0, BitsPerWord, in_value, 0);
  ASSERT_NOT_OPEN;

  // TODO: Bounds checking?  Need to look up what the max value is
  self->m_bits_per_word = in_value;

  FUNCTION_CHAIN;
}

SPI_FUNC_IMPL(GetSetMaxSpeed) {
  FUNCTION_PREAMBLE;
  GETTER(1, Number::New(self->m_max_speed));
  REQ_INT_ARG_GT(0, MaxSpeed, in_value, 0);
  ASSERT_NOT_OPEN;

  // TODO: Bounds Checking? Need to look up what the max value is
  self->m_max_speed = in_value;

  FUNCTION_CHAIN;
}

SPI_FUNC_IMPL(GetSet3Wire) {
  FUNCTION_PREAMBLE;
  GETTER(1, Boolean::New((self->m_mode&SPI_3WIRE) > 0));
  REQ_BOOL_ARG(0, in_value);

  if (in_value) {
    self->m_mode |= SPI_3WIRE;
  } else {
    self->m_mode &= ~SPI_3WIRE;
  }
  FUNCTION_CHAIN;
}

// Expose m_delay as "delay"
SPI_FUNC_IMPL(GetSetDelay) {
	FUNCTION_PREAMBLE;
	GETTER(1, Number::New(self->m_delay));
	REQ_INT_ARG_GT(0, Delay, in_value, 0);
	ASSERT_NOT_OPEN;

	self->m_delay = in_value;

	FUNCTION_CHAIN;
}

SPI_FUNC_BOOLEAN_TOGGLE_IMPL(GetSetLoop, SPI_LOOP);
SPI_FUNC_BOOLEAN_TOGGLE_IMPL(GetSetBitOrder, SPI_LSB_FIRST);
<commit_msg>Fix the bug that won't let transfer 1 byte messages<commit_after>/*
    Copyright (c) 2012, Russell Hay <me@russellhay.com>

    Permission to use, copy, modify, and/or distribute this software for any
    purpose with or without fee is hereby granted, provided that the above
    copyright notice and this permission notice appear in all copies.

    THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#define BUILDING_NODE_EXTENSION

#include "spi_binding.h"

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/spi/spidev.h>
#include <v8.h>
#include <node.h>
#include <node_buffer.h>

using namespace v8;
using namespace node;

extern "C" {
  void init (Handle<Object> target) {
    Spi::Initialize(target);
  }

  NODE_MODULE(_spi, init);
}

Persistent<Function> Spi::constructor;

void Spi::Initialize(Handle<Object> target) {
  HandleScope scope;

  // var t = function() {};
  Local<FunctionTemplate> t = FunctionTemplate::New(New);

  // t = function _spi() {};
  t->SetClassName(String::NewSymbol("_spi"));
  t->InstanceTemplate()->SetInternalFieldCount(1);

  // t.prototype.open = open;
  t->PrototypeTemplate()->Set(String::NewSymbol("open"),
                              FunctionTemplate::New(Open)->GetFunction());
  // t.prototype.close = close;
  t->PrototypeTemplate()->Set(String::NewSymbol("close"),
                              FunctionTemplate::New(Close)->GetFunction());

  // t.prototype.transfer = transfer;
  t->PrototypeTemplate()->Set(String::NewSymbol("transfer"),
                              FunctionTemplate::New(Transfer)->GetFunction());

  // t.prototype.mode = GetSetMode;
  t->PrototypeTemplate()->Set(String::NewSymbol("mode"),
                              FunctionTemplate::New(GetSetMode)->GetFunction());

  // t.prototype.chipSelect = GetSetChipSelect;
  t->PrototypeTemplate()->Set(String::NewSymbol("chipSelect"),
                              FunctionTemplate::New(GetSetChipSelect)->GetFunction());

  // t.prototype.bitsPerWord = GetSetBitsPerWord;
  t->PrototypeTemplate()->Set(String::NewSymbol("size"),
                              FunctionTemplate::New(GetSetBitsPerWord)->GetFunction());

  // t.prototype.bitOrder = GetSetBitOrder;
  t->PrototypeTemplate()->Set(String::NewSymbol("bitOrder"),
                              FunctionTemplate::New(GetSetBitOrder)->GetFunction());

  // t.prototype.maxSpeed = GetSetMaxSpeed;
  t->PrototypeTemplate()->Set(String::NewSymbol("maxSpeed"),
                              FunctionTemplate::New(GetSetMaxSpeed)->GetFunction());

  // t.prototype.halfDuplex = GetSet3Wire;
  t->PrototypeTemplate()->Set(String::NewSymbol("halfDuplex"),
                              FunctionTemplate::New(GetSet3Wire)->GetFunction());

  // t.prototype.delay = GetSetDelay;
  t->PrototypeTemplate()->Set(String::NewSymbol("delay"),
  			      FunctionTemplate::New(GetSetDelay)->GetFunction());

  // t.prototype.loopback = GetSetLoop;
  t->PrototypeTemplate()->Set(String::NewSymbol("loopback"),
                              FunctionTemplate::New(GetSetLoop)->GetFunction());

  // var constructor = t; // in context of new.
  constructor = Persistent<Function>::New(t->GetFunction());

  // exports._spi = constructor;
  target->Set(String::NewSymbol("_spi"), constructor);

  /* Should be change here.

	  // SPI modes
	  NODE_DEFINE_CONSTANT(target, SPI_MODE_0);
	  NODE_DEFINE_CONSTANT(target, SPI_MODE_1);
	  NODE_DEFINE_CONSTANT(target, SPI_MODE_2);
	  NODE_DEFINE_CONSTANT(target, SPI_MODE_3);

	  // Logic Level High for Chip Select
	  NODE_DEFINE_CONSTANT(target, SPI_CS_HIGH);

	  // No Chip Select
	  NODE_DEFINE_CONSTANT(target, SPI_NO_CS);
  */
  /* From:
  	_spi = {
  		SPI_MODE_0: 0
  	, SPI_MODE_1: 1
  	, SPI_MODE_2: 2
  	, SPI_MODE_3: 3

  	, SPI_NO_CS: 64
  	, SPI_CS_HIGH: 4
  	};
  */
  /* To:
  	var spi = require('spi');

  	spi.MODE_0 == 0;
  	spi.MODE_1 == 1;
  	spi.MODE_2 == 2;
  	spi.MODE_3 == 3;

  	spi.CS_LOW == 0;
  	spi.CS_HIGH == 4;
  	spi.NO_CS == 64;
  */

  // Expose constants
  target->Set(v8::String::NewSymbol("MODE_0"), v8::Integer::New(SPI_MODE_0));
  target->Set(v8::String::NewSymbol("MODE_1"), v8::Integer::New(SPI_MODE_1));
  target->Set(v8::String::NewSymbol("MODE_2"), v8::Integer::New(SPI_MODE_2));
  target->Set(v8::String::NewSymbol("MODE_3"), v8::Integer::New(SPI_MODE_3));

  target->Set(v8::String::NewSymbol("NO_CS"), v8::Integer::New(SPI_NO_CS));
  target->Set(v8::String::NewSymbol("CS_LOW"), v8::Integer::New(0));
  target->Set(v8::String::NewSymbol("CS_HIGH"), v8::Integer::New(SPI_CS_HIGH));

  target->Set(v8::String::NewSymbol("ORDER_MSB"), v8::Boolean::New(false));
  target->Set(v8::String::NewSymbol("ORDER_LSB"), v8::Boolean::New(true));
}

// new Spi(string device)
//Handle<Value> Spi::New(const Arguments& args) {
SPI_FUNC_IMPL(New) {
  Spi* spi = new Spi();
  spi->Wrap(args.This());

  return args.This();
}

// TODO: Make Non-blocking once basic functionality is proven
Handle<Value> Spi::Open(const Arguments& args) {
  FUNCTION_PREAMBLE;
  REQ_ARGS(1);
  ASSERT_NOT_OPEN;

  String::Utf8Value device(args[0]->ToString());
  int retval = 0;

  self->m_fd = open(*device, O_RDWR); // Blocking!
  if (self->m_fd < 0) {
    return ThrowException(Exception::Error(String::New("Unable to open device")));
  }

  SET_IOCTL_VALUE(self->m_fd, SPI_IOC_WR_MODE, self->m_mode);
  SET_IOCTL_VALUE(self->m_fd, SPI_IOC_RD_MODE, self->m_mode);
  SET_IOCTL_VALUE(self->m_fd, SPI_IOC_WR_BITS_PER_WORD, self->m_bits_per_word);
  SET_IOCTL_VALUE(self->m_fd, SPI_IOC_RD_BITS_PER_WORD, self->m_bits_per_word);
  SET_IOCTL_VALUE(self->m_fd, SPI_IOC_WR_MAX_SPEED_HZ, self->m_max_speed);
  SET_IOCTL_VALUE(self->m_fd, SPI_IOC_RD_MAX_SPEED_HZ, self->m_max_speed);

  FUNCTION_CHAIN;
}

Handle<Value> Spi::Close(const Arguments &args) {
  FUNCTION_PREAMBLE;
  ONLY_IF_OPEN;

  close(self->m_fd);
  self->m_fd = -1;

  FUNCTION_CHAIN;
}

// tranfer(write_buffer, read_buffer);
Handle<Value> Spi::Transfer(const Arguments &args) {
  FUNCTION_PREAMBLE;
  ASSERT_OPEN;
  REQ_ARGS(2);

  if ((args[0]->IsNull()) && (args[1]->IsNull())) {
    return ERROR("Both buffers cannot be null");
  }

  char *write_buffer = NULL;
  char *read_buffer = NULL;
  size_t write_length = -1;
  size_t read_length = -1;
  Local<Object> write_buffer_obj;
  Local<Object> read_buffer_obj;

  if (Buffer::HasInstance(args[0])) {
    write_buffer_obj = args[0]->ToObject();
    write_buffer = Buffer::Data(write_buffer_obj);
    write_length = Buffer::Length(write_buffer_obj);
  }

  if (Buffer::HasInstance(args[1])) {
    read_buffer_obj = args[1]->ToObject();
    read_buffer = Buffer::Data(read_buffer_obj);
    read_length = Buffer::Length(read_buffer_obj);
  }

  if (write_length > 0 && read_length > 0 && write_length != read_length) {
    return ERROR("Read and write buffers MUST be the same length");
  }

  Handle<Value> retval = self->full_duplex_transfer(write_buffer, read_buffer,
                                MAX(write_length, read_length),
                                self->m_max_speed, self->m_delay, self->m_bits_per_word);

  if (!retval->IsUndefined()) {
    return retval;
  }

  FUNCTION_CHAIN;
}

Handle<Value> Spi::full_duplex_transfer(char *write, char *read, size_t length, uint32_t speed, uint16_t delay, uint8_t bits) {
  struct spi_ioc_transfer data = {
	  (unsigned long)write,
	  (unsigned long)read,
	  length,
	  speed,
	  delay, // Still unsure ... just expose to options.
	  bits,
  };

  int ret = ioctl(this->m_fd, SPI_IOC_MESSAGE(1), &data);

  if (ret == -1) {
    return ERROR("Unable to send SPI message");
  }

  return v8::Integer::New(ret);
}

// This overrides any of the OTHER set functions since modes are predefined
// sets of options.
SPI_FUNC_IMPL(GetSetMode) {
  FUNCTION_PREAMBLE;
  GETTER(1, Number::New(self->m_mode));
  REQ_INT_ARG(0, in_mode);
  ASSERT_NOT_OPEN;

  if (in_mode == SPI_MODE_0 || in_mode == SPI_MODE_1 ||
      in_mode == SPI_MODE_2 || in_mode == SPI_MODE_3) {
    self->m_mode = in_mode;
  } else {
    ThrowException(Exception::RangeError(String::New(
      "Argument 1 must be one of the SPI_MODE_X constants"
    )));
  }
  FUNCTION_CHAIN;
}
SPI_FUNC_IMPL(GetSetChipSelect) {
  FUNCTION_PREAMBLE;
  GETTER(1, Number::New(self->m_mode&(SPI_CS_HIGH|SPI_NO_CS)));
  REQ_INT_ARG(0, in_value);
  ASSERT_NOT_OPEN;

  switch(in_value) {
    case SPI_CS_HIGH:
      self->m_mode |= SPI_CS_HIGH;
      self->m_mode &= ~SPI_NO_CS;
      break;
    case SPI_NO_CS:
      self->m_mode |= SPI_NO_CS;
      self->m_mode &= ~SPI_CS_HIGH;
      break;
    default:
      self->m_mode &= ~(SPI_NO_CS|SPI_CS_HIGH);
      break;
  }

  FUNCTION_CHAIN;
}

SPI_FUNC_IMPL(GetSetBitsPerWord) {
  FUNCTION_PREAMBLE;
  GETTER(1, Number::New(self->m_bits_per_word));
  REQ_INT_ARG_GT(0, BitsPerWord, in_value, 0);
  ASSERT_NOT_OPEN;

  // TODO: Bounds checking?  Need to look up what the max value is
  self->m_bits_per_word = in_value;

  FUNCTION_CHAIN;
}

SPI_FUNC_IMPL(GetSetMaxSpeed) {
  FUNCTION_PREAMBLE;
  GETTER(1, Number::New(self->m_max_speed));
  REQ_INT_ARG_GT(0, MaxSpeed, in_value, 0);
  ASSERT_NOT_OPEN;

  // TODO: Bounds Checking? Need to look up what the max value is
  self->m_max_speed = in_value;

  FUNCTION_CHAIN;
}

SPI_FUNC_IMPL(GetSet3Wire) {
  FUNCTION_PREAMBLE;
  GETTER(1, Boolean::New((self->m_mode&SPI_3WIRE) > 0));
  REQ_BOOL_ARG(0, in_value);

  if (in_value) {
    self->m_mode |= SPI_3WIRE;
  } else {
    self->m_mode &= ~SPI_3WIRE;
  }
  FUNCTION_CHAIN;
}

// Expose m_delay as "delay"
SPI_FUNC_IMPL(GetSetDelay) {
	FUNCTION_PREAMBLE;
	GETTER(1, Number::New(self->m_delay));
	REQ_INT_ARG_GT(0, Delay, in_value, 0);
	ASSERT_NOT_OPEN;

	self->m_delay = in_value;

	FUNCTION_CHAIN;
}

SPI_FUNC_BOOLEAN_TOGGLE_IMPL(GetSetLoop, SPI_LOOP);
SPI_FUNC_BOOLEAN_TOGGLE_IMPL(GetSetBitOrder, SPI_LSB_FIRST);
<|endoftext|>


<commit_before>#include "stack_alloc.hh"
#include "ten/thread_local.hh"
#include "ten/logging.hh"
#include <boost/context/stack_allocator.hpp>
#include <boost/context/stack_utils.hpp>
#include <sys/mman.h>
#include <algorithm>
#include <atomic>

namespace ten {

namespace stack_allocator {

size_t default_stacksize{ (size_t)256 * 1024 };

// impl

namespace {

std::atomic<bool> alloc_fail{false};

inline void free_stack(void *ptr, size_t stack_size) {
    PCHECK(munmap(ptr, stack_size) == 0);
}

struct stack {
    void *ptr = nullptr;
    size_t size = 0;

    stack(void *p, size_t s) : ptr{p}, size{s} {}

    stack(const stack &) = delete;
    stack & operator = (const stack &) = delete;

    stack(stack &&other)               { take(other); }
    stack & operator = (stack &&other) { if (this != &other) take(other); return *this; }

    ~stack() { clear(); }

    void take(stack &other) {
        clear();
        std::swap(ptr, other.ptr);
        std::swap(size, other.size);
    }
    void clear() {
        if (ptr) {
            free_stack(ptr, size);
            ptr = nullptr;
        }
    }

    void *release() {
        void *tmp = nullptr;
        std::swap(tmp, ptr);
        return tmp;
    }
};

struct cache_tag {};
thread_cached<cache_tag, std::vector<stack>> stack_cache;

} // anon

// calling this function ensures all the above have been initialized
int initialize() { return 0; }

void gc_cache(std::vector<stack> &cache) {
    // reduce cache size by 20%
    const size_t n = cache.size() / 5;
    if (n) {
        cache.erase(end(cache) - n, end(cache));
        cache.shrink_to_fit();
    }
}

void *allocate(size_t stack_size) {
    // TODO: check stack_size >= min_stacksize (8k because of 4k guard page)
    auto &cache = *stack_cache;

    void *stack_ptr = nullptr;
    if (cache.empty()) {
        stack_ptr = mmap(nullptr, stack_size, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE|MAP_STACK, 0, 0);
        if (stack_ptr == MAP_FAILED) {
            alloc_fail.store(true);
            throw bad_stack_alloc();
        }
        if (mprotect(stack_ptr, page_size, PROT_NONE) == -1) {
            alloc_fail.store(true);
            free_stack(stack_ptr, stack_size);
            throw bad_stack_alloc();
        }
    } else {
        auto &reuse = cache.back();
        CHECK(reuse.size == stack_size);
        stack_ptr = reuse.release();
        cache.pop_back();
        if (!cache.empty() && alloc_fail.exchange(false)) {
            gc_cache(cache);
        }
    }
    return static_cast<char *>(stack_ptr) + stack_size;
}

void deallocate(void *stack_end, size_t stack_size) noexcept {
    void *stack_ptr = static_cast<char *>(stack_end) - stack_size;
    auto &cache = *stack_cache;
    try {
        if (!cache.empty() && alloc_fail.exchange(false)) {
            free_stack(stack_ptr, stack_size);
            gc_cache(cache);
        } else {
            cache.emplace_back(stack_ptr, stack_size);
        }
    } catch (std::bad_alloc &e) {
        free_stack(stack_ptr, stack_size);
    }
}

} // stack_allocator

} // ten

<commit_msg>remove unused headers<commit_after>#include "stack_alloc.hh"
#include "ten/thread_local.hh"
#include "ten/logging.hh"
#include <sys/mman.h>
#include <algorithm>
#include <atomic>

namespace ten {

namespace stack_allocator {

size_t default_stacksize{ (size_t)256 * 1024 };

// impl

namespace {

std::atomic<bool> alloc_fail{false};

inline void free_stack(void *ptr, size_t stack_size) {
    PCHECK(munmap(ptr, stack_size) == 0);
}

struct stack {
    void *ptr = nullptr;
    size_t size = 0;

    stack(void *p, size_t s) : ptr{p}, size{s} {}

    stack(const stack &) = delete;
    stack & operator = (const stack &) = delete;

    stack(stack &&other)               { take(other); }
    stack & operator = (stack &&other) { if (this != &other) take(other); return *this; }

    ~stack() { clear(); }

    void take(stack &other) {
        clear();
        std::swap(ptr, other.ptr);
        std::swap(size, other.size);
    }
    void clear() {
        if (ptr) {
            free_stack(ptr, size);
            ptr = nullptr;
        }
    }

    void *release() {
        void *tmp = nullptr;
        std::swap(tmp, ptr);
        return tmp;
    }
};

struct cache_tag {};
thread_cached<cache_tag, std::vector<stack>> stack_cache;

} // anon

// calling this function ensures all the above have been initialized
int initialize() { return 0; }

void gc_cache(std::vector<stack> &cache) {
    // reduce cache size by 20%
    const size_t n = cache.size() / 5;
    if (n) {
        cache.erase(end(cache) - n, end(cache));
        cache.shrink_to_fit();
    }
}

void *allocate(size_t stack_size) {
    // TODO: check stack_size >= min_stacksize (8k because of 4k guard page)
    auto &cache = *stack_cache;

    void *stack_ptr = nullptr;
    if (cache.empty()) {
        stack_ptr = mmap(nullptr, stack_size, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE|MAP_STACK, 0, 0);
        if (stack_ptr == MAP_FAILED) {
            alloc_fail.store(true);
            throw bad_stack_alloc();
        }
        if (mprotect(stack_ptr, page_size, PROT_NONE) == -1) {
            alloc_fail.store(true);
            free_stack(stack_ptr, stack_size);
            throw bad_stack_alloc();
        }
    } else {
        auto &reuse = cache.back();
        CHECK(reuse.size == stack_size);
        stack_ptr = reuse.release();
        cache.pop_back();
        if (!cache.empty() && alloc_fail.exchange(false)) {
            gc_cache(cache);
        }
    }
    return static_cast<char *>(stack_ptr) + stack_size;
}

void deallocate(void *stack_end, size_t stack_size) noexcept {
    void *stack_ptr = static_cast<char *>(stack_end) - stack_size;
    auto &cache = *stack_cache;
    try {
        if (!cache.empty() && alloc_fail.exchange(false)) {
            free_stack(stack_ptr, stack_size);
            gc_cache(cache);
        } else {
            cache.emplace_back(stack_ptr, stack_size);
        }
    } catch (std::bad_alloc &e) {
        free_stack(stack_ptr, stack_size);
    }
}

} // stack_allocator

} // ten

<|endoftext|>


<commit_before>#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <iostream>
#include "runner.hh"

namespace runsync {

const int TIMEOUT_INTERVAL = 1000 * 20; // microseconds

double tv_to_seconds(struct timeval* tv) {
    static double usec = 1.0 / 1000 / 1000;
    return tv->tv_sec + tv->tv_usec * usec;
}

SpawnRunner::SpawnRunner(const Local<String>& file, const Local<Array>& args, const Local<Object>& options)
        : file_(file),
          args_(args),
          options_(options),
          timeout_(-1),
          has_timedout_(false) {
    Local<Value> timeout_opt = options->Get(NanNew<String>("timeout"));
    if(timeout_opt->IsNumber()) {
        timeout_ = timeout_opt->IntegerValue();
    }
}

Local<Object> SpawnRunner::Run() {
    pipe(err_pipe_);
    pid_t pid = fork();
    if(pid == 0) {
        close(err_pipe_[0]);
        RunChild();
        _exit(127);
    } else {
        close(err_pipe_[1]);
        int stat = RunParent(pid);
        return BuildResultObject(stat, pid);
    }
    return BuildResultObject(0, pid);
}

int SpawnRunner::RunChild() {
    if(PipeStdio()) { return 1; }
    if(SetEnvironment()) { return 1; }
    if(ChangeDirectory()) { return 1; }
    String::Utf8Value file(file_);
    char** args = BuildArgs();
    execvp(*file, args);
    SendErrno(*file);
    return 1;
}

int SpawnRunner::RunParent(pid_t pid) {
    int stat;
    if(0 <= timeout_) {
        struct timeval tv;
        gettimeofday(&tv, NULL);
        double timeout = timeout_ * 0.001;
        double start = tv_to_seconds(&tv);

        while(waitpid(pid, &stat, WNOHANG) == 0) {
            usleep(TIMEOUT_INTERVAL);
            gettimeofday(&tv, NULL);
            if(timeout < tv_to_seconds(&tv) - start) {
                close(err_pipe_[0]);
                kill(pid, SIGTERM);
                has_timedout_ = true;
            }
        }
    } else {
        waitpid(pid, &stat, 0);
    }
    return stat;
}

Local<Object> SpawnRunner::BuildResultObject(int stat, pid_t pid) {
    Local<Object> result = NanNew<Object>();

    int status = 0;
    if(WIFEXITED(stat)) {
        status = WEXITSTATUS(stat);
        result->Set(NanNew<String>("signal"), NanNull());
    } else if(WIFSIGNALED(stat)) {
        int sig = WTERMSIG(stat);
        result->Set(NanNew<String>("signal"), NanNew<String>(node::signo_string(sig)));
        status = 128 + sig;
    }

    result->Set(NanNew<String>("status"), NanNew<Number>(status));
    result->Set(NanNew<String>("pid"), NanNew<Number>(pid));
    result->Set(NanNew<String>("file"), file_);
    result->Set(NanNew<String>("args"), args_);
    if(has_timedout_) {
        result->Set(NanNew<String>("_hasTimedOut"), NanNew<Boolean>(has_timedout_));
    }

    char errmsg[1024];
    int read_size = read(err_pipe_[0], errmsg, 1024);
    close(err_pipe_[0]);
    if(0 < read_size) {
        result->Set(NanNew<String>("_errmsg"), NanNew<String>(errmsg));
    }

    return result;
}

char** SpawnRunner::BuildArgs() {
    int len = args_->Length();
    char** args = new char*[len + 1];

    for(int i = 0; i < len; i++) {
        String::Utf8Value value(args_->Get(i));
        char* str = new char[value.length() + 1];
        strcpy(str, *value);
        args[i] = str;
    }

    // add sentinel
    args[len] = NULL;
    return args;
}

int SpawnRunner::PipeStdio() {
    Local<Array> stdio = options_->Get(NanNew<String>("stdio")).As<Array>();
    uint32_t len = stdio->Length();
    static const char* devfiles[3] = {"/dev/stdin", "/dev/stdout", "/dev/stderr"};

    for(uint32_t fileno = 0; fileno < len; fileno++) {
        Local<Value> pipe = stdio->Get(NanNew<Number>(fileno));
        int fd;
        if(pipe->IsNumber()) {
            fd = pipe->IntegerValue();

        } else {
            String::Utf8Value pipe_value(pipe);
            int mode = fileno == 0 ? O_RDONLY : O_WRONLY;
            if(strcmp(*pipe_value, "inherit") == 0) {
                if(fileno < 3) {
                    fd = open(devfiles[fileno], mode);
                } else {
                    fd = fileno;
                }
            } else if(strcmp(*pipe_value, "ignore") == 0) {
                fd = open("/dev/null", mode);
            } else {
                fd = open(*pipe_value, mode);
            }

            if(fd == -1) {
                SendErrno(*pipe_value);
                return 1;
            }
        }
        if(dup2(fd, fileno) == -1) {
            SendErrno("dup");
            return 1;
        }
    }
    return 0;
}

int SpawnRunner::SetEnvironment() {
    Local<Array> envPairs = options_->Get(NanNew<String>("envPairs")).As<Array>();
    int len = envPairs->Length();
    for(int i = 0; i < len; i++) {
        String::Utf8Value value(envPairs->Get(i));
        putenv(*value);
    }

    return 0;
}

int SpawnRunner::ChangeDirectory() {
    Local<Value> cwd = options_->Get(NanNew<String>("cwd"));
    if(cwd->IsString()) {
        String::Utf8Value cwd_value(cwd);
        int err = chdir(*cwd_value);
        if(err) {
            SendErrno(*cwd_value);
            return err;
        }
    }
    return 0;
}

void SpawnRunner::SendErrno(const char* msg) {
    char str[1024];
    snprintf(str, 1022, "%d %s", errno, msg);
    write(err_pipe_[1], str, strlen(str) + 1);
}

} // namespace runsync
<commit_msg>Close pipe when child process was terminated<commit_after>#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <iostream>
#include "runner.hh"

namespace runsync {

const int TIMEOUT_INTERVAL = 1000 * 20; // microseconds

double tv_to_seconds(struct timeval* tv) {
    static double usec = 1.0 / 1000 / 1000;
    return tv->tv_sec + tv->tv_usec * usec;
}

SpawnRunner::SpawnRunner(const Local<String>& file, const Local<Array>& args, const Local<Object>& options)
        : file_(file),
          args_(args),
          options_(options),
          timeout_(-1),
          has_timedout_(false) {
    Local<Value> timeout_opt = options->Get(NanNew<String>("timeout"));
    if(timeout_opt->IsNumber()) {
        timeout_ = timeout_opt->IntegerValue();
    }
}

Local<Object> SpawnRunner::Run() {
    int err = pipe(err_pipe_);
    assert(err == 0);

    pid_t pid = fork();
    if(pid == 0) {
        close(err_pipe_[0]);
        RunChild();
        _exit(127);
    } else {
        close(err_pipe_[1]);
        int stat = RunParent(pid);
        return BuildResultObject(stat, pid);
    }
    return BuildResultObject(0, pid);
}

int SpawnRunner::RunChild() {
    if(PipeStdio()) { return 1; }
    if(SetEnvironment()) { return 1; }
    if(ChangeDirectory()) { return 1; }
    String::Utf8Value file(file_);
    char** args = BuildArgs();
    execvp(*file, args);
    SendErrno(*file);
    return 1;
}

int SpawnRunner::RunParent(pid_t pid) {
    int stat;
    if(0 <= timeout_) {
        struct timeval tv;
        gettimeofday(&tv, NULL);
        double timeout = timeout_ * 0.001;
        double start = tv_to_seconds(&tv);

        while(waitpid(pid, &stat, WNOHANG) == 0) {
            usleep(TIMEOUT_INTERVAL);
            gettimeofday(&tv, NULL);
            if(timeout < tv_to_seconds(&tv) - start) {
                kill(pid, SIGTERM);
                has_timedout_ = true;
            }
        }
    } else {
        waitpid(pid, &stat, 0);
    }
    return stat;
}

Local<Object> SpawnRunner::BuildResultObject(int stat, pid_t pid) {
    Local<Object> result = NanNew<Object>();
    int status = 0;
    bool pipe_closed = false;

    if(WIFEXITED(stat)) {
        status = WEXITSTATUS(stat);
        result->Set(NanNew<String>("signal"), NanNull());
    } else if(WIFSIGNALED(stat)) {
        int sig = WTERMSIG(stat);
        close(err_pipe_[0]);
        pipe_closed = true;
        result->Set(NanNew<String>("signal"), NanNew<String>(node::signo_string(sig)));
        status = 128 + sig;
    }

    result->Set(NanNew<String>("status"), NanNew<Number>(status));
    result->Set(NanNew<String>("pid"), NanNew<Number>(pid));
    result->Set(NanNew<String>("file"), file_);
    result->Set(NanNew<String>("args"), args_);
    if(has_timedout_) {
        result->Set(NanNew<String>("_hasTimedOut"), NanNew<Boolean>(has_timedout_));
    }

    if(pipe_closed == false) {
        char errmsg[1024];
        int read_size = read(err_pipe_[0], errmsg, 1024);
        if(0 < read_size) {
            result->Set(NanNew<String>("_errmsg"), NanNew<String>(errmsg));
        }
        close(err_pipe_[0]);
    }

    return result;
}

char** SpawnRunner::BuildArgs() {
    int len = args_->Length();
    char** args = new char*[len + 1];

    for(int i = 0; i < len; i++) {
        String::Utf8Value value(args_->Get(i));
        char* str = new char[value.length() + 1];
        strcpy(str, *value);
        args[i] = str;
    }

    // add sentinel
    args[len] = NULL;
    return args;
}

int SpawnRunner::PipeStdio() {
    Local<Array> stdio = options_->Get(NanNew<String>("stdio")).As<Array>();
    uint32_t len = stdio->Length();
    static const char* devfiles[3] = {"/dev/stdin", "/dev/stdout", "/dev/stderr"};

    for(uint32_t fileno = 0; fileno < len; fileno++) {
        Local<Value> pipe = stdio->Get(NanNew<Number>(fileno));
        int fd;
        if(pipe->IsNumber()) {
            fd = pipe->IntegerValue();

        } else {
            String::Utf8Value pipe_value(pipe);
            int mode = fileno == 0 ? O_RDONLY : O_WRONLY;
            if(strcmp(*pipe_value, "inherit") == 0) {
                if(fileno < 3) {
                    fd = open(devfiles[fileno], mode);
                } else {
                    fd = fileno;
                }
            } else if(strcmp(*pipe_value, "ignore") == 0) {
                fd = open("/dev/null", mode);
            } else {
                fd = open(*pipe_value, mode);
            }

            if(fd == -1) {
                SendErrno(*pipe_value);
                return 1;
            }
        }
        if(dup2(fd, fileno) == -1) {
            SendErrno("dup");
            return 1;
        }
    }
    return 0;
}

int SpawnRunner::SetEnvironment() {
    Local<Array> envPairs = options_->Get(NanNew<String>("envPairs")).As<Array>();
    int len = envPairs->Length();
    for(int i = 0; i < len; i++) {
        String::Utf8Value value(envPairs->Get(i));
        putenv(*value);
    }

    return 0;
}

int SpawnRunner::ChangeDirectory() {
    Local<Value> cwd = options_->Get(NanNew<String>("cwd"));
    if(cwd->IsString()) {
        String::Utf8Value cwd_value(cwd);
        int err = chdir(*cwd_value);
        if(err) {
            SendErrno(*cwd_value);
            return err;
        }
    }
    return 0;
}

void SpawnRunner::SendErrno(const char* msg) {
    char str[1024];
    snprintf(str, 1022, "%d %s", errno, msg);
    ssize_t size = write(err_pipe_[1], str, strlen(str) + 1);
    assert(0 < size);

}

} // namespace runsync
<|endoftext|>