<commit_before>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/

#include "gettingstartedwelcomepagewidget.h"
#include "ui_gettingstartedwelcomepagewidget.h"

#include <coreplugin/icore.h>
#include <coreplugin/coreconstants.h>

#include <extensionsystem/pluginmanager.h>

#include <help/helpplugin.h>

#include <QtCore/QDateTime>
#include <QtCore/QDir>
#include <QtCore/QFileInfo>
#include <QtCore/QDebug>
#include <QtCore/QUrl>
#include <QtCore/QXmlStreamReader>
#include <QtGui/QFont>

namespace Qt4ProjectManager {
namespace Internal {

GettingStartedWelcomePageWidget::GettingStartedWelcomePageWidget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::GettingStartedWelcomePageWidget)
{
    ui->setupUi(this);
    ui->tutorialsTitleLabel->setStyledText(tr("Tutorials"));
    ui->demoTitleLabel->setStyledText(tr("Explore Qt Examples"));
    ui->didYouKnowTextBrowser->viewport()->setAutoFillBackground(false);
    ui->didYouKnowTitleLabel->setStyledText(tr("Did You Know?"));

    connect(ui->tutorialTreeWidget, SIGNAL(activated(QString)), SLOT(slotOpenHelpPage(const QString&)));
    connect(ui->openExampleButton, SIGNAL(clicked()), SLOT(slotOpenExample()));
    connect(ui->examplesComboBox, SIGNAL(currentIndexChanged(int)), SLOT(slotEnableExampleButton(int)));

    ui->tutorialTreeWidget->addItem(tr("Qt Creator - A quick tour"),
                                        QString("qthelp://com.nokia.qtcreator.%1%2/doc/index.html").arg(IDE_VERSION_MAJOR).arg(IDE_VERSION_MINOR));
    ui->tutorialTreeWidget->addItem(tr("Creating an address book"),
                                        QLatin1String("qthelp://com.nokia.qtcreator/doc/tutorials-addressbook-sdk.html?view=split"));
    ui->tutorialTreeWidget->addItem(tr("Understanding widgets"),
                                        QLatin1String("qthelp://com.trolltech.qt/qdoc/widgets-tutorial.html?view=split"));
    ui->tutorialTreeWidget->addItem(tr("Building with qmake"),
                                        QLatin1String("qthelp://com.trolltech.qmake/qdoc/qmake-tutorial.html?view=split"));
    ui->tutorialTreeWidget->addItem(tr("Writing test cases"),
                                        QLatin1String("qthelp://com.trolltech.qt/qdoc/qtestlib-tutorial.html?view=split"));

    srand(QDateTime::currentDateTime().toTime_t());
    QStringList tips = tipsOfTheDay();
    m_currentTip = rand()%tips.count();

    QTextDocument *doc = ui->didYouKnowTextBrowser->document();
    doc->setDefaultStyleSheet("a:link {color:black;}");
    ui->didYouKnowTextBrowser->setDocument(doc);
    ui->didYouKnowTextBrowser->setText(tips.at(m_currentTip));

    connect(ui->nextTipBtn, SIGNAL(clicked()), this, SLOT(slotNextTip()));
    connect(ui->prevTipBtn, SIGNAL(clicked()), this, SLOT(slotPrevTip()));

}

GettingStartedWelcomePageWidget::~GettingStartedWelcomePageWidget()
{
    delete ui;
}

void GettingStartedWelcomePageWidget::updateExamples(const QString& examplePath, const QString& demosPath, const QString &sourcePath)
{
    QString demoxml = demosPath + "/qtdemo/xml/examples.xml";
    if (!QFile::exists(demoxml)) {
        demoxml = sourcePath + "/demos/qtdemo/xml/examples.xml";
        if (!QFile::exists(demoxml))
            return;
    }

    QFile description(demoxml);
    if (!description.open(QFile::ReadOnly))
        return;

    ui->examplesComboBox->clear();
    ui->examplesComboBox->setEnabled(true);

    ui->examplesComboBox->addItem(tr("Choose an example..."));
    QFont f = font();
    f.setItalic(true);
    ui->examplesComboBox->setItemData(0, f, Qt::FontRole);
    f.setItalic(false);
    bool inExamples = false;
    QString dirName;
    QXmlStreamReader reader(&description);
    while (!reader.atEnd()) {
        switch (reader.readNext()) {
            case QXmlStreamReader::StartElement:
            if (reader.name() == "category") {
                QString name = reader.attributes().value(QLatin1String("name")).toString();
                if (name.contains("tutorial"))
                    break;
                dirName = reader.attributes().value(QLatin1String("dirname")).toString();
                ui->examplesComboBox->addItem(name);
                f.setBold(true);
                ui->examplesComboBox->setItemData(ui->examplesComboBox->count()-1, f, Qt::FontRole);
                f.setBold(false);
                inExamples = true;
            }
            if (inExamples && reader.name() == "example") {
                QString name = reader.attributes().value(QLatin1String("name")).toString();
                QString fn = reader.attributes().value(QLatin1String("filename")).toString();
                QString relativeProPath = '/' + dirName + '/' + fn + '/' + fn + ".pro";
                QString fileName = examplePath + relativeProPath;
                if (!QFile::exists(fileName))
                    fileName = sourcePath + "/examples" + relativeProPath;
                QString helpPath = "qthelp://com.trolltech.qt/qdoc/" + dirName.replace("/", "-") + "-" + fn + ".html";

                ui->examplesComboBox->addItem("  " + name, fileName);
                ui->examplesComboBox->setItemData(ui->examplesComboBox->count()-1, helpPath, Qt::UserRole+1);
            }
            break;
            case QXmlStreamReader::EndElement:
            if (reader.name() == "category")
                inExamples = false;
            break;
            default:
            break;
        }
    }
}

void GettingStartedWelcomePageWidget::slotEnableExampleButton(int index)
{
    QString fileName = ui->examplesComboBox->itemData(index, Qt::UserRole).toString();
    ui->openExampleButton->setEnabled(!fileName.isEmpty());
}

void GettingStartedWelcomePageWidget::slotOpenExample()
{
    QComboBox *box = ui->examplesComboBox;
    QString proFile = box->itemData(box->currentIndex(), Qt::UserRole).toString();
    QString helpFile = box->itemData(box->currentIndex(), Qt::UserRole + 1).toString();
    QStringList files;
    QFileInfo fi(proFile);
    QString tryFile = fi.path() + "/main.cpp";
    files << proFile;
    if(!QFile::exists(tryFile))
        tryFile = fi.path() + '/' + fi.baseName() + ".cpp";
    if(QFile::exists(tryFile))
        files << tryFile;
    Core::ICore::instance()->openFiles(files);
    slotOpenContextHelpPage(helpFile);
}

void GettingStartedWelcomePageWidget::slotOpenHelpPage(const QString& url)
{
    Help::HelpManager *helpManager
        = ExtensionSystem::PluginManager::instance()->getObject<Help::HelpManager>();
    Q_ASSERT(helpManager);
    helpManager->openHelpPage(url);
}
void GettingStartedWelcomePageWidget::slotOpenContextHelpPage(const QString& url)
{
    Help::HelpManager *helpManager
        = ExtensionSystem::PluginManager::instance()->getObject<Help::HelpManager>();
    Q_ASSERT(helpManager);
    helpManager->openContextHelpPage(url);
}

void GettingStartedWelcomePageWidget::slotNextTip()
{
    QStringList tips = tipsOfTheDay();
    m_currentTip = ((m_currentTip+1)%tips.count());
    ui->didYouKnowTextBrowser->setText(tips.at(m_currentTip));
}

void GettingStartedWelcomePageWidget::slotPrevTip()
{
    QStringList tips = tipsOfTheDay();
    m_currentTip = ((m_currentTip-1)+tips.count())%tips.count();
    ui->didYouKnowTextBrowser->setText(tips.at(m_currentTip));
}

QStringList GettingStartedWelcomePageWidget::tipsOfTheDay()
{
    static QStringList tips;
    if (tips.isEmpty()) {
        QString altShortcut =
#ifdef Q_WS_MAC
            tr("Cmd", "Shortcut key");
#else
            tr("Alt", "Shortcut key");
#endif

        QString ctrlShortcut =
#ifdef Q_WS_MAC
            tr("Cmd", "Shortcut key");
#else
            tr("Ctrl", "Shortcut key");
#endif

        tips.append(tr("You can switch between Qt Creator's modes using <tt>Ctrl+number</tt>:
"
                       "
1 - Welcome

2 - Edit

3 - Debug

4 - Projects

5 - Help
"
                       "

6 - Output

"));
        //:%1 gets replaced by Alt (Win/Unix) or Cmd (Mac)
        tips.append(tr("You can show and hide the side bar using <tt>%1+0<tt>.").arg(altShortcut));
        tips.append(tr("You can fine tune the <tt>Find</tt> function by selecting "Whole Words" "
                       "or "Case Sensitive". Simply click on the icons on the right end of the line edit."));
        tips.append(tr("If you add external libraries, Qt Creator will automatically offer syntax highlighting "
                        "and code completion."));
        tips.append(tr("The code completion is CamelCase-aware. For example, to complete <tt>namespaceUri</tt> "
                       "you can just type <tt>nU</tt> and hit <tt>Ctrl+Space</tt>."));
        tips.append(tr("You can force code completion at any time using <tt>Ctrl+Space</tt>."));
        tips.append(tr("You can start Qt Creator with a session by calling <tt>qtcreator <sessionname></tt>."));
        tips.append(tr("You can return to edit mode from any other mode at any time by hitting <tt>Escape</tt>."));
        //:%1 gets replaced by Alt (Win/Unix) or Cmd (Mac)
        tips.append(tr("You can switch between the output pane by hitting <tt>%1+n</tt> where n is the number denoted "
                       "on the buttons at the window bottom:"
                       "

1 - Build Issues

2 - Search Results

3 - Application Output
"
                       "
4 - Compile Output

").arg(altShortcut));
        tips.append(tr("You can quickly search methods, classes, help and more using the "
                       "Locator bar (<tt>%1+K</tt>).").arg(ctrlShortcut));
        tips.append(tr("You can add custom build steps in the "
                       "build settings."));
        tips.append(tr("Within a session, you can add "
                       "dependencies between projects."));
        tips.append(tr("You can set the preferred editor encoding for every project in <tt>Projects -> Editor Settings -> Default Encoding</tt>."));
        tips.append(tr("You can modify the binary that is being executed when you press the <tt>Run</tt> button: Add a <tt>Custom Executable</tt> "
                       "by clicking the <tt>+</tt> button in <tt>Projects -> Run Settings -> Run Configuration</tt> and then select the new "
                       "target in the combo box."));
        tips.append(tr("You can use Qt Creator with a number of "
                       "revision control systems such as Subversion, Perforce, CVS and Git."));
        tips.append(tr("In the editor, <tt>F2</tt> toggles declaration and definition while <tt>F4</tt> toggles header file and source file."));
    }
    return tips;
}

} // namespace Internal
} // namespace Qt4ProjectManager
<commit_msg>Workaround for Linux Distro Qt where examples live in write-protected dirs.<commit_after>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/

#include "gettingstartedwelcomepagewidget.h"
#include "ui_gettingstartedwelcomepagewidget.h"

#include <coreplugin/icore.h>
#include <coreplugin/coreconstants.h>

#include <utils/pathchooser.h>

#include <extensionsystem/pluginmanager.h>

#include <help/helpplugin.h>

#include <QtCore/QDateTime>
#include <QtCore/QDir>
#include <QtCore/QFileInfo>
#include <QtCore/QDebug>
#include <QtCore/QUrl>
#include <QtCore/QSettings>
#include <QtCore/QXmlStreamReader>
#include <QtGui/QDialogButtonBox>
#include <QtGui/QFont>
#include <QtGui/QMessageBox>
#include <QtGui/QPushButton>

namespace Qt4ProjectManager {
namespace Internal {

GettingStartedWelcomePageWidget::GettingStartedWelcomePageWidget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::GettingStartedWelcomePageWidget)
{
    ui->setupUi(this);
    ui->tutorialsTitleLabel->setStyledText(tr("Tutorials"));
    ui->demoTitleLabel->setStyledText(tr("Explore Qt Examples"));
    ui->didYouKnowTextBrowser->viewport()->setAutoFillBackground(false);
    ui->didYouKnowTitleLabel->setStyledText(tr("Did You Know?"));

    connect(ui->tutorialTreeWidget, SIGNAL(activated(QString)), SLOT(slotOpenHelpPage(const QString&)));
    connect(ui->openExampleButton, SIGNAL(clicked()), SLOT(slotOpenExample()));
    connect(ui->examplesComboBox, SIGNAL(currentIndexChanged(int)), SLOT(slotEnableExampleButton(int)));

    ui->tutorialTreeWidget->addItem(tr("Qt Creator - A quick tour"),
                                        QString("qthelp://com.nokia.qtcreator.%1%2/doc/index.html").arg(IDE_VERSION_MAJOR).arg(IDE_VERSION_MINOR));
    ui->tutorialTreeWidget->addItem(tr("Creating an address book"),
                                        QLatin1String("qthelp://com.nokia.qtcreator/doc/tutorials-addressbook-sdk.html?view=split"));
    ui->tutorialTreeWidget->addItem(tr("Understanding widgets"),
                                        QLatin1String("qthelp://com.trolltech.qt/qdoc/widgets-tutorial.html?view=split"));
    ui->tutorialTreeWidget->addItem(tr("Building with qmake"),
                                        QLatin1String("qthelp://com.trolltech.qmake/qdoc/qmake-tutorial.html?view=split"));
    ui->tutorialTreeWidget->addItem(tr("Writing test cases"),
                                        QLatin1String("qthelp://com.trolltech.qt/qdoc/qtestlib-tutorial.html?view=split"));

    srand(QDateTime::currentDateTime().toTime_t());
    QStringList tips = tipsOfTheDay();
    m_currentTip = rand()%tips.count();

    QTextDocument *doc = ui->didYouKnowTextBrowser->document();
    doc->setDefaultStyleSheet("a:link {color:black;}");
    ui->didYouKnowTextBrowser->setDocument(doc);
    ui->didYouKnowTextBrowser->setText(tips.at(m_currentTip));

    connect(ui->nextTipBtn, SIGNAL(clicked()), this, SLOT(slotNextTip()));
    connect(ui->prevTipBtn, SIGNAL(clicked()), this, SLOT(slotPrevTip()));

}

GettingStartedWelcomePageWidget::~GettingStartedWelcomePageWidget()
{
    delete ui;
}

void GettingStartedWelcomePageWidget::updateExamples(const QString& examplePath, const QString& demosPath, const QString &sourcePath)
{
    QString demoxml = demosPath + "/qtdemo/xml/examples.xml";
    if (!QFile::exists(demoxml)) {
        demoxml = sourcePath + "/demos/qtdemo/xml/examples.xml";
        if (!QFile::exists(demoxml))
            return;
    }

    QFile description(demoxml);
    if (!description.open(QFile::ReadOnly))
        return;

    ui->examplesComboBox->clear();
    ui->examplesComboBox->setEnabled(true);

    ui->examplesComboBox->addItem(tr("Choose an example..."));
    QFont f = font();
    f.setItalic(true);
    ui->examplesComboBox->setItemData(0, f, Qt::FontRole);
    f.setItalic(false);
    bool inExamples = false;
    QString dirName;
    QXmlStreamReader reader(&description);
    while (!reader.atEnd()) {
        switch (reader.readNext()) {
            case QXmlStreamReader::StartElement:
            if (reader.name() == "category") {
                QString name = reader.attributes().value(QLatin1String("name")).toString();
                if (name.contains("tutorial"))
                    break;
                dirName = reader.attributes().value(QLatin1String("dirname")).toString();
                ui->examplesComboBox->addItem(name);
                f.setBold(true);
                ui->examplesComboBox->setItemData(ui->examplesComboBox->count()-1, f, Qt::FontRole);
                f.setBold(false);
                inExamples = true;
            }
            if (inExamples && reader.name() == "example") {
                QString name = reader.attributes().value(QLatin1String("name")).toString();
                QString fn = reader.attributes().value(QLatin1String("filename")).toString();
                QString relativeProPath = '/' + dirName + '/' + fn + '/' + fn + ".pro";
                QString fileName = examplePath + relativeProPath;
                if (!QFile::exists(fileName))
                    fileName = sourcePath + "/examples" + relativeProPath;
                QString helpPath = "qthelp://com.trolltech.qt/qdoc/" + dirName.replace("/", "-") + "-" + fn + ".html";

                ui->examplesComboBox->addItem("  " + name, fileName);
                ui->examplesComboBox->setItemData(ui->examplesComboBox->count()-1, helpPath, Qt::UserRole+1);
            }
            break;
            case QXmlStreamReader::EndElement:
            if (reader.name() == "category")
                inExamples = false;
            break;
            default:
            break;
        }
    }
}

void GettingStartedWelcomePageWidget::slotEnableExampleButton(int index)
{
    QString fileName = ui->examplesComboBox->itemData(index, Qt::UserRole).toString();
    ui->openExampleButton->setEnabled(!fileName.isEmpty());
}

namespace {
void copyRecursive(const QDir& from, const QDir& to, const QString& dir)
{
    QDir dest(to);
    dest.mkdir(dir);
    dest.cd(dir);
    QDir src(from);
    src.cd(dir);
    foreach(const QFileInfo& roFile, src.entryInfoList(QDir::Files)) {
        QFile::copy(roFile.absoluteFilePath(), dest.absolutePath() + '/' + roFile.fileName());
    }
    foreach(const QString& roDir, src.entryList(QDir::NoDotAndDotDot|QDir::Dirs)) {
        copyRecursive(src, dest, QDir(roDir).dirName());
    }
}
} // namespace

void GettingStartedWelcomePageWidget::slotOpenExample()
{
    QComboBox *box = ui->examplesComboBox;
    QString proFile = box->itemData(box->currentIndex(), Qt::UserRole).toString();
    QString helpFile = box->itemData(box->currentIndex(), Qt::UserRole + 1).toString();
    QStringList files;
    QFileInfo proFileInfo(proFile);
    // If the Qt is a distro Qt on Linux, it will not be writable, hence compilation will fail
    if (!proFileInfo.isWritable())
    {
        QDialog d;
        QGridLayout *lay = new QGridLayout(&d);
        QLabel *descrLbl = new QLabel;
        d.setWindowTitle(tr("Copy Project to writable Location?"));
        descrLbl->setTextFormat(Qt::RichText);
        descrLbl->setWordWrap(true);
        descrLbl->setText(tr("
The project you are about to open is located in the "
                             "write-protected location:

%1
"
                             "
Please select a writable location below and click \"Copy Project and Open\" "
                             "to open a modifiable copy of the project or click \"Keep Project and Open\" "
                             "to open the project in location.

Note: You will not "
                             "be able to alter or compile your project in the current location.
")
                          .arg(QDir::toNativeSeparators(proFileInfo.dir().absolutePath())));
        lay->addWidget(descrLbl, 0, 0, 1, 2);
        QLabel *txt = new QLabel(tr("&Location:"));
        Utils::PathChooser *chooser = new Utils::PathChooser;
        txt->setBuddy(chooser);
        chooser->setExpectedKind(Utils::PathChooser::Directory);
        QSettings *settings = Core::ICore::instance()->settings();
        chooser->setPath(settings->value(
                QString::fromLatin1("General/ProjectsFallbackRoot"), QDir::homePath()).toString());
        lay->addWidget(txt, 1, 0);
        lay->addWidget(chooser, 1, 1);
        QDialogButtonBox *bb = new QDialogButtonBox;
        connect(bb, SIGNAL(accepted()), &d, SLOT(accept()));
        connect(bb, SIGNAL(rejected()), &d, SLOT(reject()));
        QPushButton *copyBtn = bb->addButton(tr("&Copy Project and Open"), QDialogButtonBox::AcceptRole);
        copyBtn->setDefault(true);
        bb->addButton(tr("&Keep Project and Open"), QDialogButtonBox::RejectRole);
        lay->addWidget(bb, 2, 0, 1, 2);
        connect(chooser, SIGNAL(validChanged(bool)), copyBtn, SLOT(setEnabled(bool)));
        if (d.exec() == QDialog::Accepted) {
            QString exampleDirName = proFileInfo.dir().dirName();
            QString toDir = chooser->path();
            settings->setValue(QString::fromLatin1("General/ProjectsFallbackRoot"), toDir);
            QDir toDirWithExamplesDir(toDir);
            if (toDirWithExamplesDir.cd(exampleDirName)) {
                toDirWithExamplesDir.cdUp(); // step out, just to not be in the way
                QMessageBox::warning(topLevelWidget(), tr("Warning"),
                                     tr("The specified location already exists. "
                                        "Please specify a valid location."),
                                     QMessageBox::Ok, QMessageBox::NoButton);
                return;
            } else {
                QDir from = proFileInfo.dir();
                from.cdUp();
                copyRecursive(from, toDir, exampleDirName);
                // set vars to new location
                proFileInfo = QFileInfo(toDir + '/'+ exampleDirName + '/' + proFileInfo.fileName());
                proFile = proFileInfo.absoluteFilePath();
            }
        }
    }

    QString tryFile = proFileInfo.path() + "/main.cpp";
    files << proFile;
    if(!QFile::exists(tryFile))
        tryFile = proFileInfo.path() + '/' + proFileInfo.baseName() + ".cpp";
    if(QFile::exists(tryFile))
        files << tryFile;
    Core::ICore::instance()->openFiles(files);
    slotOpenContextHelpPage(helpFile);
}

void GettingStartedWelcomePageWidget::slotOpenHelpPage(const QString& url)
{
    Help::HelpManager *helpManager
        = ExtensionSystem::PluginManager::instance()->getObject<Help::HelpManager>();
    Q_ASSERT(helpManager);
    helpManager->openHelpPage(url);
}
void GettingStartedWelcomePageWidget::slotOpenContextHelpPage(const QString& url)
{
    Help::HelpManager *helpManager
        = ExtensionSystem::PluginManager::instance()->getObject<Help::HelpManager>();
    Q_ASSERT(helpManager);
    helpManager->openContextHelpPage(url);
}

void GettingStartedWelcomePageWidget::slotNextTip()
{
    QStringList tips = tipsOfTheDay();
    m_currentTip = ((m_currentTip+1)%tips.count());
    ui->didYouKnowTextBrowser->setText(tips.at(m_currentTip));
}

void GettingStartedWelcomePageWidget::slotPrevTip()
{
    QStringList tips = tipsOfTheDay();
    m_currentTip = ((m_currentTip-1)+tips.count())%tips.count();
    ui->didYouKnowTextBrowser->setText(tips.at(m_currentTip));
}

QStringList GettingStartedWelcomePageWidget::tipsOfTheDay()
{
    static QStringList tips;
    if (tips.isEmpty()) {
        QString altShortcut =
#ifdef Q_WS_MAC
            tr("Cmd", "Shortcut key");
#else
            tr("Alt", "Shortcut key");
#endif

        QString ctrlShortcut =
#ifdef Q_WS_MAC
            tr("Cmd", "Shortcut key");
#else
            tr("Ctrl", "Shortcut key");
#endif

        tips.append(tr("You can switch between Qt Creator's modes using <tt>Ctrl+number</tt>:
"
                       "
1 - Welcome

2 - Edit

3 - Debug

4 - Projects

5 - Help
"
                       "

6 - Output

"));
        //:%1 gets replaced by Alt (Win/Unix) or Cmd (Mac)
        tips.append(tr("You can show and hide the side bar using <tt>%1+0<tt>.").arg(altShortcut));
        tips.append(tr("You can fine tune the <tt>Find</tt> function by selecting "Whole Words" "
                       "or "Case Sensitive". Simply click on the icons on the right end of the line edit."));
        tips.append(tr("If you add external libraries, Qt Creator will automatically offer syntax highlighting "
                        "and code completion."));
        tips.append(tr("The code completion is CamelCase-aware. For example, to complete <tt>namespaceUri</tt> "
                       "you can just type <tt>nU</tt> and hit <tt>Ctrl+Space</tt>."));
        tips.append(tr("You can force code completion at any time using <tt>Ctrl+Space</tt>."));
        tips.append(tr("You can start Qt Creator with a session by calling <tt>qtcreator <sessionname></tt>."));
        tips.append(tr("You can return to edit mode from any other mode at any time by hitting <tt>Escape</tt>."));
        //:%1 gets replaced by Alt (Win/Unix) or Cmd (Mac)
        tips.append(tr("You can switch between the output pane by hitting <tt>%1+n</tt> where n is the number denoted "
                       "on the buttons at the window bottom:"
                       "

1 - Build Issues

2 - Search Results

3 - Application Output
"
                       "
4 - Compile Output

").arg(altShortcut));
        tips.append(tr("You can quickly search methods, classes, help and more using the "
                       "Locator bar (<tt>%1+K</tt>).").arg(ctrlShortcut));
        tips.append(tr("You can add custom build steps in the "
                       "build settings."));
        tips.append(tr("Within a session, you can add "
                       "dependencies between projects."));
        tips.append(tr("You can set the preferred editor encoding for every project in <tt>Projects -> Editor Settings -> Default Encoding</tt>."));
        tips.append(tr("You can modify the binary that is being executed when you press the <tt>Run</tt> button: Add a <tt>Custom Executable</tt> "
                       "by clicking the <tt>+</tt> button in <tt>Projects -> Run Settings -> Run Configuration</tt> and then select the new "
                       "target in the combo box."));
        tips.append(tr("You can use Qt Creator with a number of "
                       "revision control systems such as Subversion, Perforce, CVS and Git."));
        tips.append(tr("In the editor, <tt>F2</tt> toggles declaration and definition while <tt>F4</tt> toggles header file and source file."));
    }
    return tips;
}

} // namespace Internal
} // namespace Qt4ProjectManager
<|endoftext|>


<commit_before>/* <x0/request.hpp>
 *
 * This file is part of the x0 web server project and is released under LGPL-3.
 *
 * (c) 2009 Chrisitan Parpart <trapni@gentoo.org>
 */

#ifndef x0_http_request_hpp
#define x0_http_request_hpp (1)

#include <x0/buffer.hpp>
#include <x0/header.hpp>
#include <x0/fileinfo.hpp>
#include <x0/strutils.hpp>
#include <x0/types.hpp>
#include <x0/api.hpp>
#include <string>
#include <vector>
#include <boost/tuple/tuple.hpp>
#include <boost/logic/tribool.hpp>

namespace x0 {

//! \addtogroup core
//@{

/**
 * \brief a client HTTP reuqest object, holding the parsed x0 request data.
 *
 * \see header, response, connection, server
 */
struct request
{
public:
	class reader;

public:
	explicit request(x0::connection& connection);

	/// the TCP/IP connection this request has been sent through
	x0::connection& connection;

public: // request properties
	/// HTTP request method, e.g. HEAD, GET, POST, PUT, etc.
	buffer_ref method;

	/// parsed request uri
	buffer_ref uri;

	/// decoded path-part
	buffer_ref path;

	/// the final entity to be served, for example the full path to the file on disk.
	fileinfo_ptr fileinfo;

	/// decoded query-part
	buffer_ref query;

	/// HTTP protocol version major part that this request was formed in
	int http_version_major;
	/// HTTP protocol version minor part that this request was formed in
	int http_version_minor;

	/// request headers
	std::vector<x0::request_header> headers;

	/** retrieve value of a given request header */
	buffer_ref header(const std::string& name) const;

	/// body
	std::string body;

public: // accumulated request data
	/// username this client has authenticated with.
	buffer_ref username;

	/// the document root directory for this request.
	std::string document_root;

//	std::string if_modified_since;		//!< "If-Modified-Since" request header value, if specified.
//	std::shared_ptr<range_def> range;	//!< parsed "Range" request header

public: // utility methods
	bool supports_protocol(int major, int minor) const;
	std::string hostid() const;
};

/**
 * \brief implements the HTTP request parser.
 *
 * \see request, connection
 */
class request::reader
{
public:
	enum state
	{
		method_start,
		method,
		uri_start,
		uri,
		http_version_h,
		http_version_t_1,
		http_version_t_2,
		http_version_p,
		http_version_slash,
		http_version_major_start,
		http_version_major,
		http_version_minor_start,
		http_version_minor,
		expecting_newline_1,
		header_line_start,
		header_lws,
		header_name,
		space_before_header_value,
		header_value,
		expecting_newline_2,
		expecting_newline_3,
		reading_body
	};

private:
	state state_;
	std::size_t left_;

private:
	static inline bool is_char(int ch);
	static inline bool is_ctl(int ch);
	static inline bool is_tspecial(int ch);
	static inline bool is_digit(int ch);

	static inline bool url_decode(buffer_ref& url);

public:
	reader();

	void reset();

	/** parses partial HTTP request.
	 *
	 * \param r request to fill with parsed data
	 * \param data buffer holding the (possibly partial) data of the request to be parsed.
	 *
	 * \retval true request has been fully parsed.
	 * \retval false HTTP request parser error (should result into bad_request if possible.)
	 * \retval indeterminate parsial request parsed successfully but more input is needed to complete parsing.
	 */
	inline boost::tribool parse(request& req, const buffer_ref& data);
};

// {{{ request impl
inline request::request(x0::connection& conn) :
	connection(conn)
{
}

inline bool request::supports_protocol(int major, int minor) const
{
	if (major == http_version_major && minor <= http_version_minor)
		return true;

	if (major < http_version_major)
		return true;

	return false;
}
// }}}

// {{{ request::reader impl
inline bool request::reader::is_char(int ch)
{
	return ch >= 0 && ch < 127;
}

inline bool request::reader::is_ctl(int ch)
{
	return (ch >= 0 && ch <= 31) || ch == 127;
}

inline bool request::reader::is_tspecial(int ch)
{
	switch (ch)
	{
		case '(':
		case ')':
		case '<':
		case '>':
		case '@':
		case ',':
		case ';':
		case ':':
		case '\\':
		case '"':
		case '/':
		case '[':
		case ']':
		case '?':
		case '=':
		case '{':
		case '}':
		case ' ':
		case '\t':
			return true;
		default:
			return false;
	}
}

inline bool request::reader::is_digit(int ch)
{
	return ch >= '0' && ch <= '9';
}

inline bool request::reader::url_decode(buffer_ref& url)
{
	std::size_t left = url.offset();
	std::size_t right = left + url.size();
	std::size_t i = left; // read pos
	std::size_t d = left; // write pos
	buffer& value = url.buffer();

	while (i != right)
	{
		if (value[i] == '%')
		{
			if (i + 3 <= right)
			{
				int ival;
				if (hex2int(value.begin() + i + 1, value.begin() + i + 3, ival))
				{
					value[d++] = static_cast<char>(ival);
					i += 3;
				}
				else
				{
					return false;
				}
			}
			else
			{
				return false;
			}
		}
		else if (value[i] == '+')
		{
			value[d++] = ' ';
			++i;
		}
		else if (d != i)
		{
			value[d++] = value[i++];
		}
		else
		{
			++d;
			++i;
		}
	}

	url = value.ref(left, d - left);
	return true;
}

inline request::reader::reader() :
	state_(method_start), left_(0)
{
}

inline void request::reader::reset()
{
	state_ = method_start;
	left_ = 0;
}

inline boost::tribool request::reader::parse(request& r, const buffer_ref& data)
{
	std::size_t cur = data.offset();
	std::size_t count = cur + data.size();
	buffer_ref::const_iterator i = data.begin();

	for (; cur != count; ++cur)
	{
		char input = *i++;

		switch (state_)
		{
			case method_start:
				if (!is_char(input) || is_ctl(input) || is_tspecial(input))
					return false;

				state_ = method;
				break;
			case method:
				if (input == ' ')
				{
					r.method = data.buffer().ref(left_, cur - left_);
					state_ = uri;
					left_ = cur + 1;
				}
				else if (!is_char(input) || is_ctl(input) || is_tspecial(input))
					return false;

				break;
			case uri_start:
				if (is_ctl(input))
					return false;

				state_ = uri;
				break;
			case uri:
				if (input == ' ')
				{
					r.uri = data.buffer().ref(left_, cur - left_);
					left_ = cur + 1;

					if (!url_decode(r.uri))
						return false;

					std::size_t n = r.uri.find("?");
					if (n != std::string::npos)
					{
						r.path = r.uri.ref(0, n);
						r.query = r.uri.ref(n + 1);
					}
					else
					{
						r.path = r.uri;
					}

					if (r.path.empty() || r.path[0] != '/' || r.path.find("..") != std::string::npos)
						return false;

					state_ = http_version_h;
				}
				else if (is_ctl(input))
					return false;

				break;
			case http_version_h:
				if (input != 'H')
					return false;

				state_ = http_version_t_1;
				break;
			case http_version_t_1:
				if (input != 'T')
					return false;

				state_ = http_version_t_2;
				break;
			case http_version_t_2:
				if (input != 'T')
					return false;

				state_ = http_version_p;
				break;
			case http_version_p:
				if (input != 'P')
					return false;

				state_ = http_version_slash;
				break;
			case http_version_slash:
				if (input != '/')
					return false;

				r.http_version_major = 0;
				r.http_version_minor = 0;

				state_ = http_version_major_start;
				break;
			case http_version_major_start:
				if (!is_digit(input))
					return false;

				r.http_version_major = r.http_version_major * 10 + input - '0';
				state_ = http_version_major;
				break;
			case http_version_major:
				if (input == '.')
					state_ = http_version_minor_start;
				else if (is_digit(input))
					r.http_version_major = r.http_version_major * 10 + input - '0';
				else
					return false;

				break;
			case http_version_minor_start:
				if (input == '\r')
					state_ = expecting_newline_1;
				else if (is_digit(input))
					r.http_version_minor = r.http_version_minor * 10 + input - '0';
				else
					return false;

				break;
			case expecting_newline_1:
				if (input != '\n')
					return false;

				state_ = header_line_start;
				break;
			case header_line_start:
				if (input == '\r')
					state_ = expecting_newline_3;
				else if (!r.headers.empty() && (input == ' ' || input == '\t'))
					state_ = header_lws;
				else if (!is_char(input) || is_ctl(input) || is_tspecial(input))
					return false;
				else
				{
					r.headers.push_back(x0::request_header());
					//r.headers.back().name.push_back(input);
					r.headers.back().name = data.buffer().ref(cur, 1);

					state_ = header_name;
				}
				break;
			case header_lws:
				if (input == '\r')
					state_ = expecting_newline_2;
				else if (input != ' ' && input != '\t')
				{
					state_ = header_value;
					r.headers.back().value = data.buffer().ref(cur, 1);
				}
				break;
			case header_name:
				if (input == ':')
					state_ = space_before_header_value;
				else if (!is_char(input) || is_ctl(input) || is_tspecial(input))
					return false;
				else
					r.headers.back().name.shr(1);

				break;
			case space_before_header_value:
				if (input != ' ')
					return false;

				state_ = header_value;
				break;
			case header_value:
				if (input == '\r')
					state_ = expecting_newline_2;
				else if (is_ctl(input))
					return false;
				else if (r.headers.back().value.empty())
					r.headers.back().value = data.buffer().ref(cur, 1);
				else
					r.headers.back().value.shr(1);

				break;
			case expecting_newline_2:
				if (input != '\n')
					return false;

				state_ = header_line_start;
				break;
			case expecting_newline_3:
				if (input == '\n')
				{
					buffer_ref s(r.header("Content-Length"));
					if (!s.empty())
					{
						state_ = reading_body;
						r.body.reserve(std::atoi(s.data()));
						break;
					}
					else
					{
						return true;
					}
				}
				else
				{
					return false;
				}
			case reading_body:
				r.body.push_back(input);

				if (r.body.length() < r.body.capacity())
				{
					break;
				}
				else
				{
					return true;
				}
			default:
				return false;
		}
	}

	// request header parsed partially
	return boost::indeterminate;
}
// }}}

//@}

} // namespace x0

#endif
<commit_msg>core: comment-foo<commit_after>/* <x0/request.hpp>
 *
 * This file is part of the x0 web server project and is released under LGPL-3.
 *
 * (c) 2009 Chrisitan Parpart <trapni@gentoo.org>
 */

#ifndef x0_http_request_hpp
#define x0_http_request_hpp (1)

#include <x0/buffer.hpp>
#include <x0/header.hpp>
#include <x0/fileinfo.hpp>
#include <x0/strutils.hpp>
#include <x0/types.hpp>
#include <x0/api.hpp>
#include <string>
#include <vector>
#include <boost/tuple/tuple.hpp>
#include <boost/logic/tribool.hpp>

namespace x0 {

//! \addtogroup core
//@{

/**
 * \brief a client HTTP reuqest object, holding the parsed x0 request data.
 *
 * \see header, response, connection, server
 */
struct request
{
public:
	class reader;

public:
	explicit request(x0::connection& connection);

	/// the TCP/IP connection this request has been sent through
	x0::connection& connection;

public: // request properties
	/// HTTP request method, e.g. HEAD, GET, POST, PUT, etc.
	buffer_ref method;

	/// parsed request uri
	buffer_ref uri;

	/// decoded path-part
	buffer_ref path;

	/// the final entity to be served, for example the full path to the file on disk.
	fileinfo_ptr fileinfo;

	/// decoded query-part
	buffer_ref query;

	/// HTTP protocol version major part that this request was formed in
	int http_version_major;
	/// HTTP protocol version minor part that this request was formed in
	int http_version_minor;

	/// request headers
	std::vector<x0::request_header> headers;

	/** retrieve value of a given request header */
	buffer_ref header(const std::string& name) const;

	/// body
	std::string body;

public: // accumulated request data
	/// username this client has authenticated with.
	buffer_ref username;

	/// the document root directory for this request.
	std::string document_root;

//	std::string if_modified_since;		//!< "If-Modified-Since" request header value, if specified.
//	std::shared_ptr<range_def> range;	//!< parsed "Range" request header

public: // utility methods
	bool supports_protocol(int major, int minor) const;
	std::string hostid() const;
};

/**
 * \brief implements the HTTP request parser.
 *
 * \see request, connection
 */
class request::reader
{
public:
	enum state
	{
		method_start,
		method,
		uri_start,
		uri,
		http_version_h,
		http_version_t_1,
		http_version_t_2,
		http_version_p,
		http_version_slash,
		http_version_major_start,
		http_version_major,
		http_version_minor_start,
		http_version_minor,
		expecting_newline_1,
		header_line_start,
		header_lws,
		header_name,
		space_before_header_value,
		header_value,
		expecting_newline_2,
		expecting_newline_3,
		reading_body
	};

private:
	state state_;
	std::size_t left_;

private:
	static inline bool is_char(int ch);
	static inline bool is_ctl(int ch);
	static inline bool is_tspecial(int ch);
	static inline bool is_digit(int ch);

	static inline bool url_decode(buffer_ref& url);

public:
	reader();

	void reset();

	/** parses partial HTTP request.
	 *
	 * \param r request to fill with parsed data
	 * \param data buffer holding the (possibly partial) data of the request to be parsed.
	 *
	 * \retval true request has been fully parsed.
	 * \retval false HTTP request parser error (should result into bad_request if possible.)
	 * \retval indeterminate parsial request parsed successfully but more input is needed to complete parsing.
	 */
	inline boost::tribool parse(request& req, const buffer_ref& data);
};

// {{{ request impl
inline request::request(x0::connection& conn) :
	connection(conn)
{
}

inline bool request::supports_protocol(int major, int minor) const
{
	if (major == http_version_major && minor <= http_version_minor)
		return true;

	if (major < http_version_major)
		return true;

	return false;
}
// }}}

// {{{ request::reader impl
inline bool request::reader::is_char(int ch)
{
	return ch >= 0 && ch < 127;
}

inline bool request::reader::is_ctl(int ch)
{
	return (ch >= 0 && ch <= 31) || ch == 127;
}

inline bool request::reader::is_tspecial(int ch)
{
	switch (ch)
	{
		case '(':
		case ')':
		case '<':
		case '>':
		case '@':
		case ',':
		case ';':
		case ':':
		case '\\':
		case '"':
		case '/':
		case '[':
		case ']':
		case '?':
		case '=':
		case '{':
		case '}':
		case ' ':
		case '\t':
			return true;
		default:
			return false;
	}
}

inline bool request::reader::is_digit(int ch)
{
	return ch >= '0' && ch <= '9';
}

inline bool request::reader::url_decode(buffer_ref& url)
{
	std::size_t left = url.offset();
	std::size_t right = left + url.size();
	std::size_t i = left; // read pos
	std::size_t d = left; // write pos
	buffer& value = url.buffer();

	while (i != right)
	{
		if (value[i] == '%')
		{
			if (i + 3 <= right)
			{
				int ival;
				if (hex2int(value.begin() + i + 1, value.begin() + i + 3, ival))
				{
					value[d++] = static_cast<char>(ival);
					i += 3;
				}
				else
				{
					return false;
				}
			}
			else
			{
				return false;
			}
		}
		else if (value[i] == '+')
		{
			value[d++] = ' ';
			++i;
		}
		else if (d != i)
		{
			value[d++] = value[i++];
		}
		else
		{
			++d;
			++i;
		}
	}

	url = value.ref(left, d - left);
	return true;
}

inline request::reader::reader() :
	state_(method_start), left_(0)
{
}

inline void request::reader::reset()
{
	state_ = method_start;
	left_ = 0;
}

inline boost::tribool request::reader::parse(request& r, const buffer_ref& data)
{
	std::size_t cur = data.offset();
	std::size_t count = cur + data.size();
	buffer_ref::const_iterator i = data.begin();

	for (; cur != count; ++cur)
	{
		char input = *i++;

		switch (state_)
		{
			case method_start:
				if (!is_char(input) || is_ctl(input) || is_tspecial(input))
					return false;

				state_ = method;
				break;
			case method:
				if (input == ' ')
				{
					r.method = data.buffer().ref(left_, cur - left_);
					state_ = uri;
					left_ = cur + 1;
				}
				else if (!is_char(input) || is_ctl(input) || is_tspecial(input))
					return false;

				break;
			case uri_start:
				if (is_ctl(input))
					return false;

				state_ = uri;
				break;
			case uri:
				if (input == ' ')
				{
					r.uri = data.buffer().ref(left_, cur - left_);
					left_ = cur + 1;

					if (!url_decode(r.uri))
						return false;

					std::size_t n = r.uri.find("?");
					if (n != std::string::npos)
					{
						r.path = r.uri.ref(0, n);
						r.query = r.uri.ref(n + 1);
					}
					else
					{
						r.path = r.uri;
					}

					if (r.path.empty() || r.path[0] != '/' || r.path.find("..") != std::string::npos)
						return false;

					state_ = http_version_h;
				}
				else if (is_ctl(input))
					return false;

				break;
			case http_version_h:
				if (input != 'H')
					return false;

				state_ = http_version_t_1;
				break;
			case http_version_t_1:
				if (input != 'T')
					return false;

				state_ = http_version_t_2;
				break;
			case http_version_t_2:
				if (input != 'T')
					return false;

				state_ = http_version_p;
				break;
			case http_version_p:
				if (input != 'P')
					return false;

				state_ = http_version_slash;
				break;
			case http_version_slash:
				if (input != '/')
					return false;

				r.http_version_major = 0;
				r.http_version_minor = 0;

				state_ = http_version_major_start;
				break;
			case http_version_major_start:
				if (!is_digit(input))
					return false;

				r.http_version_major = r.http_version_major * 10 + input - '0';
				state_ = http_version_major;
				break;
			case http_version_major:
				if (input == '.')
					state_ = http_version_minor_start;
				else if (is_digit(input))
					r.http_version_major = r.http_version_major * 10 + input - '0';
				else
					return false;

				break;
			case http_version_minor_start:
				if (input == '\r')
					state_ = expecting_newline_1;
				else if (is_digit(input))
					r.http_version_minor = r.http_version_minor * 10 + input - '0';
				else
					return false;

				break;
			case expecting_newline_1:
				if (input != '\n')
					return false;

				state_ = header_line_start;
				break;
			case header_line_start:
				if (input == '\r')
					state_ = expecting_newline_3;
				else if (!r.headers.empty() && (input == ' ' || input == '\t'))
					state_ = header_lws; // header-value continuation
				else if (!is_char(input) || is_ctl(input) || is_tspecial(input))
					return false;
				else
				{
					r.headers.push_back(x0::request_header());
					//r.headers.back().name.push_back(input);
					r.headers.back().name = data.buffer().ref(cur, 1);

					state_ = header_name;
				}
				break;
			case header_lws:
				if (input == '\r')
					state_ = expecting_newline_2;
				else if (input != ' ' && input != '\t')
				{
					state_ = header_value;
					r.headers.back().value = data.buffer().ref(cur, 1);
				}
				break;
			case header_name:
				if (input == ':')
					state_ = space_before_header_value;
				else if (!is_char(input) || is_ctl(input) || is_tspecial(input))
					return false;
				else
					r.headers.back().name.shr(1);

				break;
			case space_before_header_value:
				if (input != ' ')
					return false;

				state_ = header_value;
				break;
			case header_value:
				if (input == '\r')
					state_ = expecting_newline_2;
				else if (is_ctl(input))
					return false;
				else if (r.headers.back().value.empty())
					r.headers.back().value = data.buffer().ref(cur, 1);
				else
					r.headers.back().value.shr(1);

				break;
			case expecting_newline_2:
				if (input != '\n')
					return false;

				state_ = header_line_start;
				break;
			case expecting_newline_3:
				if (input == '\n')
				{
					buffer_ref s(r.header("Content-Length"));
					if (!s.empty())
					{
						state_ = reading_body;
						r.body.reserve(std::atoi(s.data()));
						break;
					}
					else
					{
						return true;
					}
				}
				else
				{
					return false;
				}
			case reading_body:
				r.body.push_back(input);

				if (r.body.length() < r.body.capacity())
				{
					break;
				}
				else
				{
					return true;
				}
			default:
				return false;
		}
	}

	// request header parsed partially
	return boost::indeterminate;
}
// }}}

//@}

} // namespace x0

#endif
<|endoftext|>


<commit_before>#include "include/udata.h"
#include "include/amici_exception.h"
#include <cstdio>
#include <cstring>
#include <algorithm>

namespace amici {

UserData::UserData(const int np, const int nk, const int nx) : sizex(nx) {
    // these fields must always be initialized, others are optional or can be set later
    konst.resize(nk);
    par.resize(np);
    unpar.resize(np);
    qpositivex.assign(nx,1);
}

UserData::UserData() : sizex(0) {
    konst.resize(0);
    par.resize(0);
    unpar.resize(0);
    qpositivex.assign(0,1);
}

UserData::UserData(const UserData &other) : UserData(other.np(), other.nk(), other.nx())
{
    nmaxevent = other.nmaxevent;
    qpositivex = other.qpositivex;
    p_index = other.p_index;
    par = other.par;
    unpar = other.unpar;
    konst = other.konst;
    pscale = other.pscale;
    tstart = other.tstart;
    ts = other.ts;
    pbar = other.pbar;
    xbar = other.xbar;
    sensi = other.sensi;
    atol = other.atol;
    rtol = other.rtol;
    maxsteps = other.maxsteps;
    quad_atol = other.quad_atol;
    quad_rtol = other.quad_rtol;
    maxstepsB = other.maxstepsB;
    newton_maxsteps = other.newton_maxsteps;
    newton_maxlinsteps = other.newton_maxlinsteps;
    newton_preeq = other.newton_preeq;
    newton_precon = other.newton_precon;
    ism = other.ism;
    sensi_meth = other.sensi_meth;
    linsol = other.linsol;
    interpType = other.interpType;
    lmm = other.lmm;
    iter = other.iter;
    stldet = other.stldet;
    x0data = other.x0data;
    sx0data = other.sx0data;
    ordering = other.ordering;
    newton_precon = other.newton_precon;
    ism = other.ism;
}

void UserData::unscaleParameters(double *bufferUnscaled) const {
    /**
     * unscaleParameters removes parameter scaling according to the parameter
     * scaling in pscale
     *
     * @param[out] bufferUnscaled unscaled parameters are written to the array
     * @type double
     *
     * @return status flag indicating success of execution @type int
     */
    switch (pscale) {
    case AMICI_SCALING_LOG10:
        for (int ip = 0; ip < np(); ++ip) {
            bufferUnscaled[ip] = pow(10, par[ip]);
        }
        break;
    case AMICI_SCALING_LN:
        for (int ip = 0; ip < np(); ++ip)
            bufferUnscaled[ip] = exp(par[ip]);
        break;
    case AMICI_SCALING_NONE:
        for (int ip = 0; ip < np(); ++ip)
            bufferUnscaled[ip] = par[ip];
        break;
    }
}

void UserData::setTimepoints(const double * timepoints, int numTimepoints) {
    ts.resize(numTimepoints);
    memcpy(ts.data(), timepoints, sizeof(double) * numTimepoints);
}

void UserData::setParameters(const double * parameters) {
    memcpy(par.data(), parameters, sizeof(double) * np());
    unscaleParameters(unpar.data());
}

void UserData::setConstants(const double *constants) {
    memcpy(konst.data(), constants, sizeof(double) * nk());
}

void UserData::setPlist(const double *plist, int length) {
    if(!plist)
        throw AmiException("Provided plist was a nullptr, please provide a valid pointer.");
    p_index.resize(length);
    pbar.resize(nplist());
    std::fill(pbar.begin(),pbar.end(),1.0);
    for (int ip = 0; ip < length; ip++) {
        p_index[ip] = (int)plist[ip];
    }
}

void UserData::setPlist(const int *plist, int length) {
    if(!plist)
        throw AmiException("Provided plist was a nullptr, please provide a valid pointer.");
    p_index.resize(length);
    pbar.resize(nplist());
    std::fill(pbar.begin(),pbar.end(),1.0);
    memcpy(p_index.data(), plist, sizeof(int) * length);
}

void UserData::setPScale(const AMICI_parameter_scaling pscale) {
    this->pscale = pscale;
    unscaleParameters(unpar.data());
}

const AMICI_parameter_scaling UserData::getPScale() const {
    return pscale;
}

void UserData::requireSensitivitiesForAllParameters()
{
    p_index.resize(nplist());
    for (int i = 0; i < nplist(); ++i)
        p_index[i] = i;

}

void UserData::setPbar(const double *parameterScaling) {
    if(parameterScaling) {
        pbar.resize(nplist());
        memcpy(pbar.data(), parameterScaling, sizeof(double) * nplist());
    } else {
        pbar.clear();
    }
}

const double *UserData::getPbar() const {
    return pbar.data();
}

void UserData::setXbar(const double *stateScaling) {
    if(stateScaling){
        xbar.resize(nx());
        memcpy(xbar.data(), stateScaling, sizeof(double) * nx());
    } else {
        xbar.clear();
    }
}

void UserData::setStateInitialization(const double *stateInitialization) {
    if(stateInitialization) {
        x0data.resize(nx());
        memcpy(x0data.data(), stateInitialization, sizeof(double) * nx());
    } else {
        x0data.clear();
    }
}

void UserData::setSensitivityInitialization(
    const double *sensitivityInitialization) {
    if(sensitivityInitialization) {
        sx0data.resize(nx() * nplist());
        memcpy(sx0data.data(), sensitivityInitialization, sizeof(double) * nx() * nplist());
    } else {
        sx0data.clear();
    }
}

/**
 * @brief getLinearMultistepMethod
 * @return lmm
 */
const LinearMultistepMethod UserData::getLinearMultistepMethod() const{
    return lmm;
}

/**
 * @brief getNonlinearSolverIteration
 * @return iter
 */
const NonlinearSolverIteration UserData::getNonlinearSolverIteration() const{
    return iter;
}

/**
 * @brief getInterpolationType
 * @return interType
 */
const InterpolationType UserData::getInterpolationType() const{
    return interpType;
}

/**
 * @brief getStateOrdering
 * @return ordering
 */
const StateOrdering UserData::getStateOrdering() const{
    return ordering;
}

/**
 * @brief getStabilityLimitFlag
 * @return stldet
 */
const int UserData::getStabilityLimitFlag() const{
    return stldet;
}

UserData::~UserData() {
}

void UserData::print() const {
    printf("qpositivex: %p\n", qpositivex.data());
    printf("plist: %p\n", p_index.data());
    printf("nplist: %d\n", nplist());
    printf("nt: %d\n", nt());
    printf("nmaxevent: %d\n", nmaxevent);
    printf("p: %p\n", par.data());
    printf("k: %p\n", konst.data());
    printf("tstart: %e\n", tstart);
    printf("ts: %p\n", ts.data());
    printf("pbar: %p\n", pbar.data());
    printf("xbar: %p\n", xbar.data());
    printf("sensi: %d\n", sensi);
    printf("atol: %e\n", atol);
    printf("rtol: %e\n", rtol);
    printf("maxsteps: %d\n", maxsteps);
    printf("quad_atol: %e\n", quad_atol);
    printf("quad_rtol: %e\n", quad_rtol);
    printf("maxstepsB: %d\n", maxstepsB);
    printf("newton_maxsteps: %d\n", newton_maxsteps);
    printf("newton_maxlinsteps: %d\n", newton_maxlinsteps);
    printf("ism: %d\n", ism);
    printf("sensi_meth: %d\n", sensi_meth);
    printf("linsol: %d\n", linsol);
    printf("interpType: %d\n", interpType);
    printf("lmm: %d\n", lmm);
    printf("iter: %d\n", iter);
    printf("stldet: %d\n", stldet);
    printf("x0data: %p\n", x0data.data());
    printf("sx0data: %p\n", sx0data.data());
    printf("ordering: %d\n", ordering);
}

} // namespace amici
<commit_msg>moved the setting of default maxstepsB from Matlab to cpp code<commit_after>#include "include/udata.h"
#include "include/amici_exception.h"
#include <cstdio>
#include <cstring>
#include <algorithm>

namespace amici {

UserData::UserData(const int np, const int nk, const int nx) : sizex(nx) {
    // these fields must always be initialized, others are optional or can be set later
    konst.resize(nk);
    par.resize(np);
    unpar.resize(np);
    qpositivex.assign(nx,1);
}

UserData::UserData() : sizex(0) {
    konst.resize(0);
    par.resize(0);
    unpar.resize(0);
    qpositivex.assign(0,1);
}

UserData::UserData(const UserData &other) : UserData(other.np(), other.nk(), other.nx())
{
    nmaxevent = other.nmaxevent;
    qpositivex = other.qpositivex;
    p_index = other.p_index;
    par = other.par;
    unpar = other.unpar;
    konst = other.konst;
    pscale = other.pscale;
    tstart = other.tstart;
    ts = other.ts;
    pbar = other.pbar;
    xbar = other.xbar;
    sensi = other.sensi;
    atol = other.atol;
    rtol = other.rtol;
    quad_atol = other.quad_atol;
    quad_rtol = other.quad_rtol;
    maxsteps = other.maxsteps;
    maxstepsB = other.maxstepsB;
    if (maxstepsB == 0)
        maxstepsB = 100 * maxsteps;
    newton_maxsteps = other.newton_maxsteps;
    newton_maxlinsteps = other.newton_maxlinsteps;
    newton_preeq = other.newton_preeq;
    newton_precon = other.newton_precon;
    ism = other.ism;
    sensi_meth = other.sensi_meth;
    linsol = other.linsol;
    interpType = other.interpType;
    lmm = other.lmm;
    iter = other.iter;
    stldet = other.stldet;
    x0data = other.x0data;
    sx0data = other.sx0data;
    ordering = other.ordering;
    newton_precon = other.newton_precon;
    ism = other.ism;
}

void UserData::unscaleParameters(double *bufferUnscaled) const {
    /**
     * unscaleParameters removes parameter scaling according to the parameter
     * scaling in pscale
     *
     * @param[out] bufferUnscaled unscaled parameters are written to the array
     * @type double
     *
     * @return status flag indicating success of execution @type int
     */
    switch (pscale) {
    case AMICI_SCALING_LOG10:
        for (int ip = 0; ip < np(); ++ip) {
            bufferUnscaled[ip] = pow(10, par[ip]);
        }
        break;
    case AMICI_SCALING_LN:
        for (int ip = 0; ip < np(); ++ip)
            bufferUnscaled[ip] = exp(par[ip]);
        break;
    case AMICI_SCALING_NONE:
        for (int ip = 0; ip < np(); ++ip)
            bufferUnscaled[ip] = par[ip];
        break;
    }
}

void UserData::setTimepoints(const double * timepoints, int numTimepoints) {
    ts.resize(numTimepoints);
    memcpy(ts.data(), timepoints, sizeof(double) * numTimepoints);
}

void UserData::setParameters(const double * parameters) {
    memcpy(par.data(), parameters, sizeof(double) * np());
    unscaleParameters(unpar.data());
}

void UserData::setConstants(const double *constants) {
    memcpy(konst.data(), constants, sizeof(double) * nk());
}

void UserData::setPlist(const double *plist, int length) {
    if(!plist)
        throw AmiException("Provided plist was a nullptr, please provide a valid pointer.");
    p_index.resize(length);
    pbar.resize(nplist());
    std::fill(pbar.begin(),pbar.end(),1.0);
    for (int ip = 0; ip < length; ip++) {
        p_index[ip] = (int)plist[ip];
    }
}

void UserData::setPlist(const int *plist, int length) {
    if(!plist)
        throw AmiException("Provided plist was a nullptr, please provide a valid pointer.");
    p_index.resize(length);
    pbar.resize(nplist());
    std::fill(pbar.begin(),pbar.end(),1.0);
    memcpy(p_index.data(), plist, sizeof(int) * length);
}

void UserData::setPScale(const AMICI_parameter_scaling pscale) {
    this->pscale = pscale;
    unscaleParameters(unpar.data());
}

const AMICI_parameter_scaling UserData::getPScale() const {
    return pscale;
}

void UserData::requireSensitivitiesForAllParameters()
{
    p_index.resize(nplist());
    for (int i = 0; i < nplist(); ++i)
        p_index[i] = i;

}

void UserData::setPbar(const double *parameterScaling) {
    if(parameterScaling) {
        pbar.resize(nplist());
        memcpy(pbar.data(), parameterScaling, sizeof(double) * nplist());
    } else {
        pbar.clear();
    }
}

const double *UserData::getPbar() const {
    return pbar.data();
}

void UserData::setXbar(const double *stateScaling) {
    if(stateScaling){
        xbar.resize(nx());
        memcpy(xbar.data(), stateScaling, sizeof(double) * nx());
    } else {
        xbar.clear();
    }
}

void UserData::setStateInitialization(const double *stateInitialization) {
    if(stateInitialization) {
        x0data.resize(nx());
        memcpy(x0data.data(), stateInitialization, sizeof(double) * nx());
    } else {
        x0data.clear();
    }
}

void UserData::setSensitivityInitialization(
    const double *sensitivityInitialization) {
    if(sensitivityInitialization) {
        sx0data.resize(nx() * nplist());
        memcpy(sx0data.data(), sensitivityInitialization, sizeof(double) * nx() * nplist());
    } else {
        sx0data.clear();
    }
}

/**
 * @brief getLinearMultistepMethod
 * @return lmm
 */
const LinearMultistepMethod UserData::getLinearMultistepMethod() const{
    return lmm;
}

/**
 * @brief getNonlinearSolverIteration
 * @return iter
 */
const NonlinearSolverIteration UserData::getNonlinearSolverIteration() const{
    return iter;
}

/**
 * @brief getInterpolationType
 * @return interType
 */
const InterpolationType UserData::getInterpolationType() const{
    return interpType;
}

/**
 * @brief getStateOrdering
 * @return ordering
 */
const StateOrdering UserData::getStateOrdering() const{
    return ordering;
}

/**
 * @brief getStabilityLimitFlag
 * @return stldet
 */
const int UserData::getStabilityLimitFlag() const{
    return stldet;
}

UserData::~UserData() {
}

void UserData::print() const {
    printf("qpositivex: %p\n", qpositivex.data());
    printf("plist: %p\n", p_index.data());
    printf("nplist: %d\n", nplist());
    printf("nt: %d\n", nt());
    printf("nmaxevent: %d\n", nmaxevent);
    printf("p: %p\n", par.data());
    printf("k: %p\n", konst.data());
    printf("tstart: %e\n", tstart);
    printf("ts: %p\n", ts.data());
    printf("pbar: %p\n", pbar.data());
    printf("xbar: %p\n", xbar.data());
    printf("sensi: %d\n", sensi);
    printf("atol: %e\n", atol);
    printf("rtol: %e\n", rtol);
    printf("maxsteps: %d\n", maxsteps);
    printf("quad_atol: %e\n", quad_atol);
    printf("quad_rtol: %e\n", quad_rtol);
    printf("maxstepsB: %d\n", maxstepsB);
    printf("newton_maxsteps: %d\n", newton_maxsteps);
    printf("newton_maxlinsteps: %d\n", newton_maxlinsteps);
    printf("ism: %d\n", ism);
    printf("sensi_meth: %d\n", sensi_meth);
    printf("linsol: %d\n", linsol);
    printf("interpType: %d\n", interpType);
    printf("lmm: %d\n", lmm);
    printf("iter: %d\n", iter);
    printf("stldet: %d\n", stldet);
    printf("x0data: %p\n", x0data.data());
    printf("sx0data: %p\n", sx0data.data());
    printf("ordering: %d\n", ordering);
}

} // namespace amici
<|endoftext|>


<commit_before>#include "utils.h"
//
#include <fstream>      // fstream
#include <boost/tokenizer.hpp>
#include <boost/numeric/ublas/matrix.hpp>

using namespace std;
using namespace boost;
using namespace boost::numeric::ublas;

std::ostream& operator<<(std::ostream& os, const map<int, double>& int_double_map) {
  map<int, double>::const_iterator it = int_double_map.begin();
  os << "{";
  if(it==int_double_map.end()) {
    os << "}";
    return os;
  }
  os << it->first << ":" << it->second;
  it++;
  for(; it!=int_double_map.end(); it++) {
    os << ", " << it->first << ":" << it->second;
  }
  os << "}";
  return  os;
}

std::ostream& operator<<(std::ostream& os, const map<int, int>& int_int_map) {
  map<int, int>::const_iterator it = int_int_map.begin();
  os << "{";
  if(it==int_int_map.end()) {
    os << "}";
    return os;
  }
  os << it->first << ":" << it->second;
  it++;
  for(; it!=int_int_map.end(); it++) {
    os << ", " << it->first << ":" << it->second;
  }
  os << "}";
  return  os;
}

string int_to_str(int i) {
  std::stringstream out;
  out << i;
  string s = out.str();
  return s;
}

// FROM runModel_v2.cpp
/////////////////////////////////////////////////////////////////////
// expect a csv file of data
void LoadData(string file, boost::numeric::ublas::matrix<double>& M) {
  ifstream in(file.c_str());
  if (!in.is_open()) return;
  typedef tokenizer< char_separator<char> > Tokenizer;
  char_separator<char> sep(",");

  string line;
  int nrows = 0;
  int ncols = 0;
  std::vector<string> vec;

  // get the size first
  while (std::getline(in,line)) {
    Tokenizer tok(line, sep);
    vec.assign(tok.begin(), tok.end());
    ncols = vec.end() - vec.begin();
    nrows++;
  }
  cout << "num rows = "<< nrows << "  num cols = " << ncols << endl;

  // create a matrix to hold data
  matrix<double> Data(nrows, ncols);

  // make second pass
  in.clear();
  in.seekg(0);
  int r = 0;
  while (std::getline(in,line)) {
    Tokenizer tok(line, sep);
    vec.assign(tok.begin(), tok.end());
    int i = 0;
    for(i=0; i < vec.size() ; i++) {
      Data(r, i) = ::strtod(vec[i].c_str(), 0);
    }
    r++;
  }
  M = Data;
}

bool is_almost(double val1, double val2, double precision) {
  return abs(val1-val2) < precision;
}

// http://stackoverflow.com/a/11747023/1769715
std::vector<double> linspace(double a, double b, int n) {
  std::vector<double> array;
  double step = (b-a) / (n-1);
  while(a <= b) {
    array.push_back(a);
    a += step;
  }
  return array;
}

std::vector<double> log_linspace(double a, double b, int n) {
  std::vector<double> values = linspace(log(a), log(b), n);
  std::transform(values.begin(), values.end(), values.begin(), (double (*)(double))exp);
  return values;
}
<commit_msg>linspace: change variable name from array to values to avoid confusion with boost arrays<commit_after>#include "utils.h"
//
#include <fstream>      // fstream
#include <boost/tokenizer.hpp>
#include <boost/numeric/ublas/matrix.hpp>

using namespace std;
using namespace boost;
using namespace boost::numeric::ublas;

std::ostream& operator<<(std::ostream& os, const map<int, double>& int_double_map) {
  map<int, double>::const_iterator it = int_double_map.begin();
  os << "{";
  if(it==int_double_map.end()) {
    os << "}";
    return os;
  }
  os << it->first << ":" << it->second;
  it++;
  for(; it!=int_double_map.end(); it++) {
    os << ", " << it->first << ":" << it->second;
  }
  os << "}";
  return  os;
}

std::ostream& operator<<(std::ostream& os, const map<int, int>& int_int_map) {
  map<int, int>::const_iterator it = int_int_map.begin();
  os << "{";
  if(it==int_int_map.end()) {
    os << "}";
    return os;
  }
  os << it->first << ":" << it->second;
  it++;
  for(; it!=int_int_map.end(); it++) {
    os << ", " << it->first << ":" << it->second;
  }
  os << "}";
  return  os;
}

string int_to_str(int i) {
  std::stringstream out;
  out << i;
  string s = out.str();
  return s;
}

// FROM runModel_v2.cpp
/////////////////////////////////////////////////////////////////////
// expect a csv file of data
void LoadData(string file, boost::numeric::ublas::matrix<double>& M) {
  ifstream in(file.c_str());
  if (!in.is_open()) return;
  typedef tokenizer< char_separator<char> > Tokenizer;
  char_separator<char> sep(",");

  string line;
  int nrows = 0;
  int ncols = 0;
  std::vector<string> vec;

  // get the size first
  while (std::getline(in,line)) {
    Tokenizer tok(line, sep);
    vec.assign(tok.begin(), tok.end());
    ncols = vec.end() - vec.begin();
    nrows++;
  }
  cout << "num rows = "<< nrows << "  num cols = " << ncols << endl;

  // create a matrix to hold data
  matrix<double> Data(nrows, ncols);

  // make second pass
  in.clear();
  in.seekg(0);
  int r = 0;
  while (std::getline(in,line)) {
    Tokenizer tok(line, sep);
    vec.assign(tok.begin(), tok.end());
    int i = 0;
    for(i=0; i < vec.size() ; i++) {
      Data(r, i) = ::strtod(vec[i].c_str(), 0);
    }
    r++;
  }
  M = Data;
}

bool is_almost(double val1, double val2, double precision) {
  return abs(val1-val2) < precision;
}

// http://stackoverflow.com/a/11747023/1769715
std::vector<double> linspace(double a, double b, int n) {
  std::vector<double> values;
  double step = (b-a) / (n-1);
  while(a <= b) {
    values.push_back(a);
    a += step;
  }
  return values;
}

std::vector<double> log_linspace(double a, double b, int n) {
  std::vector<double> values = linspace(log(a), log(b), n);
  std::transform(values.begin(), values.end(), values.begin(), (double (*)(double))exp);
  return values;
}
<|endoftext|>


<commit_before>// Copyright 2010-2012 RethinkDB, all rights reserved.
#ifndef UTILS_HPP_
#define UTILS_HPP_

#ifndef __STDC_FORMAT_MACROS
#define __STDC_FORMAT_MACROS
#endif
#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS
#endif

#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>

#ifdef VALGRIND
#include <valgrind/memcheck.h>
#endif  // VALGRIND

#include <stdexcept>
#include <string>
#include <vector>

#include "containers/printf_buffer.hpp"
#include "errors.hpp"
#include "config/args.hpp"

void run_generic_global_startup_behavior();

struct const_charslice {
    const char *beg, *end;
    const_charslice(const char *_beg, const char *_end) : beg(_beg), end(_end) { }
    const_charslice() : beg(NULL), end(NULL) { }
};

typedef uint64_t microtime_t;

microtime_t current_microtime();

/* General exception to be thrown when some process is interrupted. It's in
`utils.hpp` because I can't think where else to put it */
class interrupted_exc_t : public std::exception {
public:
    const char *what() const throw () {
        return "interrupted";
    }
};

/* Pad a value to the size of a cache line to avoid false sharing.
 * TODO: This is implemented as a struct with subtraction rather than a union
 * so that it gives an error when trying to pad a value bigger than
 * CACHE_LINE_SIZE. If that's needed, this may have to be done differently.
 */
template<typename value_t>
struct cache_line_padded_t {
    value_t value;
    char padding[CACHE_LINE_SIZE - sizeof(value_t)];
};

void *malloc_aligned(size_t size, size_t alignment = 64);

template <class T1, class T2>
T1 ceil_aligned(T1 value, T2 alignment) {
    return value + alignment - (((value + alignment - 1) % alignment) + 1);
}

template <class T1, class T2>
T1 ceil_divide(T1 dividend, T2 alignment) {
    return (dividend + alignment - 1) / alignment;
}

template <class T1, class T2>
T1 floor_aligned(T1 value, T2 alignment) {
    return value - (value % alignment);
}

template <class T1, class T2>
T1 ceil_modulo(T1 value, T2 alignment) {
    T1 x = (value + alignment - 1) % alignment;
    return value + alignment - ((x < 0 ? x + alignment : x) + 1);
}

inline bool divides(int64_t x, int64_t y) {
    return y % x == 0;
}

int gcd(int x, int y);

int64_t round_up_to_power_of_two(int64_t x);

timespec clock_monotonic();
timespec clock_realtime();

typedef uint64_t ticks_t;
ticks_t secs_to_ticks(time_t secs);
ticks_t get_ticks();
time_t get_secs();
double ticks_to_secs(ticks_t ticks);

#ifndef NDEBUG
#define trace_call(fn, args...) do {                                          \
        debugf("%s:%u: %s: entered\n", __FILE__, __LINE__, stringify(fn));  \
        fn(args);                                                           \
        debugf("%s:%u: %s: returned\n", __FILE__, __LINE__, stringify(fn)); \
    } while (0)
#define TRACEPOINT debugf("%s:%u reached\n", __FILE__, __LINE__)
#else
#define trace_call(fn, args...) fn(args)
// TRACEPOINT is not defined in release, so that TRACEPOINTS do not linger in the code unnecessarily
#endif

// HEY: Maybe debugf and log_call and TRACEPOINT should be placed in
// debugf.hpp (and debugf.cc).
/* Debugging printing API (prints current thread in addition to message) */
void debug_print_quoted_string(append_only_printf_buffer_t *buf, const uint8_t *s, size_t n);
void debugf_prefix_buf(printf_buffer_t<1000> *buf);
void debugf_dump_buf(printf_buffer_t<1000> *buf);

// Primitive debug_print declarations.
void debug_print(append_only_printf_buffer_t *buf, uint64_t x);
void debug_print(append_only_printf_buffer_t *buf, const std::string& s);

#ifndef NDEBUG
void debugf(const char *msg, ...) __attribute__((format (printf, 1, 2)));
template <class T>
void debugf_print(const char *msg, const T& obj) {
    printf_buffer_t<1000> buf;
    debugf_prefix_buf(&buf);
    buf.appendf("%s: ", msg);
    debug_print(&buf, obj);
    buf.appendf("\n");
    debugf_dump_buf(&buf);
}
#else
#define debugf(...) ((void)0)
#define debugf_print(...) ((void)0)
#endif

class debugf_in_dtor_t {
public:
    explicit debugf_in_dtor_t(const char *msg, ...);
    ~debugf_in_dtor_t();
private:
    std::string message;
};

class rng_t {
public:
// Returns a random number in [0, n).  Is not perfectly uniform; the
// bias tends to get worse when RAND_MAX is far from a multiple of n.
    int randint(int n);
    explicit rng_t(int seed = -1);
private:
    unsigned short xsubi[3];
    DISABLE_COPYING(rng_t);
};

// Reads from /dev/urandom.  Use this sparingly, please.
void get_dev_urandom(void *out, int64_t nbytes);

int randint(int n);
std::string rand_string(int len);

bool begins_with_minus(const char *string);
// strtoul() and strtoull() will for some reason not fail if the input begins
// with a minus sign. strtou64_strict() does.  Also we fix the constness of the
// end parameter.
int64_t strtoi64_strict(const char *string, const char **end, int base);
uint64_t strtou64_strict(const char *string, const char **end, int base);

// These functions return false and set the result to 0 if the conversion fails or
// does not consume the whole string.
MUST_USE bool strtoi64_strict(const std::string &str, int base, int64_t *out_result);
MUST_USE bool strtou64_strict(const std::string &str, int base, uint64_t *out_result);

std::string strprintf(const char *format, ...) __attribute__ ((format (printf, 1, 2)));
std::string vstrprintf(const char *format, va_list ap);

// formatted time:
// yyyy-mm-ddThh:mm:ss.nnnnnnnnn   (29 characters)
const size_t formatted_time_length = 29;    // not including null

void format_time(struct timespec time, append_only_printf_buffer_t *buf);
std::string format_time(struct timespec time);

struct timespec parse_time(const std::string &str) THROWS_ONLY(std::runtime_error);

/* Printing binary data to stdout in a nice format */

void print_hd(const void *buf, size_t offset, size_t length);

// Fast string compare

int sized_strcmp(const uint8_t *str1, int len1, const uint8_t *str2, int len2);

/* The home thread mixin is a mixin for objects that can only be used
on a single thread. Its thread ID is exposed as the `home_thread()`
method. Some subclasses of `home_thread_mixin_debug_only_t` can move themselves to
another thread, modifying the field real_home_thread. */

#define INVALID_THREAD (-1)

class home_thread_mixin_debug_only_t {
public:
#ifndef NDEBUG
    void assert_thread() const;
#else
    void assert_thread() const { }
#endif

protected:
    explicit home_thread_mixin_debug_only_t(int specified_home_thread);
    home_thread_mixin_debug_only_t();
    virtual ~home_thread_mixin_debug_only_t() { }

private:
    DISABLE_COPYING(home_thread_mixin_debug_only_t);

#ifndef NDEBUG
    int real_home_thread;
#endif
};

class home_thread_mixin_t {
public:
    int home_thread() const { return real_home_thread; }
#ifndef NDEBUG
    void assert_thread() const;
#else
    void assert_thread() const { }
#endif

protected:
    explicit home_thread_mixin_t(int specified_home_thread);
    home_thread_mixin_t();
    virtual ~home_thread_mixin_t() { }

    int real_home_thread;

private:
    // Things with home threads should not be copyable, since we don't
    // want to nonchalantly copy their real_home_thread variable.
    DISABLE_COPYING(home_thread_mixin_t);
};

/* `on_thread_t` switches to the given thread in its constructor, then switches
back in its destructor. For example:

    printf("Suppose we are on thread 1.\n");
    {
        on_thread_t thread_switcher(2);
        printf("Now we are on thread 2.\n");
    }
    printf("And now we are on thread 1 again.\n");

*/

class on_thread_t : public home_thread_mixin_t {
public:
    explicit on_thread_t(int thread);
    ~on_thread_t();
};

template <class InputIterator, class UnaryPredicate>
bool all_match_predicate(InputIterator begin, InputIterator end, UnaryPredicate f) {
    bool res = true;
    for (; begin != end; begin++) {
        res &= f(*begin);
    }
    return res;
}

template <class T, class UnaryPredicate>
bool all_in_container_match_predicate (const T &container, UnaryPredicate f) {
    return all_match_predicate(container.begin(), container.end(), f);
}

bool notf(bool x);

/* Translates to and from `0123456789ABCDEF`. */
bool hex_to_int(char c, int *out);
char int_to_hex(int i);

std::string read_file(const char *path);

struct path_t {
    std::vector<std::string> nodes;
    bool is_absolute;
};

path_t parse_as_path(const std::string &);
std::string render_as_path(const path_t &);

enum region_join_result_t { REGION_JOIN_OK, REGION_JOIN_BAD_JOIN, REGION_JOIN_BAD_REGION };

template <class T>
class assignment_sentry_t {
public:
    assignment_sentry_t(T *v, const T &value) :
        var(v), old_value(*var) {
        *var = value;
    }
    ~assignment_sentry_t() {
        *var = old_value;
    }
private:
    T *var;
    T old_value;
};

std::string sanitize_for_logger(const std::string &s);
static inline std::string time2str(const time_t &t) {
    char timebuf[26]; // I apologize for the magic constant.
    //           ^^ See man 3 ctime_r
    return ctime_r(&t, timebuf);
}

std::string errno_string(int errsv);

int get_num_db_threads();

template <class T>
T valgrind_undefined(T value) {
#ifdef VALGRIND
    VALGRIND_MAKE_MEM_UNDEFINED(&value, sizeof(value));
#endif
    return value;
}

#define STR(x) #x
#define MSTR(x) STR(x) // Stringify a macro
#if defined __clang__
#define COMPILER "CLANG " __clang_version__
#elif defined __GNUC__
#define COMPILER "GCC " MSTR(__GNUC__) "." MSTR(__GNUC_MINOR__) "." MSTR(__GNUC_PATCHLEVEL__)
#else
#define COMPILER "UNKNOWN COMPILER"
#endif

#ifndef NDEBUG
#define RETHINKDB_VERSION_STR "rethinkdb " RETHINKDB_VERSION " (debug)" " (" COMPILER ")"
#else
#define RETHINKDB_VERSION_STR "rethinkdb " RETHINKDB_VERSION " (" COMPILER ")"
#endif

#define NULLPTR (static_cast<void *>(0))

#endif // UTILS_HPP_
<commit_msg>Added unused type portno_t in utils.hpp.<commit_after>// Copyright 2010-2012 RethinkDB, all rights reserved.
#ifndef UTILS_HPP_
#define UTILS_HPP_

#ifndef __STDC_FORMAT_MACROS
#define __STDC_FORMAT_MACROS
#endif
#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS
#endif

#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>

#ifdef VALGRIND
#include <valgrind/memcheck.h>
#endif  // VALGRIND

#include <stdexcept>
#include <string>
#include <vector>

#include "containers/printf_buffer.hpp"
#include "errors.hpp"
#include "config/args.hpp"

void run_generic_global_startup_behavior();

struct const_charslice {
    const char *beg, *end;
    const_charslice(const char *_beg, const char *_end) : beg(_beg), end(_end) { }
    const_charslice() : beg(NULL), end(NULL) { }
};

typedef uint64_t microtime_t;

microtime_t current_microtime();

/* General exception to be thrown when some process is interrupted. It's in
`utils.hpp` because I can't think where else to put it */
class interrupted_exc_t : public std::exception {
public:
    const char *what() const throw () {
        return "interrupted";
    }
};

/* Pad a value to the size of a cache line to avoid false sharing.
 * TODO: This is implemented as a struct with subtraction rather than a union
 * so that it gives an error when trying to pad a value bigger than
 * CACHE_LINE_SIZE. If that's needed, this may have to be done differently.
 */
template<typename value_t>
struct cache_line_padded_t {
    value_t value;
    char padding[CACHE_LINE_SIZE - sizeof(value_t)];
};

void *malloc_aligned(size_t size, size_t alignment = 64);

template <class T1, class T2>
T1 ceil_aligned(T1 value, T2 alignment) {
    return value + alignment - (((value + alignment - 1) % alignment) + 1);
}

template <class T1, class T2>
T1 ceil_divide(T1 dividend, T2 alignment) {
    return (dividend + alignment - 1) / alignment;
}

template <class T1, class T2>
T1 floor_aligned(T1 value, T2 alignment) {
    return value - (value % alignment);
}

template <class T1, class T2>
T1 ceil_modulo(T1 value, T2 alignment) {
    T1 x = (value + alignment - 1) % alignment;
    return value + alignment - ((x < 0 ? x + alignment : x) + 1);
}

inline bool divides(int64_t x, int64_t y) {
    return y % x == 0;
}

int gcd(int x, int y);

int64_t round_up_to_power_of_two(int64_t x);

timespec clock_monotonic();
timespec clock_realtime();

typedef uint64_t ticks_t;
ticks_t secs_to_ticks(time_t secs);
ticks_t get_ticks();
time_t get_secs();
double ticks_to_secs(ticks_t ticks);

#ifndef NDEBUG
#define trace_call(fn, args...) do {                                          \
        debugf("%s:%u: %s: entered\n", __FILE__, __LINE__, stringify(fn));  \
        fn(args);                                                           \
        debugf("%s:%u: %s: returned\n", __FILE__, __LINE__, stringify(fn)); \
    } while (0)
#define TRACEPOINT debugf("%s:%u reached\n", __FILE__, __LINE__)
#else
#define trace_call(fn, args...) fn(args)
// TRACEPOINT is not defined in release, so that TRACEPOINTS do not linger in the code unnecessarily
#endif

// HEY: Maybe debugf and log_call and TRACEPOINT should be placed in
// debugf.hpp (and debugf.cc).
/* Debugging printing API (prints current thread in addition to message) */
void debug_print_quoted_string(append_only_printf_buffer_t *buf, const uint8_t *s, size_t n);
void debugf_prefix_buf(printf_buffer_t<1000> *buf);
void debugf_dump_buf(printf_buffer_t<1000> *buf);

// Primitive debug_print declarations.
void debug_print(append_only_printf_buffer_t *buf, uint64_t x);
void debug_print(append_only_printf_buffer_t *buf, const std::string& s);

#ifndef NDEBUG
void debugf(const char *msg, ...) __attribute__((format (printf, 1, 2)));
template <class T>
void debugf_print(const char *msg, const T& obj) {
    printf_buffer_t<1000> buf;
    debugf_prefix_buf(&buf);
    buf.appendf("%s: ", msg);
    debug_print(&buf, obj);
    buf.appendf("\n");
    debugf_dump_buf(&buf);
}
#else
#define debugf(...) ((void)0)
#define debugf_print(...) ((void)0)
#endif

class debugf_in_dtor_t {
public:
    explicit debugf_in_dtor_t(const char *msg, ...);
    ~debugf_in_dtor_t();
private:
    std::string message;
};

class rng_t {
public:
// Returns a random number in [0, n).  Is not perfectly uniform; the
// bias tends to get worse when RAND_MAX is far from a multiple of n.
    int randint(int n);
    explicit rng_t(int seed = -1);
private:
    unsigned short xsubi[3];
    DISABLE_COPYING(rng_t);
};

// Reads from /dev/urandom.  Use this sparingly, please.
void get_dev_urandom(void *out, int64_t nbytes);

int randint(int n);
std::string rand_string(int len);

bool begins_with_minus(const char *string);
// strtoul() and strtoull() will for some reason not fail if the input begins
// with a minus sign. strtou64_strict() does.  Also we fix the constness of the
// end parameter.
int64_t strtoi64_strict(const char *string, const char **end, int base);
uint64_t strtou64_strict(const char *string, const char **end, int base);

// These functions return false and set the result to 0 if the conversion fails or
// does not consume the whole string.
MUST_USE bool strtoi64_strict(const std::string &str, int base, int64_t *out_result);
MUST_USE bool strtou64_strict(const std::string &str, int base, uint64_t *out_result);

std::string strprintf(const char *format, ...) __attribute__ ((format (printf, 1, 2)));
std::string vstrprintf(const char *format, va_list ap);

// formatted time:
// yyyy-mm-ddThh:mm:ss.nnnnnnnnn   (29 characters)
const size_t formatted_time_length = 29;    // not including null

void format_time(struct timespec time, append_only_printf_buffer_t *buf);
std::string format_time(struct timespec time);

struct timespec parse_time(const std::string &str) THROWS_ONLY(std::runtime_error);

/* Printing binary data to stdout in a nice format */

void print_hd(const void *buf, size_t offset, size_t length);

// Fast string compare

int sized_strcmp(const uint8_t *str1, int len1, const uint8_t *str2, int len2);

/* The home thread mixin is a mixin for objects that can only be used
on a single thread. Its thread ID is exposed as the `home_thread()`
method. Some subclasses of `home_thread_mixin_debug_only_t` can move themselves to
another thread, modifying the field real_home_thread. */

#define INVALID_THREAD (-1)

class home_thread_mixin_debug_only_t {
public:
#ifndef NDEBUG
    void assert_thread() const;
#else
    void assert_thread() const { }
#endif

protected:
    explicit home_thread_mixin_debug_only_t(int specified_home_thread);
    home_thread_mixin_debug_only_t();
    virtual ~home_thread_mixin_debug_only_t() { }

private:
    DISABLE_COPYING(home_thread_mixin_debug_only_t);

#ifndef NDEBUG
    int real_home_thread;
#endif
};

class home_thread_mixin_t {
public:
    int home_thread() const { return real_home_thread; }
#ifndef NDEBUG
    void assert_thread() const;
#else
    void assert_thread() const { }
#endif

protected:
    explicit home_thread_mixin_t(int specified_home_thread);
    home_thread_mixin_t();
    virtual ~home_thread_mixin_t() { }

    int real_home_thread;

private:
    // Things with home threads should not be copyable, since we don't
    // want to nonchalantly copy their real_home_thread variable.
    DISABLE_COPYING(home_thread_mixin_t);
};

/* `on_thread_t` switches to the given thread in its constructor, then switches
back in its destructor. For example:

    printf("Suppose we are on thread 1.\n");
    {
        on_thread_t thread_switcher(2);
        printf("Now we are on thread 2.\n");
    }
    printf("And now we are on thread 1 again.\n");

*/

class on_thread_t : public home_thread_mixin_t {
public:
    explicit on_thread_t(int thread);
    ~on_thread_t();
};

template <class InputIterator, class UnaryPredicate>
bool all_match_predicate(InputIterator begin, InputIterator end, UnaryPredicate f) {
    bool res = true;
    for (; begin != end; begin++) {
        res &= f(*begin);
    }
    return res;
}

template <class T, class UnaryPredicate>
bool all_in_container_match_predicate (const T &container, UnaryPredicate f) {
    return all_match_predicate(container.begin(), container.end(), f);
}

bool notf(bool x);

/* Translates to and from `0123456789ABCDEF`. */
bool hex_to_int(char c, int *out);
char int_to_hex(int i);

std::string read_file(const char *path);

struct path_t {
    std::vector<std::string> nodes;
    bool is_absolute;
};

path_t parse_as_path(const std::string &);
std::string render_as_path(const path_t &);

enum region_join_result_t { REGION_JOIN_OK, REGION_JOIN_BAD_JOIN, REGION_JOIN_BAD_REGION };

template <class T>
class assignment_sentry_t {
public:
    assignment_sentry_t(T *v, const T &value) :
        var(v), old_value(*var) {
        *var = value;
    }
    ~assignment_sentry_t() {
        *var = old_value;
    }
private:
    T *var;
    T old_value;
};

std::string sanitize_for_logger(const std::string &s);
static inline std::string time2str(const time_t &t) {
    char timebuf[26]; // I apologize for the magic constant.
    //           ^^ See man 3 ctime_r
    return ctime_r(&t, timebuf);
}

std::string errno_string(int errsv);

int get_num_db_threads();

template <class T>
T valgrind_undefined(T value) {
#ifdef VALGRIND
    VALGRIND_MAKE_MEM_UNDEFINED(&value, sizeof(value));
#endif
    return value;
}

// A static type for port number values.
class portno_t {
public:
    // Unimplemented constructors to snag attempts to pass things other than uint16_t.
    explicit portno_t(int portno);
    explicit portno_t(int16_t portno);

    explicit portno_t(const uint16_t portno) : portno_(portno) { }

    uint16_t as_uint16() const { return portno_; }

    uint16_t as_uint16_with_offset(const int port_offset) const {
        rassert(port_offset >= 0);
        if (portno_ == 0) {
            return 0;
        } else {
            int ret = portno_ + port_offset;
            guarantee(ret < 0x10000);
            return ret;
        }
    }

private:
    uint16_t portno_;
};

#define STR(x) #x
#define MSTR(x) STR(x) // Stringify a macro
#if defined __clang__
#define COMPILER "CLANG " __clang_version__
#elif defined __GNUC__
#define COMPILER "GCC " MSTR(__GNUC__) "." MSTR(__GNUC_MINOR__) "." MSTR(__GNUC_PATCHLEVEL__)
#else
#define COMPILER "UNKNOWN COMPILER"
#endif

#ifndef NDEBUG
#define RETHINKDB_VERSION_STR "rethinkdb " RETHINKDB_VERSION " (debug)" " (" COMPILER ")"
#else
#define RETHINKDB_VERSION_STR "rethinkdb " RETHINKDB_VERSION " (" COMPILER ")"
#endif

#define NULLPTR (static_cast<void *>(0))

#endif // UTILS_HPP_
<|endoftext|>


<commit_before>#include "ed.h"

utimer::timer_entry::timer_entry (const utime_t &time, u_long interval,
                                  lisp fn, int one_shot_p)
     : te_time (time + interval * utime_t (UNITS_PER_SEC / 1000)),
       te_interval (interval), te_fn (fn),
       te_flags (one_shot_p ? (TE_ONE_SHOT | TE_NEW) : TE_NEW)
{
}

utimer::utimer ()
     : t_hwnd (0), t_timer_on (0), t_in_timer (0)
{
}

utimer::~utimer ()
{
  while (!t_entries.empty_p ())
    delete t_entries.remove_head ();
  while (!t_defers.empty_p ())
    delete t_defers.remove_head ();
}

void
utimer::stop_timer ()
{
  if (t_timer_on)
    {
      KillTimer (t_hwnd, TID_USER);
      t_timer_on = 0;
    }
}

void
utimer::start_timer (const utime_t &t)
{
  stop_timer ();

  timer_entry *entry = t_entries.head ();
  if (entry)
    {
      utime_t d = (entry->te_time - t) / (timer_entry::UNITS_PER_SEC / 1000);
      if (d < 0)
        d = 0;
      else if (d >= LONG_MAX)
        d = LONG_MAX;
      SetTimer (t_hwnd, TID_USER, UINT (d), 0);
      t_timer_on = 1;
    }
}

void
utimer::insert (timer_entry *entry)
{
  for (timer_entry *p = t_entries.head (); p; p = p->next ())
    if (entry->te_time < p->te_time)
      {
        t_entries.insert_before (entry, p);
        return;
      }
  t_entries.add_tail (entry);
}

void
utimer::timer ()
{
  stop_timer ();

  if (t_in_timer)
    return;
  t_in_timer = 1;

  utime_t t;
  current_time (t);
  while (1)
    {
      timer_entry *entry = t_entries.head ();
      if (!entry)
        break;
      if (entry->te_time > t)
        break;

      lisp fn = entry->te_fn;

      t_entries.remove (entry);
      if (entry->te_flags & timer_entry::TE_ONE_SHOT)
        delete entry;
      else
        t_defers.add_tail (entry);

      try {Ffuncall (fn, Qnil);} catch (nonlocal_jump &) {}
    }

  t_in_timer = 0;

  current_time (t);
  while (!t_defers.empty_p ())
    {
      timer_entry *entry = t_defers.remove_head ();
      if (entry->te_flags & timer_entry::TE_NEW)
        entry->te_flags &= ~timer_entry::TE_NEW;
      else
        entry->te_time = t + (entry->te_interval
                              * utime_t (timer_entry::UNITS_PER_SEC / 1000));
      insert (entry);
    }

  start_timer (t);
}

void
utimer::add (u_long interval, lisp fn, int one_shot_p)
{
  utime_t t;
  current_time (t);
  timer_entry *entry = new timer_entry (t, interval, fn, one_shot_p);
  if (t_in_timer)
    t_defers.add_tail (entry);
  else
    {
      insert (entry);
      start_timer (t);
    }
}

int
utimer::remove (xlist <timer_entry> &list, lisp fn)
{
  for (timer_entry *p = list.head (); p; p = p->next ())
    if (p->te_fn == fn)
      {
        delete list.remove (p);
        return 1;
      }
  return 0;
}

int
utimer::remove (lisp fn)
{
  if (!remove (t_entries, fn) && !remove (t_defers, fn))
    return 0;
  if (!t_in_timer)
    {
      utime_t t;
      current_time (t);
      start_timer (t);
    }
  return 1;
}

void
utimer::gc_mark (void (*f)(lisp))
{
  timer_entry *p = t_entries.head ();
  for (; p; p = p->next ())
    (*f)(p->te_fn);
  for (p = t_defers.head (); p; p = p->next ())
    (*f)(p->te_fn);
}

lisp
Fstart_timer (lisp linterval, lisp lfn, lisp lone_shot_p)
{
  double interval (coerce_to_double_float (linterval) * 1000);
  if (interval < 0 || interval > LONG_MAX)
    FErange_error (linterval);
  active_app_frame().user_timer.add (u_long (interval), lfn, lone_shot_p && lone_shot_p != Qnil);
  return Qt;
}

lisp
Fstop_timer (lisp fn)
{
  return boole (active_app_frame().user_timer.remove (fn));
}
<commit_msg>xyzzy.src : fix start-timer.<commit_after>#include "ed.h"

utimer::timer_entry::timer_entry (const utime_t &time, u_long interval,
                                  lisp fn, int one_shot_p)
     : te_time (time + interval * utime_t (UNITS_PER_SEC / 1000)),
       te_interval (interval), te_fn (fn),
       te_flags (one_shot_p ? (TE_ONE_SHOT | TE_NEW) : TE_NEW)
{
}

utimer::utimer ()
     : t_hwnd (0), t_timer_on (0), t_in_timer (0)
{
}

utimer::~utimer ()
{
  while (!t_entries.empty_p ())
    delete t_entries.remove_head ();
  while (!t_defers.empty_p ())
    delete t_defers.remove_head ();
}

void
utimer::stop_timer ()
{
  if (t_timer_on)
    {
      KillTimer (t_hwnd, TID_USER);
      t_timer_on = 0;
    }
}

void
utimer::start_timer (const utime_t &t)
{
  stop_timer ();

  timer_entry *entry = t_entries.head ();
  if (entry)
    {
      utime_t d = (entry->te_time - t) / (timer_entry::UNITS_PER_SEC / 1000);
      if (d < 0)
        d = 0;
      else if (d >= LONG_MAX)
        d = LONG_MAX;
      SetTimer (t_hwnd, TID_USER, UINT (d), 0);
      t_timer_on = 1;
    }
}

void
utimer::insert (timer_entry *entry)
{
  for (timer_entry *p = t_entries.head (); p; p = p->next ())
    if (entry->te_time < p->te_time)
      {
        t_entries.insert_before (entry, p);
        return;
      }
  t_entries.add_tail (entry);
}

void
utimer::timer ()
{
  stop_timer ();

  if (t_in_timer)
    return;
  t_in_timer = 1;

  utime_t t;
  current_time (t);
  while (1)
    {
      timer_entry *entry = t_entries.head ();
      if (!entry)
        break;
      if (entry->te_time > t)
        break;

      lisp fn = entry->te_fn;

      t_entries.remove (entry);
      if (entry->te_flags & timer_entry::TE_ONE_SHOT)
        delete entry;
      else
        t_defers.add_tail (entry);

      try {Ffuncall (fn, Qnil);} catch (nonlocal_jump &) {}
    }

  t_in_timer = 0;

  current_time (t);
  while (!t_defers.empty_p ())
    {
      timer_entry *entry = t_defers.remove_head ();
      if (entry->te_flags & timer_entry::TE_NEW)
        entry->te_flags &= ~timer_entry::TE_NEW;
      entry->te_time = t + (entry->te_interval
                            * utime_t (timer_entry::UNITS_PER_SEC / 1000));
      insert (entry);
    }

  start_timer (t);
}

void
utimer::add (u_long interval, lisp fn, int one_shot_p)
{
  utime_t t;
  current_time (t);
  timer_entry *entry = new timer_entry (t, interval, fn, one_shot_p);
  if (t_in_timer)
    t_defers.add_tail (entry);
  else
    {
      insert (entry);
      start_timer (t);
    }
}

int
utimer::remove (xlist <timer_entry> &list, lisp fn)
{
  for (timer_entry *p = list.head (); p; p = p->next ())
    if (p->te_fn == fn)
      {
        delete list.remove (p);
        return 1;
      }
  return 0;
}

int
utimer::remove (lisp fn)
{
  if (!remove (t_entries, fn) && !remove (t_defers, fn))
    return 0;
  if (!t_in_timer)
    {
      utime_t t;
      current_time (t);
      start_timer (t);
    }
  return 1;
}

void
utimer::gc_mark (void (*f)(lisp))
{
  timer_entry *p = t_entries.head ();
  for (; p; p = p->next ())
    (*f)(p->te_fn);
  for (p = t_defers.head (); p; p = p->next ())
    (*f)(p->te_fn);
}

lisp
Fstart_timer (lisp linterval, lisp lfn, lisp lone_shot_p)
{
  double interval (coerce_to_double_float (linterval) * 1000);
  if (interval < 0 || interval > LONG_MAX)
    FErange_error (linterval);
  active_app_frame().user_timer.add (u_long (interval), lfn, lone_shot_p && lone_shot_p != Qnil);
  return Qt;
}

lisp
Fstop_timer (lisp fn)
{
  return boole (active_app_frame().user_timer.remove (fn));
}
<|endoftext|>