<commit_before>//
// file : hydra_logo.hpp
// in : file:///home/tim/projects/hydra/hydra/hydra_logo.hpp
//
// created by : Timothée Feuillet
// date: Fri Sep 02 2016 19:41:28 GMT+0200 (CEST)
//
//
// Copyright (c) 2016 Timothée Feuillet
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//

#ifndef __N_200324051639512063_182864571_HYDRA_LOGO_HPP__
#define __N_200324051639512063_182864571_HYDRA_LOGO_HPP__

#include <cstdint>  // uint*
#include <cstddef>  // size_t
#include <cstring>  // memset

namespace neam
{
  namespace hydra
  {
    /// \brief Generate the RGBA logo of hydra
    /// \param[out] pixels Where the image will be written. Must have a size of at least icon_sz * icon_sz * 4
    /// \param icon_sz The size of the image. Must be a power of 2 and greater than 16.
    /// \param glyph_count The number of glyph the image will have (must be lower than 5 and lower than 4 if icon_sz is 16)
    static uint8_t *generate_rgba_logo(uint8_t *pixels, size_t icon_sz = 256, size_t glyph_count = 4)
    {
      const uint8_t hydra_logo[] = {0x7D, 0x3D, 0xEB, 0x5F, 0x7B};

      if (icon_sz < 16) return pixels; // not possible
      if (glyph_count < 1 || glyph_count > sizeof(hydra_logo)) glyph_count = 4;
      if (icon_sz == 16 && glyph_count > 4) glyph_count = 4;

      const size_t sq_sz = icon_sz / (glyph_count * 4) ;
      const size_t y_pos = (glyph_count == 1 ? (sq_sz / 2) : (icon_sz / 2 - (sq_sz / 2 + 1)));
      const size_t x_pos = sq_sz / 2;
      memset(pixels, 0, icon_sz * icon_sz * 4);

      for (size_t i = 0; i < glyph_count; ++i)
      {
        for (size_t y = 0; y < sq_sz; ++y)
        {
          for (size_t x = 0; x < sq_sz; ++x)
          {
            size_t bidx = (y_pos + y) * icon_sz * 4 + (x_pos + x + 4 * sq_sz * i) * 4;
            pixels[bidx + 3 + 0 * sq_sz * 4 + 0 * icon_sz * sq_sz * 4] = hydra_logo[i] & 0x01 ? 255 : 0;
            pixels[bidx + 3 + 1 * sq_sz * 4 + 0 * icon_sz * sq_sz * 4] = hydra_logo[i] & 0x02 ? 255 : 0;
            pixels[bidx + 3 + 2 * sq_sz * 4 + 0 * icon_sz * sq_sz * 4] = hydra_logo[i] & 0x04 ? 255 : 0;
            pixels[bidx + 3 + 0 * sq_sz * 4 + 1 * icon_sz * sq_sz * 4] = hydra_logo[i] & 0x08 ? 255 : 0;
            pixels[bidx + 3 + 1 * sq_sz * 4 + 1 * icon_sz * sq_sz * 4] = hydra_logo[i] & 0x10 ? 255 : 0;
            pixels[bidx + 3 + 2 * sq_sz * 4 + 1 * icon_sz * sq_sz * 4] = hydra_logo[i] & 0x20 ? 255 : 0;
            pixels[bidx + 3 + 0 * sq_sz * 4 + 2 * icon_sz * sq_sz * 4] = hydra_logo[i] & 0x40 ? 255 : 0;
            pixels[bidx + 3 + 1 * sq_sz * 4 + 2 * icon_sz * sq_sz * 4] = hydra_logo[i] & 0x80 ? 255 : 0;
            pixels[bidx + 3 + 2 * sq_sz * 4 + 2 * icon_sz * sq_sz * 4] = 255;
          }
        }
      }
      return pixels;
    }
  } // namespace hydra
} // namespace neam

#endif // __N_200324051639512063_182864571_HYDRA_LOGO_HPP__

<commit_msg>Add support for coloring the logo<commit_after>//
// file : hydra_logo.hpp
// in : file:///home/tim/projects/hydra/hydra/hydra_logo.hpp
//
// created by : Timothée Feuillet
// date: Fri Sep 02 2016 19:41:28 GMT+0200 (CEST)
//
//
// Copyright (c) 2016 Timothée Feuillet
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//

#ifndef __N_200324051639512063_182864571_HYDRA_LOGO_HPP__
#define __N_200324051639512063_182864571_HYDRA_LOGO_HPP__

#include <cstdint>  // uint*
#include <cstddef>  // size_t
#include <cstring>  // memset

namespace neam
{
  namespace hydra
  {
    /// \brief Generate the RGBA logo of hydra
    /// \param[out] pixels Where the image will be written. Must have a size of at least icon_sz * icon_sz * 4
    /// \param icon_sz The size of the image. Must be a power of 2 and greater than 16.
    /// \param glyph_count The number of glyph the image will have (must be lower than 5 and lower than 4 if icon_sz is 16)
    static uint8_t* generate_rgba_logo(uint8_t* pixels, size_t icon_sz = 256, size_t glyph_count = 4, uint32_t color = 0)
    {
      const uint8_t hydra_logo[] = {0x7D, 0x3D, 0xEB, 0x5F, 0x7B};

      if (icon_sz < 16) return pixels; // not possible
      if (glyph_count < 1 || glyph_count > sizeof(hydra_logo)) glyph_count = 4;
      if (icon_sz == 16 && glyph_count > 4) glyph_count = 4;

      const size_t sq_sz = icon_sz / (glyph_count * 4) ;
      const size_t y_pos = (glyph_count == 1 ? (sq_sz / 2) : (icon_sz / 2 - (sq_sz / 2 + 1)));
      const size_t x_pos = sq_sz / 2;
      color = color & 0x00FFFFFF;
      if (!color)
      {
        memset(pixels, 0, icon_sz * icon_sz * 4);
      }
      else
      {
        uint32_t* upixels = (uint32_t*)pixels;
        for (uint32_t i = 0; i < icon_sz * icon_sz; ++i)
        {
          upixels[i] = color;
        }
      }

      for (size_t i = 0; i < glyph_count; ++i)
      {
        for (size_t y = 0; y < sq_sz; ++y)
        {
          for (size_t x = 0; x < sq_sz; ++x)
          {
            size_t bidx = (y_pos + y) * icon_sz * 4 + (x_pos + x + 4 * sq_sz * i) * 4;
            pixels[bidx + 3 + 0 * sq_sz * 4 + 0 * icon_sz * sq_sz * 4] = hydra_logo[i] & 0x01 ? 255 : 0;
            pixels[bidx + 3 + 1 * sq_sz * 4 + 0 * icon_sz * sq_sz * 4] = hydra_logo[i] & 0x02 ? 255 : 0;
            pixels[bidx + 3 + 2 * sq_sz * 4 + 0 * icon_sz * sq_sz * 4] = hydra_logo[i] & 0x04 ? 255 : 0;
            pixels[bidx + 3 + 0 * sq_sz * 4 + 1 * icon_sz * sq_sz * 4] = hydra_logo[i] & 0x08 ? 255 : 0;
            pixels[bidx + 3 + 1 * sq_sz * 4 + 1 * icon_sz * sq_sz * 4] = hydra_logo[i] & 0x10 ? 255 : 0;
            pixels[bidx + 3 + 2 * sq_sz * 4 + 1 * icon_sz * sq_sz * 4] = hydra_logo[i] & 0x20 ? 255 : 0;
            pixels[bidx + 3 + 0 * sq_sz * 4 + 2 * icon_sz * sq_sz * 4] = hydra_logo[i] & 0x40 ? 255 : 0;
            pixels[bidx + 3 + 1 * sq_sz * 4 + 2 * icon_sz * sq_sz * 4] = hydra_logo[i] & 0x80 ? 255 : 0;
            pixels[bidx + 3 + 2 * sq_sz * 4 + 2 * icon_sz * sq_sz * 4] = 255;
          }
        }
      }
      return pixels;
    }
  } // namespace hydra
} // namespace neam

#endif // __N_200324051639512063_182864571_HYDRA_LOGO_HPP__

<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 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.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "loadcoredialog.h"

#include "debuggerconstants.h"
#include "debuggercore.h"
#include "debuggerstartparameters.h"
#include "debuggerdialogs.h"

#include <coreplugin/icore.h>
#include <projectexplorer/abi.h>
#include <projectexplorer/kitchooser.h>
#include <projectexplorer/kitinformation.h>
#include <ssh/sshconnection.h>
#include <ssh/sshremoteprocessrunner.h>
#include <ssh/sftpdefs.h>
#include <ssh/sftpfilesystemmodel.h>
#include <utils/historycompleter.h>
#include <utils/pathchooser.h>
#include <utils/qtcassert.h>

#include <QCoreApplication>
#include <QDebug>
#include <QDir>
#include <QRegExp>
#include <QTemporaryFile>

#include <QButtonGroup>
#include <QComboBox>
#include <QDialogButtonBox>
#include <QFileDialog>
#include <QFormLayout>
#include <QGridLayout>
#include <QGroupBox>
#include <QHeaderView>
#include <QLineEdit>
#include <QMessageBox>
#include <QPushButton>
#include <QRadioButton>
#include <QScrollArea>
#include <QSortFilterProxyModel>
#include <QStandardItemModel>
#include <QTableView>
#include <QTextBrowser>
#include <QTreeView>
#include <QVBoxLayout>

using namespace Core;
using namespace ProjectExplorer;
using namespace QSsh;
using namespace Utils;

namespace Debugger {
namespace Internal {

///////////////////////////////////////////////////////////////////////
//
// SelectRemoteFileDialog
//
///////////////////////////////////////////////////////////////////////

class SelectRemoteFileDialog : public QDialog
{
    Q_OBJECT

public:
    explicit SelectRemoteFileDialog(QWidget *parent);

    void attachToDevice(Kit *k);
    QString localFile() const { return m_localFile; }
    QString remoteFile() const { return m_remoteFile; }

private slots:
    void handleSftpOperationFinished(QSsh::SftpJobId, const QString &error);
    void handleSftpOperationFailed(const QString &errorMessage);
    void handleConnectionError(const QString &errorMessage);
    void handleRemoteError(const QString &errorMessage);
    void selectFile();

private:
    QSortFilterProxyModel m_model;
    SftpFileSystemModel m_fileSystemModel;
    QTreeView *m_fileSystemView;
    QTextBrowser *m_textBrowser;
    QDialogButtonBox *m_buttonBox;
    QString m_localFile;
    QString m_remoteFile;
    SftpJobId m_sftpJobId;
};

SelectRemoteFileDialog::SelectRemoteFileDialog(QWidget *parent)
    : QDialog(parent)
{
    m_model.setSourceModel(&m_fileSystemModel);

    m_fileSystemView = new QTreeView(this);
    m_fileSystemView->setModel(&m_model);
    m_fileSystemView->setSortingEnabled(true);
    m_fileSystemView->setUniformRowHeights(true);
    m_fileSystemView->setSelectionMode(QAbstractItemView::SingleSelection);
    m_fileSystemView->setSelectionBehavior(QAbstractItemView::SelectRows);
    m_fileSystemView->header()->setDefaultSectionSize(100);
    m_fileSystemView->header()->setStretchLastSection(true);

    m_textBrowser = new QTextBrowser(this);
    m_textBrowser->setEnabled(false);

    m_buttonBox = new QDialogButtonBox(this);
    m_buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok);
    m_buttonBox->button(QDialogButtonBox::Ok)->setDefault(true);
    m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);

    QVBoxLayout *layout = new QVBoxLayout(this);
    layout->addWidget(m_fileSystemView);
    layout->addWidget(m_textBrowser);
    layout->addWidget(m_buttonBox);

    QObject::connect(m_buttonBox, SIGNAL(rejected()), SLOT(reject()));
    QObject::connect(m_buttonBox, SIGNAL(accepted()), SLOT(selectFile()));

    connect(&m_fileSystemModel, SIGNAL(sftpOperationFailed(QString)),
            SLOT(handleSftpOperationFailed(QString)));
    connect(&m_fileSystemModel, SIGNAL(connectionError(QString)),
            SLOT(handleConnectionError(QString)));
}

void SelectRemoteFileDialog::attachToDevice(Kit *k)
{
    m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true);
    QTC_ASSERT(k, return);
    IDevice::ConstPtr device = DeviceKitInformation::device(k);
    QTC_ASSERT(device, return);
    QSsh::SshConnectionParameters sshParams = device->sshParameters();
    m_fileSystemModel.setSshConnection(sshParams);
}

void SelectRemoteFileDialog::handleSftpOperationFailed(const QString &errorMessage)
{
    m_textBrowser->append(errorMessage);
    //reject();
}

void SelectRemoteFileDialog::handleConnectionError(const QString &errorMessage)
{
    m_textBrowser->append(errorMessage);
    //reject();
}

void SelectRemoteFileDialog::handleSftpOperationFinished(QSsh::SftpJobId, const QString &error)
{
    if (error.isEmpty()) {
        m_textBrowser->append(tr("Download of remote file succeeded."));
        accept();
    } else {
        m_textBrowser->append(error);
        //reject();
    }
}

void SelectRemoteFileDialog::handleRemoteError(const QString &errorMessage)
{
    m_textBrowser->append(errorMessage);
}

void SelectRemoteFileDialog::selectFile()
{
    QModelIndex idx = m_model.mapToSource(m_fileSystemView->currentIndex());
    if (!idx.isValid())
        return;

    m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
    m_fileSystemView->setEnabled(false);

    connect(&m_fileSystemModel, SIGNAL(sftpOperationFinished(QSsh::SftpJobId,QString)),
            SLOT(handleSftpOperationFinished(QSsh::SftpJobId,QString)));

    {
        QTemporaryFile localFile(QDir::tempPath() + QLatin1String("/remotecore-XXXXXX"));
        localFile.open();
        m_localFile = localFile.fileName();
    }

    idx = idx.sibling(idx.row(), 1);
    m_remoteFile = m_fileSystemModel.data(idx, SftpFileSystemModel::PathRole).toString();
    m_sftpJobId = m_fileSystemModel.downloadFile(idx, m_localFile);
}

///////////////////////////////////////////////////////////////////////
//
// AttachCoreDialog
//
///////////////////////////////////////////////////////////////////////

class AttachCoreDialogPrivate
{
public:
    KitChooser *kitChooser;

    QSettings *settings;

    PathChooser *localExecFileName;
    PathChooser *localCoreFileName;
    QLineEdit *remoteCoreFileName;
    QPushButton *selectRemoteCoreButton;

    PathChooser *overrideStartScriptFileName;

    QDialogButtonBox *buttonBox;
};

AttachCoreDialog::AttachCoreDialog(QWidget *parent)
    : QDialog(parent), d(new AttachCoreDialogPrivate)
{
    setWindowTitle(tr("Load Core File"));
    setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);

    d->settings = ICore::settings();

    d->kitChooser = new DebuggerKitChooser(DebuggerKitChooser::RemoteDebugging, this);
    d->kitChooser->populate();

    d->selectRemoteCoreButton = new QPushButton(tr("Browse..."), this);
    d->remoteCoreFileName = new QLineEdit(this);
    d->remoteCoreFileName->setEnabled(false);

    d->localCoreFileName = new PathChooser(this);
    d->localCoreFileName->setExpectedKind(PathChooser::File);
    d->localCoreFileName->setPromptDialogTitle(tr("Select Core File"));

    d->localExecFileName = new PathChooser(this);
    d->localExecFileName->setExpectedKind(PathChooser::File);
    d->localExecFileName->setPromptDialogTitle(tr("Select Executable"));

    d->overrideStartScriptFileName = new PathChooser(this);
    d->overrideStartScriptFileName->setExpectedKind(PathChooser::File);
    d->overrideStartScriptFileName->setPromptDialogTitle(tr("Select Startup Script"));

    d->buttonBox = new QDialogButtonBox(this);
    d->buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok);
    d->buttonBox->button(QDialogButtonBox::Ok)->setDefault(true);
    d->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);

    QHBoxLayout *coreLayout = new QHBoxLayout;
    coreLayout->addWidget(d->localCoreFileName);
    coreLayout->addWidget(d->remoteCoreFileName);
    coreLayout->addWidget(d->selectRemoteCoreButton);

    QFormLayout *formLayout = new QFormLayout;
    formLayout->setContentsMargins(0, 0, 0, 0);
    formLayout->setHorizontalSpacing(6);
    formLayout->setVerticalSpacing(6);
    formLayout->addRow(tr("Kit:"), d->kitChooser);
    formLayout->addRow(tr("&Executable:"), d->localExecFileName);
    formLayout->addRow(tr("Core file:"), coreLayout);
    formLayout->addRow(tr("Override &start script:"), d->overrideStartScriptFileName);

    QFrame *line = new QFrame(this);
    line->setFrameShape(QFrame::HLine);
    line->setFrameShadow(QFrame::Sunken);

    formLayout->addRow(d->buttonBox);

    QVBoxLayout *vboxLayout = new QVBoxLayout(this);
    vboxLayout->addLayout(formLayout);
    vboxLayout->addStretch();
    vboxLayout->addWidget(line);
    vboxLayout->addWidget(d->buttonBox);

    connect(d->selectRemoteCoreButton, SIGNAL(clicked()), SLOT(selectRemoteCoreFile()));
    connect(d->remoteCoreFileName, SIGNAL(textChanged(QString)), SLOT(changed()));
    connect(d->localCoreFileName, SIGNAL(changed(QString)), SLOT(changed()));
    connect(d->kitChooser, SIGNAL(activated(int)), SLOT(changed()));
    connect(d->buttonBox, SIGNAL(rejected()), SLOT(reject()));
    connect(d->buttonBox, SIGNAL(accepted()), SLOT(accept()));
    changed();
}

AttachCoreDialog::~AttachCoreDialog()
{
    delete d;
}

bool AttachCoreDialog::isLocal() const
{
    Kit *k = d->kitChooser->currentKit();
    QTC_ASSERT(k, return false);
    IDevice::ConstPtr device = DeviceKitInformation::device(k);
    QTC_ASSERT(device, return false);
    SshConnectionParameters sshParams = device->sshParameters();
    d->settings->setValue(QLatin1String("LastProfile"),
        d->kitChooser->currentKitId().toString());
    return sshParams.host.isEmpty();
}

void AttachCoreDialog::changed()
{
    bool isValid = d->kitChooser->currentIndex() >= 0 && d->localExecFileName->isValid();

    if (isLocal()) {
        d->localCoreFileName->setVisible(true);
        d->remoteCoreFileName->setVisible(false);
        d->selectRemoteCoreButton->setVisible(false);
        if (isValid)
            isValid = d->localCoreFileName->isValid();
    } else {
        d->remoteCoreFileName->setVisible(true);
        d->selectRemoteCoreButton->setVisible(true);
        d->localCoreFileName->setVisible(false);
        if (isValid)
            isValid = !remoteCoreFile().isEmpty();
    }
    d->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(isValid);
}

void AttachCoreDialog::selectRemoteCoreFile()
{
    changed();
    QTC_ASSERT(!isLocal(), return);
    SelectRemoteFileDialog dlg(this);
    dlg.setWindowTitle(tr("Select Remote Core File"));
    dlg.attachToDevice(d->kitChooser->currentKit());
    if (dlg.exec() == QDialog::Rejected)
        return;
    d->localCoreFileName->setPath(dlg.localFile());
    d->remoteCoreFileName->setText(dlg.remoteFile());
    changed();
}

QString AttachCoreDialog::localCoreFile() const
{
    return d->localCoreFileName->path();
}

QString AttachCoreDialog::localExecutableFile() const
{
    return d->localExecFileName->path();
}

void AttachCoreDialog::setLocalExecutableFile(const QString &fileName)
{
    d->localExecFileName->setPath(fileName);
}

void AttachCoreDialog::setLocalCoreFile(const QString &fileName)
{
    d->localCoreFileName->setPath(fileName);
}

void AttachCoreDialog::setRemoteCoreFile(const QString &fileName)
{
    d->remoteCoreFileName->setText(fileName);
}

QString AttachCoreDialog::remoteCoreFile() const
{
    return d->remoteCoreFileName->text();
}

void AttachCoreDialog::setKitId(const Core::Id &id)
{
    d->kitChooser->setCurrentKitId(id);
    changed();
}

Kit *AttachCoreDialog::kit() const
{
    return d->kitChooser->currentKit();
}

QString AttachCoreDialog::overrideStartScript() const
{
    return d->overrideStartScriptFileName->path();
}

void AttachCoreDialog::setOverrideStartScript(const QString &scriptName)
{
    d->overrideStartScriptFileName->setPath(scriptName);
}

} // namespace Internal
} // namespace Debugger

#include "loadcoredialog.moc"
<commit_msg>Attach to Core: Sort by file name<commit_after>/****************************************************************************
**
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 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.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "loadcoredialog.h"

#include "debuggerconstants.h"
#include "debuggercore.h"
#include "debuggerstartparameters.h"
#include "debuggerdialogs.h"

#include <coreplugin/icore.h>
#include <projectexplorer/abi.h>
#include <projectexplorer/kitchooser.h>
#include <projectexplorer/kitinformation.h>
#include <ssh/sshconnection.h>
#include <ssh/sshremoteprocessrunner.h>
#include <ssh/sftpdefs.h>
#include <ssh/sftpfilesystemmodel.h>
#include <utils/historycompleter.h>
#include <utils/pathchooser.h>
#include <utils/qtcassert.h>

#include <QCoreApplication>
#include <QDebug>
#include <QDir>
#include <QRegExp>
#include <QTemporaryFile>

#include <QButtonGroup>
#include <QComboBox>
#include <QDialogButtonBox>
#include <QFileDialog>
#include <QFormLayout>
#include <QGridLayout>
#include <QGroupBox>
#include <QHeaderView>
#include <QLineEdit>
#include <QMessageBox>
#include <QPushButton>
#include <QRadioButton>
#include <QScrollArea>
#include <QSortFilterProxyModel>
#include <QStandardItemModel>
#include <QTableView>
#include <QTextBrowser>
#include <QTreeView>
#include <QVBoxLayout>

using namespace Core;
using namespace ProjectExplorer;
using namespace QSsh;
using namespace Utils;

namespace Debugger {
namespace Internal {

///////////////////////////////////////////////////////////////////////
//
// SelectRemoteFileDialog
//
///////////////////////////////////////////////////////////////////////

class SelectRemoteFileDialog : public QDialog
{
    Q_OBJECT

public:
    explicit SelectRemoteFileDialog(QWidget *parent);

    void attachToDevice(Kit *k);
    QString localFile() const { return m_localFile; }
    QString remoteFile() const { return m_remoteFile; }

private slots:
    void handleSftpOperationFinished(QSsh::SftpJobId, const QString &error);
    void handleSftpOperationFailed(const QString &errorMessage);
    void handleConnectionError(const QString &errorMessage);
    void handleRemoteError(const QString &errorMessage);
    void selectFile();

private:
    QSortFilterProxyModel m_model;
    SftpFileSystemModel m_fileSystemModel;
    QTreeView *m_fileSystemView;
    QTextBrowser *m_textBrowser;
    QDialogButtonBox *m_buttonBox;
    QString m_localFile;
    QString m_remoteFile;
    SftpJobId m_sftpJobId;
};

SelectRemoteFileDialog::SelectRemoteFileDialog(QWidget *parent)
    : QDialog(parent)
{
    m_model.setSourceModel(&m_fileSystemModel);

    m_fileSystemView = new QTreeView(this);
    m_fileSystemView->setModel(&m_model);
    m_fileSystemView->setSortingEnabled(true);
    m_fileSystemView->sortByColumn(1, Qt::AscendingOrder);
    m_fileSystemView->setUniformRowHeights(true);
    m_fileSystemView->setSelectionMode(QAbstractItemView::SingleSelection);
    m_fileSystemView->setSelectionBehavior(QAbstractItemView::SelectRows);
    m_fileSystemView->header()->setDefaultSectionSize(100);
    m_fileSystemView->header()->setStretchLastSection(true);

    m_textBrowser = new QTextBrowser(this);
    m_textBrowser->setEnabled(false);

    m_buttonBox = new QDialogButtonBox(this);
    m_buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok);
    m_buttonBox->button(QDialogButtonBox::Ok)->setDefault(true);
    m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);

    QVBoxLayout *layout = new QVBoxLayout(this);
    layout->addWidget(m_fileSystemView);
    layout->addWidget(m_textBrowser);
    layout->addWidget(m_buttonBox);

    QObject::connect(m_buttonBox, SIGNAL(rejected()), SLOT(reject()));
    QObject::connect(m_buttonBox, SIGNAL(accepted()), SLOT(selectFile()));

    connect(&m_fileSystemModel, SIGNAL(sftpOperationFailed(QString)),
            SLOT(handleSftpOperationFailed(QString)));
    connect(&m_fileSystemModel, SIGNAL(connectionError(QString)),
            SLOT(handleConnectionError(QString)));
}

void SelectRemoteFileDialog::attachToDevice(Kit *k)
{
    m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true);
    QTC_ASSERT(k, return);
    IDevice::ConstPtr device = DeviceKitInformation::device(k);
    QTC_ASSERT(device, return);
    QSsh::SshConnectionParameters sshParams = device->sshParameters();
    m_fileSystemModel.setSshConnection(sshParams);
}

void SelectRemoteFileDialog::handleSftpOperationFailed(const QString &errorMessage)
{
    m_textBrowser->append(errorMessage);
    //reject();
}

void SelectRemoteFileDialog::handleConnectionError(const QString &errorMessage)
{
    m_textBrowser->append(errorMessage);
    //reject();
}

void SelectRemoteFileDialog::handleSftpOperationFinished(QSsh::SftpJobId, const QString &error)
{
    if (error.isEmpty()) {
        m_textBrowser->append(tr("Download of remote file succeeded."));
        accept();
    } else {
        m_textBrowser->append(error);
        //reject();
    }
}

void SelectRemoteFileDialog::handleRemoteError(const QString &errorMessage)
{
    m_textBrowser->append(errorMessage);
}

void SelectRemoteFileDialog::selectFile()
{
    QModelIndex idx = m_model.mapToSource(m_fileSystemView->currentIndex());
    if (!idx.isValid())
        return;

    m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
    m_fileSystemView->setEnabled(false);

    connect(&m_fileSystemModel, SIGNAL(sftpOperationFinished(QSsh::SftpJobId,QString)),
            SLOT(handleSftpOperationFinished(QSsh::SftpJobId,QString)));

    {
        QTemporaryFile localFile(QDir::tempPath() + QLatin1String("/remotecore-XXXXXX"));
        localFile.open();
        m_localFile = localFile.fileName();
    }

    idx = idx.sibling(idx.row(), 1);
    m_remoteFile = m_fileSystemModel.data(idx, SftpFileSystemModel::PathRole).toString();
    m_sftpJobId = m_fileSystemModel.downloadFile(idx, m_localFile);
}

///////////////////////////////////////////////////////////////////////
//
// AttachCoreDialog
//
///////////////////////////////////////////////////////////////////////

class AttachCoreDialogPrivate
{
public:
    KitChooser *kitChooser;

    QSettings *settings;

    PathChooser *localExecFileName;
    PathChooser *localCoreFileName;
    QLineEdit *remoteCoreFileName;
    QPushButton *selectRemoteCoreButton;

    PathChooser *overrideStartScriptFileName;

    QDialogButtonBox *buttonBox;
};

AttachCoreDialog::AttachCoreDialog(QWidget *parent)
    : QDialog(parent), d(new AttachCoreDialogPrivate)
{
    setWindowTitle(tr("Load Core File"));
    setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);

    d->settings = ICore::settings();

    d->kitChooser = new DebuggerKitChooser(DebuggerKitChooser::RemoteDebugging, this);
    d->kitChooser->populate();

    d->selectRemoteCoreButton = new QPushButton(tr("Browse..."), this);
    d->remoteCoreFileName = new QLineEdit(this);
    d->remoteCoreFileName->setEnabled(false);

    d->localCoreFileName = new PathChooser(this);
    d->localCoreFileName->setExpectedKind(PathChooser::File);
    d->localCoreFileName->setPromptDialogTitle(tr("Select Core File"));

    d->localExecFileName = new PathChooser(this);
    d->localExecFileName->setExpectedKind(PathChooser::File);
    d->localExecFileName->setPromptDialogTitle(tr("Select Executable"));

    d->overrideStartScriptFileName = new PathChooser(this);
    d->overrideStartScriptFileName->setExpectedKind(PathChooser::File);
    d->overrideStartScriptFileName->setPromptDialogTitle(tr("Select Startup Script"));

    d->buttonBox = new QDialogButtonBox(this);
    d->buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok);
    d->buttonBox->button(QDialogButtonBox::Ok)->setDefault(true);
    d->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);

    QHBoxLayout *coreLayout = new QHBoxLayout;
    coreLayout->addWidget(d->localCoreFileName);
    coreLayout->addWidget(d->remoteCoreFileName);
    coreLayout->addWidget(d->selectRemoteCoreButton);

    QFormLayout *formLayout = new QFormLayout;
    formLayout->setContentsMargins(0, 0, 0, 0);
    formLayout->setHorizontalSpacing(6);
    formLayout->setVerticalSpacing(6);
    formLayout->addRow(tr("Kit:"), d->kitChooser);
    formLayout->addRow(tr("&Executable:"), d->localExecFileName);
    formLayout->addRow(tr("Core file:"), coreLayout);
    formLayout->addRow(tr("Override &start script:"), d->overrideStartScriptFileName);

    QFrame *line = new QFrame(this);
    line->setFrameShape(QFrame::HLine);
    line->setFrameShadow(QFrame::Sunken);

    formLayout->addRow(d->buttonBox);

    QVBoxLayout *vboxLayout = new QVBoxLayout(this);
    vboxLayout->addLayout(formLayout);
    vboxLayout->addStretch();
    vboxLayout->addWidget(line);
    vboxLayout->addWidget(d->buttonBox);

    connect(d->selectRemoteCoreButton, SIGNAL(clicked()), SLOT(selectRemoteCoreFile()));
    connect(d->remoteCoreFileName, SIGNAL(textChanged(QString)), SLOT(changed()));
    connect(d->localCoreFileName, SIGNAL(changed(QString)), SLOT(changed()));
    connect(d->kitChooser, SIGNAL(activated(int)), SLOT(changed()));
    connect(d->buttonBox, SIGNAL(rejected()), SLOT(reject()));
    connect(d->buttonBox, SIGNAL(accepted()), SLOT(accept()));
    changed();
}

AttachCoreDialog::~AttachCoreDialog()
{
    delete d;
}

bool AttachCoreDialog::isLocal() const
{
    Kit *k = d->kitChooser->currentKit();
    QTC_ASSERT(k, return false);
    IDevice::ConstPtr device = DeviceKitInformation::device(k);
    QTC_ASSERT(device, return false);
    SshConnectionParameters sshParams = device->sshParameters();
    d->settings->setValue(QLatin1String("LastProfile"),
        d->kitChooser->currentKitId().toString());
    return sshParams.host.isEmpty();
}

void AttachCoreDialog::changed()
{
    bool isValid = d->kitChooser->currentIndex() >= 0 && d->localExecFileName->isValid();

    if (isLocal()) {
        d->localCoreFileName->setVisible(true);
        d->remoteCoreFileName->setVisible(false);
        d->selectRemoteCoreButton->setVisible(false);
        if (isValid)
            isValid = d->localCoreFileName->isValid();
    } else {
        d->remoteCoreFileName->setVisible(true);
        d->selectRemoteCoreButton->setVisible(true);
        d->localCoreFileName->setVisible(false);
        if (isValid)
            isValid = !remoteCoreFile().isEmpty();
    }
    d->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(isValid);
}

void AttachCoreDialog::selectRemoteCoreFile()
{
    changed();
    QTC_ASSERT(!isLocal(), return);
    SelectRemoteFileDialog dlg(this);
    dlg.setWindowTitle(tr("Select Remote Core File"));
    dlg.attachToDevice(d->kitChooser->currentKit());
    if (dlg.exec() == QDialog::Rejected)
        return;
    d->localCoreFileName->setPath(dlg.localFile());
    d->remoteCoreFileName->setText(dlg.remoteFile());
    changed();
}

QString AttachCoreDialog::localCoreFile() const
{
    return d->localCoreFileName->path();
}

QString AttachCoreDialog::localExecutableFile() const
{
    return d->localExecFileName->path();
}

void AttachCoreDialog::setLocalExecutableFile(const QString &fileName)
{
    d->localExecFileName->setPath(fileName);
}

void AttachCoreDialog::setLocalCoreFile(const QString &fileName)
{
    d->localCoreFileName->setPath(fileName);
}

void AttachCoreDialog::setRemoteCoreFile(const QString &fileName)
{
    d->remoteCoreFileName->setText(fileName);
}

QString AttachCoreDialog::remoteCoreFile() const
{
    return d->remoteCoreFileName->text();
}

void AttachCoreDialog::setKitId(const Core::Id &id)
{
    d->kitChooser->setCurrentKitId(id);
    changed();
}

Kit *AttachCoreDialog::kit() const
{
    return d->kitChooser->currentKit();
}

QString AttachCoreDialog::overrideStartScript() const
{
    return d->overrideStartScriptFileName->path();
}

void AttachCoreDialog::setOverrideStartScript(const QString &scriptName)
{
    d->overrideStartScriptFileName->setPath(scriptName);
}

} // namespace Internal
} // namespace Debugger

#include "loadcoredialog.moc"
<|endoftext|>


<commit_before>#include "types.h"
#include "mmu.h"
#include "kernel.hh"
#include "amd64.h"
#include "cpu.hh"
#include "traps.h"
#include "queue.h"
#include "spinlock.h"
#include "condvar.h"
#include "proc.hh"
#include "kmtrace.hh"
#include "bits.hh"
#include "kalloc.hh"

extern "C" void __fetch_end(void);

struct intdesc idt[256] __attribute__((aligned(16)));

// boot.S
extern u64 trapentry[];

u64
sysentry_c(u64 a0, u64 a1, u64 a2, u64 a3, u64 a4, u64 num)
{
  sti();

  if(myproc()->killed) {
    mtstart(trap, myproc());
    exit();
  }

  trapframe *tf = (trapframe*) (myproc()->kstack + KSTACKSIZE - sizeof(*tf));
  myproc()->tf = tf;
  u64 r = syscall(a0, a1, a2, a3, a4, num);

  if(myproc()->killed) {
    mtstart(trap, myproc());
    exit();
  }

  return r;
}

int
do_pagefault(struct trapframe *tf)
{
  uptr addr = rcr2();
  if (myproc()->uaccess_) {
    if (addr >= USERTOP)
      panic("Oops");

    sti();
    if(pagefault(myproc()->vmap, addr, tf->err) >= 0){
#if MTRACE
      mtstop(myproc());
      if (myproc()->mtrace_stacks.curr >= 0)
        mtresume(myproc());
#endif
      return 0;
    }
    cprintf("pagefault: failed in kernel\n");
    tf->rax = -1;
    tf->rip = (u64)__fetch_end;
    return 0;
  } else if (tf->err & FEC_U) {
      sti();
      if(pagefault(myproc()->vmap, addr, tf->err) >= 0){
#if MTRACE
        mtstop(myproc());
        if (myproc()->mtrace_stacks.curr >= 0)
          mtresume(myproc());
#endif
        return 0;
      }
      cprintf("pagefault: failed in user\n");
      cli();
  }
  return -1;
}

void
trap(struct trapframe *tf)
{
  if (tf->trapno == T_NMI) {
    // The only locks that we can acquire during NMI are ones
    // we acquire only during NMI.
    if (sampintr(tf))
      return;
    panic("NMI");
  }

  if(tf->trapno == T_SYSCALL){
    sti();
    if(myproc()->killed) {
      mtstart(trap, myproc());
      exit();
    }
    myproc()->tf = tf;
    tf->rax = syscall(tf->rdi, tf->rsi, tf->rdx, tf->rcx, tf->r8, tf->rax);
    if(myproc()->killed) {
      mtstart(trap, myproc());
      exit();
    }
    return;
  }

#if MTRACE
  if (myproc()->mtrace_stacks.curr >= 0)
    mtpause(myproc());
  mtstart(trap, myproc());
  // XXX mt_ascope ascope("trap:%d", tf->trapno);
#endif

  switch(tf->trapno){
  case T_IRQ0 + IRQ_TIMER:
    if (mycpu()->timer_printpc) {
      cprintf("cpu%d: proc %s rip %lx rsp %lx cs %x\n",
              mycpu()->id,
              myproc() ? myproc()->name : "(none)",
              tf->rip, tf->rsp, tf->cs);
      if (mycpu()->timer_printpc == 2 && tf->rbp > KBASE) {
        uptr pc[10];
        getcallerpcs((void *) tf->rbp, pc, NELEM(pc));
        for (int i = 0; i < 10 && pc[i]; i++)
          cprintf("cpu%d:   %lx\n", mycpu()->id, pc[i]);
      }
      mycpu()->timer_printpc = 0;
    }
    if (mycpu()->id == 0)
      cv_tick();
    lapiceoi();
    break;
  case T_IRQ0 + IRQ_IDE:
    ideintr();
    lapiceoi();
    piceoi();
    break;
  case T_IRQ0 + IRQ_IDE+1:
    // Bochs generates spurious IDE1 interrupts.
    break;
  case T_IRQ0 + IRQ_KBD:
    kbdintr();
    lapiceoi();
    piceoi();
    break;
  case T_IRQ0 + IRQ_COM2:
  case T_IRQ0 + IRQ_COM1:
    uartintr();
    lapiceoi();
    piceoi();
    break;
  case T_IRQ0 + 7:
  case T_IRQ0 + IRQ_SPURIOUS:
    cprintf("cpu%d: spurious interrupt at %x:%lx\n",
            mycpu()->id, tf->cs, tf->rip);
    lapiceoi();
    break;
  case T_IRQ0 + IRQ_ERROR:
    cprintf("cpu%d: lapic error?\n", mycpu()->id);
    lapiceoi();
    break;
  case T_TLBFLUSH: {
    lapiceoi();
    u64 nreq = tlbflush_req.load();
    lcr3(rcr3());
    mycpu()->tlbflush_done = nreq;
    break;
  }
  case T_SAMPCONF:
    lapiceoi();
    sampconf();
    break;
  default:
    if (tf->trapno == T_IRQ0+e1000irq) {
      e1000intr();
      lapiceoi();
      piceoi();
      break;
    }

    if (tf->trapno == T_PGFLT && do_pagefault(tf) == 0)
      return;

    if (myproc() == 0 || (tf->cs&3) == 0)
      kerneltrap(tf);

    // In user space, assume process misbehaved.
    cprintf("pid %d %s: trap %lu err %d on cpu %d "
            "rip 0x%lx rsp 0x%lx addr 0x%lx--kill proc\n",
            myproc()->pid, myproc()->name, tf->trapno, tf->err,
            mycpu()->id, tf->rip, tf->rsp, rcr2());
    myproc()->killed = 1;
  }

  // Force process exit if it has been killed and is in user space.
  // (If it is still executing in the kernel, let it keep running
  // until it gets to the regular system call return.)
  if(myproc() && myproc()->killed && (tf->cs&3) == 0x3)
    exit();

  // Force process to give up CPU on clock tick.
  // If interrupts were on while locks held, would need to check nlock.
  if(myproc() && myproc()->get_state() == RUNNING && tf->trapno == T_IRQ0+IRQ_TIMER)
    yield();

  // Check if the process has been killed since we yielded
  if(myproc() && myproc()->killed && (tf->cs&3) == 0x3)
    exit();

#if MTRACE
  mtstop(myproc());
  if (myproc()->mtrace_stacks.curr >= 0)
    mtresume(myproc());
#endif
}

void
inittrap(void)
{
  u64 entry;
  u8 bits;
  int i;

  bits = INT_P | SEG_INTR64;  // present, interrupt gate
  for(i=0; i<256; i++) {
    entry = trapentry[i];
    idt[i] = INTDESC(KCSEG, entry, bits);
  }
  entry = trapentry[T_SYSCALL];
  idt[T_SYSCALL] = INTDESC(KCSEG, entry, SEG_DPL(3) | SEG_INTR64 |INT_P);
}

void
initnmi(void)
{
  void *nmistackbase = ksalloc(slab_stack);
  mycpu()->ts.ist[1] = (u64) nmistackbase + KSTACKSIZE;

  if (mycpu()->id == 0)
    idt[T_NMI].ist = 1;
}

void
initseg(void)
{
  volatile struct desctr dtr;
  struct cpu *c;

  dtr.limit = sizeof(idt) - 1;
  dtr.base = (u64)idt;
  lidt((void *)&dtr.limit);

  // TLS might not be ready
  c = &cpus[myid()];
  // Load per-CPU GDT
  memmove(c->gdt, bootgdt, sizeof(bootgdt));
  dtr.limit = sizeof(c->gdt) - 1;
  dtr.base = (u64)c->gdt;
  lgdt((void *)&dtr.limit);

  // When executing a syscall instruction the CPU sets the SS selector
  // to (star >> 32) + 8 and the CS selector to (star >> 32).
  // When executing a sysret instruction the CPU sets the SS selector
  // to (star >> 48) + 8 and the CS selector to (star >> 48) + 16.
  u64 star = ((((u64)UCSEG|0x3) - 16)<<48)|((u64)KCSEG<<32);
  writemsr(MSR_STAR, star);
  writemsr(MSR_LSTAR, (u64)&sysentry);
  writemsr(MSR_SFMASK, FL_TF | FL_IF);
}

// Pushcli/popcli are like cli/sti except that they are matched:
// it takes two popcli to undo two pushcli.  Also, if interrupts
// are off, then pushcli, popcli leaves them off.
void
pushcli(void)
{
  u64 rflags;

  rflags = readrflags();
  cli();
  if(mycpu()->ncli++ == 0)
    mycpu()->intena = rflags & FL_IF;
}

void
popcli(void)
{
  if(readrflags()&FL_IF)
    panic("popcli - interruptible");
  if(--mycpu()->ncli < 0)
    panic("popcli");
  if(mycpu()->ncli == 0 && mycpu()->intena)
    sti();
}

// Record the current call stack in pcs[] by following the %rbp chain.
void
getcallerpcs(void *v, uptr pcs[], int n)
{
  uptr *rbp;
  int i;

  rbp = (uptr*)v;
  for(i = 0; i < n; i++){
    if(rbp == 0 || rbp < (uptr*)KBASE || rbp == (uptr*)(~0UL) ||
       (rbp >= (uptr*)KBASEEND && rbp < (uptr*)KCODE))
      break;
    pcs[i] = rbp[1];     // saved %rip
    rbp = (uptr*)rbp[0]; // saved %rbp
  }
  for(; i < n; i++)
    pcs[i] = 0;
}
<commit_msg>Better panic message<commit_after>#include "types.h"
#include "mmu.h"
#include "kernel.hh"
#include "amd64.h"
#include "cpu.hh"
#include "traps.h"
#include "queue.h"
#include "spinlock.h"
#include "condvar.h"
#include "proc.hh"
#include "kmtrace.hh"
#include "bits.hh"
#include "kalloc.hh"

extern "C" void __fetch_end(void);

struct intdesc idt[256] __attribute__((aligned(16)));

// boot.S
extern u64 trapentry[];

u64
sysentry_c(u64 a0, u64 a1, u64 a2, u64 a3, u64 a4, u64 num)
{
  sti();

  if(myproc()->killed) {
    mtstart(trap, myproc());
    exit();
  }

  trapframe *tf = (trapframe*) (myproc()->kstack + KSTACKSIZE - sizeof(*tf));
  myproc()->tf = tf;
  u64 r = syscall(a0, a1, a2, a3, a4, num);

  if(myproc()->killed) {
    mtstart(trap, myproc());
    exit();
  }

  return r;
}

int
do_pagefault(struct trapframe *tf)
{
  uptr addr = rcr2();
  if (myproc()->uaccess_) {
    if (addr >= USERTOP)
      panic("do_pagefault: %lx", addr);

    sti();
    if(pagefault(myproc()->vmap, addr, tf->err) >= 0){
#if MTRACE
      mtstop(myproc());
      if (myproc()->mtrace_stacks.curr >= 0)
        mtresume(myproc());
#endif
      return 0;
    }
    cprintf("pagefault: failed in kernel\n");
    tf->rax = -1;
    tf->rip = (u64)__fetch_end;
    return 0;
  } else if (tf->err & FEC_U) {
      sti();
      if(pagefault(myproc()->vmap, addr, tf->err) >= 0){
#if MTRACE
        mtstop(myproc());
        if (myproc()->mtrace_stacks.curr >= 0)
          mtresume(myproc());
#endif
        return 0;
      }
      cprintf("pagefault: failed in user\n");
      cli();
  }
  return -1;
}

void
trap(struct trapframe *tf)
{
  if (tf->trapno == T_NMI) {
    // The only locks that we can acquire during NMI are ones
    // we acquire only during NMI.
    if (sampintr(tf))
      return;
    panic("NMI");
  }

  if(tf->trapno == T_SYSCALL){
    sti();
    if(myproc()->killed) {
      mtstart(trap, myproc());
      exit();
    }
    myproc()->tf = tf;
    tf->rax = syscall(tf->rdi, tf->rsi, tf->rdx, tf->rcx, tf->r8, tf->rax);
    if(myproc()->killed) {
      mtstart(trap, myproc());
      exit();
    }
    return;
  }

#if MTRACE
  if (myproc()->mtrace_stacks.curr >= 0)
    mtpause(myproc());
  mtstart(trap, myproc());
  // XXX mt_ascope ascope("trap:%d", tf->trapno);
#endif

  switch(tf->trapno){
  case T_IRQ0 + IRQ_TIMER:
    if (mycpu()->timer_printpc) {
      cprintf("cpu%d: proc %s rip %lx rsp %lx cs %x\n",
              mycpu()->id,
              myproc() ? myproc()->name : "(none)",
              tf->rip, tf->rsp, tf->cs);
      if (mycpu()->timer_printpc == 2 && tf->rbp > KBASE) {
        uptr pc[10];
        getcallerpcs((void *) tf->rbp, pc, NELEM(pc));
        for (int i = 0; i < 10 && pc[i]; i++)
          cprintf("cpu%d:   %lx\n", mycpu()->id, pc[i]);
      }
      mycpu()->timer_printpc = 0;
    }
    if (mycpu()->id == 0)
      cv_tick();
    lapiceoi();
    break;
  case T_IRQ0 + IRQ_IDE:
    ideintr();
    lapiceoi();
    piceoi();
    break;
  case T_IRQ0 + IRQ_IDE+1:
    // Bochs generates spurious IDE1 interrupts.
    break;
  case T_IRQ0 + IRQ_KBD:
    kbdintr();
    lapiceoi();
    piceoi();
    break;
  case T_IRQ0 + IRQ_COM2:
  case T_IRQ0 + IRQ_COM1:
    uartintr();
    lapiceoi();
    piceoi();
    break;
  case T_IRQ0 + 7:
  case T_IRQ0 + IRQ_SPURIOUS:
    cprintf("cpu%d: spurious interrupt at %x:%lx\n",
            mycpu()->id, tf->cs, tf->rip);
    lapiceoi();
    break;
  case T_IRQ0 + IRQ_ERROR:
    cprintf("cpu%d: lapic error?\n", mycpu()->id);
    lapiceoi();
    break;
  case T_TLBFLUSH: {
    lapiceoi();
    u64 nreq = tlbflush_req.load();
    lcr3(rcr3());
    mycpu()->tlbflush_done = nreq;
    break;
  }
  case T_SAMPCONF:
    lapiceoi();
    sampconf();
    break;
  default:
    if (tf->trapno == T_IRQ0+e1000irq) {
      e1000intr();
      lapiceoi();
      piceoi();
      break;
    }

    if (tf->trapno == T_PGFLT && do_pagefault(tf) == 0)
      return;

    if (myproc() == 0 || (tf->cs&3) == 0)
      kerneltrap(tf);

    // In user space, assume process misbehaved.
    cprintf("pid %d %s: trap %lu err %d on cpu %d "
            "rip 0x%lx rsp 0x%lx addr 0x%lx--kill proc\n",
            myproc()->pid, myproc()->name, tf->trapno, tf->err,
            mycpu()->id, tf->rip, tf->rsp, rcr2());
    myproc()->killed = 1;
  }

  // Force process exit if it has been killed and is in user space.
  // (If it is still executing in the kernel, let it keep running
  // until it gets to the regular system call return.)
  if(myproc() && myproc()->killed && (tf->cs&3) == 0x3)
    exit();

  // Force process to give up CPU on clock tick.
  // If interrupts were on while locks held, would need to check nlock.
  if(myproc() && myproc()->get_state() == RUNNING && tf->trapno == T_IRQ0+IRQ_TIMER)
    yield();

  // Check if the process has been killed since we yielded
  if(myproc() && myproc()->killed && (tf->cs&3) == 0x3)
    exit();

#if MTRACE
  mtstop(myproc());
  if (myproc()->mtrace_stacks.curr >= 0)
    mtresume(myproc());
#endif
}

void
inittrap(void)
{
  u64 entry;
  u8 bits;
  int i;

  bits = INT_P | SEG_INTR64;  // present, interrupt gate
  for(i=0; i<256; i++) {
    entry = trapentry[i];
    idt[i] = INTDESC(KCSEG, entry, bits);
  }
  entry = trapentry[T_SYSCALL];
  idt[T_SYSCALL] = INTDESC(KCSEG, entry, SEG_DPL(3) | SEG_INTR64 |INT_P);
}

void
initnmi(void)
{
  void *nmistackbase = ksalloc(slab_stack);
  mycpu()->ts.ist[1] = (u64) nmistackbase + KSTACKSIZE;

  if (mycpu()->id == 0)
    idt[T_NMI].ist = 1;
}

void
initseg(void)
{
  volatile struct desctr dtr;
  struct cpu *c;

  dtr.limit = sizeof(idt) - 1;
  dtr.base = (u64)idt;
  lidt((void *)&dtr.limit);

  // TLS might not be ready
  c = &cpus[myid()];
  // Load per-CPU GDT
  memmove(c->gdt, bootgdt, sizeof(bootgdt));
  dtr.limit = sizeof(c->gdt) - 1;
  dtr.base = (u64)c->gdt;
  lgdt((void *)&dtr.limit);

  // When executing a syscall instruction the CPU sets the SS selector
  // to (star >> 32) + 8 and the CS selector to (star >> 32).
  // When executing a sysret instruction the CPU sets the SS selector
  // to (star >> 48) + 8 and the CS selector to (star >> 48) + 16.
  u64 star = ((((u64)UCSEG|0x3) - 16)<<48)|((u64)KCSEG<<32);
  writemsr(MSR_STAR, star);
  writemsr(MSR_LSTAR, (u64)&sysentry);
  writemsr(MSR_SFMASK, FL_TF | FL_IF);
}

// Pushcli/popcli are like cli/sti except that they are matched:
// it takes two popcli to undo two pushcli.  Also, if interrupts
// are off, then pushcli, popcli leaves them off.
void
pushcli(void)
{
  u64 rflags;

  rflags = readrflags();
  cli();
  if(mycpu()->ncli++ == 0)
    mycpu()->intena = rflags & FL_IF;
}

void
popcli(void)
{
  if(readrflags()&FL_IF)
    panic("popcli - interruptible");
  if(--mycpu()->ncli < 0)
    panic("popcli");
  if(mycpu()->ncli == 0 && mycpu()->intena)
    sti();
}

// Record the current call stack in pcs[] by following the %rbp chain.
void
getcallerpcs(void *v, uptr pcs[], int n)
{
  uptr *rbp;
  int i;

  rbp = (uptr*)v;
  for(i = 0; i < n; i++){
    if(rbp == 0 || rbp < (uptr*)KBASE || rbp == (uptr*)(~0UL) ||
       (rbp >= (uptr*)KBASEEND && rbp < (uptr*)KCODE))
      break;
    pcs[i] = rbp[1];     // saved %rip
    rbp = (uptr*)rbp[0]; // saved %rbp
  }
  for(; i < n; i++)
    pcs[i] = 0;
}
<|endoftext|>


<commit_before>// Intel 8250 serial port (UART).
// http://en.wikibooks.org/wiki/Serial_Programming/8250_UART_Programming

#include "types.h"
#include "kernel.hh"
#include "amd64.h"
#include "traps.h"
#include "apic.hh"
#include "irq.hh"

#define COM2    0x2f8
#define COM1    0x3f8

#define COM_IN_RECEIVE             0      // DLAB = 0, in
#define COM_OUT_TRANSMIT           0      // DLAB = 0, out
#define COM_INT_EN                 1      // DLAB = 0
# define COM_INT_RECEIVE            0x01
# define COM_INT_TRANSMIT           0x02
# define COM_INT_LINE               0x04
# define COM_INT_MODEM              0x08
#define COM_DIVISOR_LSB            0      // DLAB = 1
#define COM_DIVISOR_MSB            1      // DLAB = 1
#define COM_IN_IIR                 2
# define COM_IN_IIR_NOT_PENDING     0x01
# define COM_IN_IIR_ID_MASK         0x0E
#define COM_OUT_FIFO_CTL           2
# define COM_OUT_FIFO_ENABLE        0x01
# define COM_OUT_FIFO_RECV_RESET    0x02
# define COM_OUT_FIFO_XMIT_RESET    0x04
# define COM_OUT_FIFO_DMA           0x08
# define COM_OUT_FIFO_TRIGGER_MASK  0xC0
# define COM_OUT_FIFO_TRIGGER_1     (0<<6)
# define COM_OUT_FIFO_TRIGGER_4     (1<<6)
# define COM_OUT_FIFO_TRIGGER_8     (2<<6)
# define COM_OUT_FIFO_TRIGGER_14    (3<<6)
#define COM_LINE_CTL               3
# define COM_LINE_LEN_MASK          0x03
# define COM_LINE_LEN_5             0
# define COM_LINE_LEN_6             1
# define COM_LINE_LEN_7             2
# define COM_LINE_LEN_8             3
# define COM_LINE_STOP_BITS         0x04
# define COM_LINE_PARITY            0x08
# define COM_LINE_EVEN_PARITY       0x10
# define COM_LINE_STICK_PARITY      0x20
# define COM_LINE_BREAK_CTL         0x40
# define COM_LINE_DLAB              0x80
#define COM_MODEM_CTL              4
#define COM_LINE_STATUS            5
# define COM_LINE_DATA_READY        0x01
# define COM_LINE_OVERRUN_ERR       0x02
# define COM_LINE_PARITY_ERR        0x04
# define COM_LINE_FRAMING_ERR       0x08
# define COM_LINE_BREAK             0x10
# define COM_LINE_XMIT_HOLDING      0x20
# define COM_LINE_XMIT_EMPTY        0x40
# define COM_LINE_FIFO_ERR          0x80
#define COM_MODEM_STATUS           6
#define COM_SCRATCH                7

static int com;
static int irq_com;
static int uart;    // is there a uart?

void
uartputc(char c)
{
  int i;

  if (!uart)
    return;
  for (i = 0; i < 128 && !(inb(com+COM_LINE_STATUS) & COM_LINE_XMIT_HOLDING);
       i++)
    microdelay(10);
#ifdef UART_SEND_DELAY_USEC
  microdelay(UART_SEND_DELAY_USEC);
#endif
  outb(com+COM_OUT_TRANSMIT, c);
#ifdef UART_SEND_DELAY_USEC
  microdelay(UART_SEND_DELAY_USEC);
#endif
}

static int
uartgetc(void)
{
  if (!uart)
    return -1;
  if (!(inb(com+COM_LINE_STATUS) & COM_LINE_DATA_READY))
    return -1;
  return inb(com+COM_IN_RECEIVE);
}

void
uartintr(void)
{
  consoleintr(uartgetc);
}

void
inituart(void)
{
  static struct {
    int com;
    int irq;
  } conf[] = {
    // Try COM2 (aka ttyS1) first, because it usually does SOL for IPMI.
    { COM2, IRQ_COM2 },
    // Still try COM1 (aka ttyS0), because it is what QEMU emulates.
    { COM1, IRQ_COM1 },
  };

  int i;
#if defined(UART_BAUD)
  int baud = UART_BAUD;
#else
  int baud = 19200;
#endif
  for (i = 0; i < 2; i++) {
    com = conf[i].com;
    irq_com = conf[i].irq;

    // Turn off the FIFO
    outb(com+COM_OUT_FIFO_CTL, 0);
    // 19200 baud
    outb(com+COM_LINE_CTL, COM_LINE_DLAB);    // Unlock divisor
    outb(com+COM_DIVISOR_LSB, 115200/baud);
    outb(com+COM_DIVISOR_MSB, 0);
    // 8 bits, one stop bit, no parity
    outb(com+COM_LINE_CTL, COM_LINE_LEN_8); // Lock divisor, 8 data bits.
    outb(com+COM_INT_EN, COM_INT_RECEIVE); // Enable receive interrupts.
    // Data terminal ready
    outb(com+COM_MODEM_CTL, 0x0);

    // If status is 0xFF, no serial port.
    if(inb(com+COM_LINE_STATUS) != 0xFF)
      break;
  }
  if (i == 2)
    return;

  uart = 1;

  // Clean up the serial console (beginning of line, erase down)
  for (const char *p="\r\x1b[J"; *p; p++)
    uartputc(*p);

  // Announce that we're here.
  for (const char *p=DEBUG?"xv6 DEBUG\n":"xv6\n"; *p; p++)
    uartputc(*p);
}

void
inituartcons(void)
{
  // Acknowledge pre-existing interrupt conditions;
  // enable interrupts.
  inb(com+COM_IN_IIR);
  inb(com+COM_IN_RECEIVE);
  extpic->map_isa_irq(irq_com).enable();
}
<commit_msg>inituartcons: fix race condition that shows up with qemu<commit_after>// Intel 8250 serial port (UART).
// http://en.wikibooks.org/wiki/Serial_Programming/8250_UART_Programming

#include "types.h"
#include "kernel.hh"
#include "amd64.h"
#include "traps.h"
#include "apic.hh"
#include "irq.hh"

#define COM2    0x2f8
#define COM1    0x3f8

#define COM_IN_RECEIVE             0      // DLAB = 0, in
#define COM_OUT_TRANSMIT           0      // DLAB = 0, out
#define COM_INT_EN                 1      // DLAB = 0
# define COM_INT_RECEIVE            0x01
# define COM_INT_TRANSMIT           0x02
# define COM_INT_LINE               0x04
# define COM_INT_MODEM              0x08
#define COM_DIVISOR_LSB            0      // DLAB = 1
#define COM_DIVISOR_MSB            1      // DLAB = 1
#define COM_IN_IIR                 2
# define COM_IN_IIR_NOT_PENDING     0x01
# define COM_IN_IIR_ID_MASK         0x0E
#define COM_OUT_FIFO_CTL           2
# define COM_OUT_FIFO_ENABLE        0x01
# define COM_OUT_FIFO_RECV_RESET    0x02
# define COM_OUT_FIFO_XMIT_RESET    0x04
# define COM_OUT_FIFO_DMA           0x08
# define COM_OUT_FIFO_TRIGGER_MASK  0xC0
# define COM_OUT_FIFO_TRIGGER_1     (0<<6)
# define COM_OUT_FIFO_TRIGGER_4     (1<<6)
# define COM_OUT_FIFO_TRIGGER_8     (2<<6)
# define COM_OUT_FIFO_TRIGGER_14    (3<<6)
#define COM_LINE_CTL               3
# define COM_LINE_LEN_MASK          0x03
# define COM_LINE_LEN_5             0
# define COM_LINE_LEN_6             1
# define COM_LINE_LEN_7             2
# define COM_LINE_LEN_8             3
# define COM_LINE_STOP_BITS         0x04
# define COM_LINE_PARITY            0x08
# define COM_LINE_EVEN_PARITY       0x10
# define COM_LINE_STICK_PARITY      0x20
# define COM_LINE_BREAK_CTL         0x40
# define COM_LINE_DLAB              0x80
#define COM_MODEM_CTL              4
#define COM_LINE_STATUS            5
# define COM_LINE_DATA_READY        0x01
# define COM_LINE_OVERRUN_ERR       0x02
# define COM_LINE_PARITY_ERR        0x04
# define COM_LINE_FRAMING_ERR       0x08
# define COM_LINE_BREAK             0x10
# define COM_LINE_XMIT_HOLDING      0x20
# define COM_LINE_XMIT_EMPTY        0x40
# define COM_LINE_FIFO_ERR          0x80
#define COM_MODEM_STATUS           6
#define COM_SCRATCH                7

static int com;
static int irq_com;
static int uart;    // is there a uart?

void
uartputc(char c)
{
  int i;

  if (!uart)
    return;
  for (i = 0; i < 128 && !(inb(com+COM_LINE_STATUS) & COM_LINE_XMIT_HOLDING);
       i++)
    microdelay(10);
#ifdef UART_SEND_DELAY_USEC
  microdelay(UART_SEND_DELAY_USEC);
#endif
  outb(com+COM_OUT_TRANSMIT, c);
#ifdef UART_SEND_DELAY_USEC
  microdelay(UART_SEND_DELAY_USEC);
#endif
}

static int
uartgetc(void)
{
  if (!uart)
    return -1;
  if (!(inb(com+COM_LINE_STATUS) & COM_LINE_DATA_READY))
    return -1;
  return inb(com+COM_IN_RECEIVE);
}

void
uartintr(void)
{
  consoleintr(uartgetc);
}

void
inituart(void)
{
  static struct {
    int com;
    int irq;
  } conf[] = {
    // Try COM2 (aka ttyS1) first, because it usually does SOL for IPMI.
    { COM2, IRQ_COM2 },
    // Still try COM1 (aka ttyS0), because it is what QEMU emulates.
    { COM1, IRQ_COM1 },
  };

  int i;
#if defined(UART_BAUD)
  int baud = UART_BAUD;
#else
  int baud = 19200;
#endif
  for (i = 0; i < 2; i++) {
    com = conf[i].com;
    irq_com = conf[i].irq;

    // Turn off the FIFO
    outb(com+COM_OUT_FIFO_CTL, 0);
    // 19200 baud
    outb(com+COM_LINE_CTL, COM_LINE_DLAB);    // Unlock divisor
    outb(com+COM_DIVISOR_LSB, 115200/baud);
    outb(com+COM_DIVISOR_MSB, 0);
    // 8 bits, one stop bit, no parity
    outb(com+COM_LINE_CTL, COM_LINE_LEN_8); // Lock divisor, 8 data bits.
    outb(com+COM_INT_EN, COM_INT_RECEIVE); // Enable receive interrupts.
    // Data terminal ready
    outb(com+COM_MODEM_CTL, 0x0);

    // If status is 0xFF, no serial port.
    if(inb(com+COM_LINE_STATUS) != 0xFF)
      break;
  }
  if (i == 2)
    return;

  uart = 1;

  // Clean up the serial console (beginning of line, erase down)
  for (const char *p="\r\x1b[J"; *p; p++)
    uartputc(*p);

  // Announce that we're here.
  for (const char *p=DEBUG?"xv6 DEBUG\n":"xv6\n"; *p; p++)
    uartputc(*p);
}

void
inituartcons(void)
{
  // Acknowledge pre-existing interrupt conditions;
  // enable interrupts.
  extpic->map_isa_irq(irq_com).enable();
  inb(com+COM_IN_IIR);
  inb(com+COM_IN_RECEIVE);
}
<|endoftext|>


<commit_before>/***************************************************************************
 *   Copyright (C) 2007 by Kevin Krammer <kevin.krammer@gmx.at>            *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU Library General Public License as       *
 *   published by the Free Software Foundation; either version 2 of the    *
 *   License, or (at your option) any later version.                       *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this program; if not, write to the                 *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
 ***************************************************************************/

#include "xdgbasedirs_p.h"

#include "akonadi-prefix.h" // for prefix defines

#include <QtCore/QDebug>
#include <QtCore/QDir>
#include <QtCore/QFileInfo>

#include <cstdlib>

static QStringList alternateExecPaths( const QString& path )
{
  QStringList pathList;

  pathList << path;

#if defined(Q_OS_WIN) //krazy:exclude=cpp
  pathList << path + QLatin1String( ".exe" );
#elif defined(Q_OS_MAC) //krazy:exclude=cpp
  pathList << path + QLatin1String( ".app/Contents/MacOS/" ) + path.section( QLatin1Char( '/' ), -1 );
#endif

  return pathList;
}

namespace Akonadi {

class XdgBaseDirsPrivate
{
  public:
    XdgBaseDirsPrivate() {}

    ~XdgBaseDirsPrivate() {}
};

class XdgBaseDirsSingleton
{
public:
    QString homePath( const char *variable, const char *defaultSubDir );

    QStringList systemPathList( const char *variable, const char *defaultDirList );

  public:
    QString mConfigHome;
    QString mDataHome;

    QStringList mConfigDirs;
    QStringList mDataDirs;
    QStringList mExecutableDirs;
};

Q_GLOBAL_STATIC(XdgBaseDirsSingleton, instance)

}

using namespace Akonadi;

XdgBaseDirs::XdgBaseDirs() : d( new XdgBaseDirsPrivate() )
{
}

XdgBaseDirs::~XdgBaseDirs()
{
  delete d;
}

QString XdgBaseDirs::homePath( const char *resource )
{
  if ( qstrncmp( "data", resource, 4 ) == 0 ) {
    if ( instance()->mDataHome.isEmpty() ) {
      instance()->mDataHome = instance()->homePath( "XDG_DATA_HOME", ".local/share" );
    }
    return instance()->mDataHome;
  } else if ( qstrncmp( "config", resource, 6 ) == 0 ) {
    if ( instance()->mConfigHome.isEmpty() ) {
      instance()->mConfigHome = instance()->homePath( "XDG_CONFIG_HOME", ".config" );
    }
    return instance()->mConfigHome;
  }

  return QString();
}

QStringList XdgBaseDirs::systemPathList( const char *resource )
{
  if ( qstrncmp( "data", resource, 4 ) == 0 ) {
    if ( instance()->mDataDirs.isEmpty() ) {
      QStringList dataDirs = instance()->systemPathList( "XDG_DATA_DIRS", "/usr/local/share:/usr/share" );

      const QString prefixDataDir = QLatin1String( AKONADIDATA );
      if ( !dataDirs.contains( prefixDataDir ) ) {
        dataDirs << prefixDataDir;
      }

      instance()->mDataDirs = dataDirs;
    }
    return instance()->mDataDirs;
  } else if ( qstrncmp( "config", resource, 6 ) == 0 ) {
    if ( instance()->mConfigDirs.isEmpty() ) {
      QStringList configDirs = instance()->systemPathList( "XDG_CONFIG_DIRS", "/etc/xdg" );

      const QString prefixConfigDir = QLatin1String( AKONADICONFIG );
      if ( !configDirs.contains( prefixConfigDir ) ) {
        configDirs << prefixConfigDir;
      }

      instance()->mConfigDirs = configDirs;
    }
    return instance()->mConfigDirs;
  }

  return QStringList();
}

QString XdgBaseDirs::findResourceFile( const char *resource, const QString &relPath )
{
  QString fullPath = homePath( resource ) + QLatin1Char('/' ) + relPath;

  QFileInfo fileInfo( fullPath );
  if ( fileInfo.exists() && fileInfo.isFile() && fileInfo.isReadable() ) {
    return fullPath;
  }

  QStringList pathList = systemPathList( resource );

  QStringList::const_iterator it    = pathList.begin();
  QStringList::const_iterator endIt = pathList.end();
  for ( ; it != endIt; ++it ) {
    fileInfo = QFileInfo( *it + QLatin1Char('/' ) + relPath );
    if ( fileInfo.exists() && fileInfo.isFile() && fileInfo.isReadable() ) {
      return fileInfo.absoluteFilePath();
    }
  }

  return QString();
}

QString XdgBaseDirs::findExecutableFile( const QString &relPath, const QStringList &searchPath )
{
  if ( instance()->mExecutableDirs.isEmpty() ) {
    QStringList executableDirs = instance()->systemPathList( "PATH", "/usr/local/bin:/usr/bin" );

    const QString prefixExecutableDir = QLatin1String( AKONADIPREFIX "/bin" );
    if ( !executableDirs.contains( prefixExecutableDir ) ) {
      executableDirs << prefixExecutableDir;
    }

    executableDirs += searchPath;

    instance()->mExecutableDirs = executableDirs;
  }

  QStringList::const_iterator pathIt    = instance()->mExecutableDirs.begin();
  QStringList::const_iterator pathEndIt = instance()->mExecutableDirs.end();
  for ( ; pathIt != pathEndIt; ++pathIt ) {
    QStringList fullPathList = alternateExecPaths(*pathIt + QLatin1Char( '/' ) + relPath );

    QStringList::const_iterator it    = fullPathList.begin();
    QStringList::const_iterator endIt = fullPathList.end();
    for ( ; it != endIt; ++it ) {
      QFileInfo fileInfo(*it);

      if ( fileInfo.exists() && fileInfo.isFile() && fileInfo.isExecutable() ) {
        return *it;
      }
    }
  }

  return QString();
}

QString XdgBaseDirs::findResourceDir( const char *resource, const QString &relPath )
{
  QString fullPath = homePath( resource ) + QLatin1Char( '/' ) + relPath;

  QFileInfo fileInfo( fullPath );
  if ( fileInfo.exists() && fileInfo.isDir() && fileInfo.isReadable() ) {
    return fullPath;
  }

  QStringList pathList = systemPathList( resource );

  QStringList::const_iterator it    = pathList.begin();
  QStringList::const_iterator endIt = pathList.end();
  for ( ; it != endIt; ++it ) {
    fileInfo = QFileInfo( *it + QLatin1Char('/' ) + relPath );
    if ( fileInfo.exists() && fileInfo.isDir() && fileInfo.isReadable() ) {
      return fileInfo.absoluteFilePath();
    }
  }

  return QString();
}

QStringList XdgBaseDirs::findAllResourceDirs( const char *resource, const QString &relPath )
{
  QStringList resultList;

  QString fullPath = homePath( resource ) + QLatin1Char('/' ) + relPath;

  QFileInfo fileInfo( fullPath );
  if ( fileInfo.exists() && fileInfo.isDir() && fileInfo.isReadable() ) {
    resultList << fileInfo.absoluteFilePath();
  }

  QStringList pathList = systemPathList( resource );

  QStringList::const_iterator it    = pathList.begin();
  QStringList::const_iterator endIt = pathList.end();
  for ( ; it != endIt; ++it ) {
    fileInfo = QFileInfo( *it + QLatin1Char('/' ) + relPath );
    if ( fileInfo.exists() && fileInfo.isDir() && fileInfo.isReadable() ) {
      resultList << fileInfo.absoluteFilePath();
    }
  }

  return resultList;
}

QString XdgBaseDirs::saveDir( const char *resource, const QString &relPath )
{
  QString fullPath = homePath( resource ) + QLatin1Char('/' ) + relPath;

  QFileInfo fileInfo( fullPath );
  if ( fileInfo.exists() ) {
    if ( fileInfo.isDir() ) {
      return fullPath;
    } else {
      qWarning() << "XdgBaseDirs::saveDir: '" << fileInfo.absoluteFilePath()
                 << "' exists but is not a directory";
    }
  } else {
    if ( !QDir::home().mkpath( fileInfo.absoluteFilePath() ) ) {
      qWarning() << "XdgBaseDirs::saveDir: failed to create directory '"
                 << fileInfo.absoluteFilePath() << "'";
    } else {
      return fullPath;
    }
  }

  return QString();
}

QString XdgBaseDirs::akonadiServerConfigFile( FileAccessMode openMode )
{
  return akonadiConfigFile( QLatin1String( "akonadiserverrc" ), openMode );
}

QString XdgBaseDirs::akonadiConnectionConfigFile( FileAccessMode openMode )
{
  return akonadiConfigFile( QLatin1String( "akonadiconnectionrc" ), openMode );
}

QString XdgBaseDirs::akonadiConfigFile( const QString &file, FileAccessMode openMode )
{
  const QString akonadiDir = QLatin1String( "akonadi" );

  QString savePath = saveDir( "config", akonadiDir ) + QLatin1Char( '/' ) + file;

  if ( openMode == WriteOnly ) return savePath;

  QString path = findResourceFile( "config", akonadiDir + QLatin1Char( '/' ) + file );

  if ( path.isEmpty() ) {
    return savePath;
  } else if ( openMode == ReadOnly || path == savePath ) {
    return path;
  }

  // file found in system paths and mode is ReadWrite, thus
  // we copy to the home path location and return this path
  QFile systemFile( path );

  systemFile.copy( savePath );

  return savePath;
}

QString XdgBaseDirsSingleton::homePath( const char *variable, const char *defaultSubDir )
{
  const QByteArray env = qgetenv( variable );

  QString xdgPath;
  if ( env.isEmpty() ) {
    xdgPath = QDir::homePath() + QLatin1Char( '/' ) + QLatin1String( defaultSubDir );
#if defined(Q_OS_WIN) //krazy:exclude=cpp
  } else if ( QDir::isAbsolutePath( QString::fromLocal8Bit( env ) ) ) {
#else
  } else if ( env.startsWith( '/' ) ) {
#endif
    xdgPath = QString::fromLocal8Bit( env );
  } else {
    xdgPath = QDir::homePath() + QLatin1Char( '/' ) + QString::fromLocal8Bit( env );
  }

  return xdgPath;
}

QStringList XdgBaseDirsSingleton::systemPathList( const char *variable, const char *defaultDirList )
{
  const QByteArray env = qgetenv( variable );

  QString xdgDirList;
  if ( env.isEmpty() ) {
    xdgDirList = QLatin1String( defaultDirList );
  } else {
    xdgDirList = QString::fromLocal8Bit( env );
  }

#if defined(Q_OS_WIN) //krazy:exclude=cpp
  return xdgDirList.split( QLatin1Char( ';' ) );
#else
  return xdgDirList.split( QLatin1Char( ':' ) );
#endif
}
<commit_msg>Fix iterator<commit_after>/***************************************************************************
 *   Copyright (C) 2007 by Kevin Krammer <kevin.krammer@gmx.at>            *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU Library General Public License as       *
 *   published by the Free Software Foundation; either version 2 of the    *
 *   License, or (at your option) any later version.                       *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this program; if not, write to the                 *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
 ***************************************************************************/

#include "xdgbasedirs_p.h"

#include "akonadi-prefix.h" // for prefix defines

#include <QtCore/QDebug>
#include <QtCore/QDir>
#include <QtCore/QFileInfo>

#include <cstdlib>

static QStringList alternateExecPaths( const QString& path )
{
  QStringList pathList;

  pathList << path;

#if defined(Q_OS_WIN) //krazy:exclude=cpp
  pathList << path + QLatin1String( ".exe" );
#elif defined(Q_OS_MAC) //krazy:exclude=cpp
  pathList << path + QLatin1String( ".app/Contents/MacOS/" ) + path.section( QLatin1Char( '/' ), -1 );
#endif

  return pathList;
}

namespace Akonadi {

class XdgBaseDirsPrivate
{
  public:
    XdgBaseDirsPrivate() {}

    ~XdgBaseDirsPrivate() {}
};

class XdgBaseDirsSingleton
{
public:
    QString homePath( const char *variable, const char *defaultSubDir );

    QStringList systemPathList( const char *variable, const char *defaultDirList );

  public:
    QString mConfigHome;
    QString mDataHome;

    QStringList mConfigDirs;
    QStringList mDataDirs;
    QStringList mExecutableDirs;
};

Q_GLOBAL_STATIC(XdgBaseDirsSingleton, instance)

}

using namespace Akonadi;

XdgBaseDirs::XdgBaseDirs() : d( new XdgBaseDirsPrivate() )
{
}

XdgBaseDirs::~XdgBaseDirs()
{
  delete d;
}

QString XdgBaseDirs::homePath( const char *resource )
{
  if ( qstrncmp( "data", resource, 4 ) == 0 ) {
    if ( instance()->mDataHome.isEmpty() ) {
      instance()->mDataHome = instance()->homePath( "XDG_DATA_HOME", ".local/share" );
    }
    return instance()->mDataHome;
  } else if ( qstrncmp( "config", resource, 6 ) == 0 ) {
    if ( instance()->mConfigHome.isEmpty() ) {
      instance()->mConfigHome = instance()->homePath( "XDG_CONFIG_HOME", ".config" );
    }
    return instance()->mConfigHome;
  }

  return QString();
}

QStringList XdgBaseDirs::systemPathList( const char *resource )
{
  if ( qstrncmp( "data", resource, 4 ) == 0 ) {
    if ( instance()->mDataDirs.isEmpty() ) {
      QStringList dataDirs = instance()->systemPathList( "XDG_DATA_DIRS", "/usr/local/share:/usr/share" );

      const QString prefixDataDir = QLatin1String( AKONADIDATA );
      if ( !dataDirs.contains( prefixDataDir ) ) {
        dataDirs << prefixDataDir;
      }

      instance()->mDataDirs = dataDirs;
    }
    return instance()->mDataDirs;
  } else if ( qstrncmp( "config", resource, 6 ) == 0 ) {
    if ( instance()->mConfigDirs.isEmpty() ) {
      QStringList configDirs = instance()->systemPathList( "XDG_CONFIG_DIRS", "/etc/xdg" );

      const QString prefixConfigDir = QLatin1String( AKONADICONFIG );
      if ( !configDirs.contains( prefixConfigDir ) ) {
        configDirs << prefixConfigDir;
      }

      instance()->mConfigDirs = configDirs;
    }
    return instance()->mConfigDirs;
  }

  return QStringList();
}

QString XdgBaseDirs::findResourceFile( const char *resource, const QString &relPath )
{
  QString fullPath = homePath( resource ) + QLatin1Char('/' ) + relPath;

  QFileInfo fileInfo( fullPath );
  if ( fileInfo.exists() && fileInfo.isFile() && fileInfo.isReadable() ) {
    return fullPath;
  }

  QStringList pathList = systemPathList( resource );

  QStringList::const_iterator it    = pathList.constBegin();
  QStringList::const_iterator endIt = pathList.constEnd();
  for ( ; it != endIt; ++it ) {
    fileInfo = QFileInfo( *it + QLatin1Char('/' ) + relPath );
    if ( fileInfo.exists() && fileInfo.isFile() && fileInfo.isReadable() ) {
      return fileInfo.absoluteFilePath();
    }
  }

  return QString();
}

QString XdgBaseDirs::findExecutableFile( const QString &relPath, const QStringList &searchPath )
{
  if ( instance()->mExecutableDirs.isEmpty() ) {
    QStringList executableDirs = instance()->systemPathList( "PATH", "/usr/local/bin:/usr/bin" );

    const QString prefixExecutableDir = QLatin1String( AKONADIPREFIX "/bin" );
    if ( !executableDirs.contains( prefixExecutableDir ) ) {
      executableDirs << prefixExecutableDir;
    }

    executableDirs += searchPath;

    instance()->mExecutableDirs = executableDirs;
  }

  QStringList::const_iterator pathIt    = instance()->mExecutableDirs.constBegin();
  QStringList::const_iterator pathEndIt = instance()->mExecutableDirs.constEnd();
  for ( ; pathIt != pathEndIt; ++pathIt ) {
    QStringList fullPathList = alternateExecPaths(*pathIt + QLatin1Char( '/' ) + relPath );

    QStringList::const_iterator it    = fullPathList.constBegin();
    QStringList::const_iterator endIt = fullPathList.constEnd();
    for ( ; it != endIt; ++it ) {
      QFileInfo fileInfo(*it);

      if ( fileInfo.exists() && fileInfo.isFile() && fileInfo.isExecutable() ) {
        return *it;
      }
    }
  }

  return QString();
}

QString XdgBaseDirs::findResourceDir( const char *resource, const QString &relPath )
{
  QString fullPath = homePath( resource ) + QLatin1Char( '/' ) + relPath;

  QFileInfo fileInfo( fullPath );
  if ( fileInfo.exists() && fileInfo.isDir() && fileInfo.isReadable() ) {
    return fullPath;
  }

  QStringList pathList = systemPathList( resource );

  QStringList::const_iterator it    = pathList.constBegin();
  QStringList::const_iterator endIt = pathList.constEnd();
  for ( ; it != endIt; ++it ) {
    fileInfo = QFileInfo( *it + QLatin1Char('/' ) + relPath );
    if ( fileInfo.exists() && fileInfo.isDir() && fileInfo.isReadable() ) {
      return fileInfo.absoluteFilePath();
    }
  }

  return QString();
}

QStringList XdgBaseDirs::findAllResourceDirs( const char *resource, const QString &relPath )
{
  QStringList resultList;

  QString fullPath = homePath( resource ) + QLatin1Char('/' ) + relPath;

  QFileInfo fileInfo( fullPath );
  if ( fileInfo.exists() && fileInfo.isDir() && fileInfo.isReadable() ) {
    resultList << fileInfo.absoluteFilePath();
  }

  QStringList pathList = systemPathList( resource );

  QStringList::const_iterator it    = pathList.constBegin();
  QStringList::const_iterator endIt = pathList.constEnd();
  for ( ; it != endIt; ++it ) {
    fileInfo = QFileInfo( *it + QLatin1Char('/' ) + relPath );
    if ( fileInfo.exists() && fileInfo.isDir() && fileInfo.isReadable() ) {
      resultList << fileInfo.absoluteFilePath();
    }
  }

  return resultList;
}

QString XdgBaseDirs::saveDir( const char *resource, const QString &relPath )
{
  QString fullPath = homePath( resource ) + QLatin1Char('/' ) + relPath;

  QFileInfo fileInfo( fullPath );
  if ( fileInfo.exists() ) {
    if ( fileInfo.isDir() ) {
      return fullPath;
    } else {
      qWarning() << "XdgBaseDirs::saveDir: '" << fileInfo.absoluteFilePath()
                 << "' exists but is not a directory";
    }
  } else {
    if ( !QDir::home().mkpath( fileInfo.absoluteFilePath() ) ) {
      qWarning() << "XdgBaseDirs::saveDir: failed to create directory '"
                 << fileInfo.absoluteFilePath() << "'";
    } else {
      return fullPath;
    }
  }

  return QString();
}

QString XdgBaseDirs::akonadiServerConfigFile( FileAccessMode openMode )
{
  return akonadiConfigFile( QLatin1String( "akonadiserverrc" ), openMode );
}

QString XdgBaseDirs::akonadiConnectionConfigFile( FileAccessMode openMode )
{
  return akonadiConfigFile( QLatin1String( "akonadiconnectionrc" ), openMode );
}

QString XdgBaseDirs::akonadiConfigFile( const QString &file, FileAccessMode openMode )
{
  const QString akonadiDir = QLatin1String( "akonadi" );

  QString savePath = saveDir( "config", akonadiDir ) + QLatin1Char( '/' ) + file;

  if ( openMode == WriteOnly ) return savePath;

  QString path = findResourceFile( "config", akonadiDir + QLatin1Char( '/' ) + file );

  if ( path.isEmpty() ) {
    return savePath;
  } else if ( openMode == ReadOnly || path == savePath ) {
    return path;
  }

  // file found in system paths and mode is ReadWrite, thus
  // we copy to the home path location and return this path
  QFile systemFile( path );

  systemFile.copy( savePath );

  return savePath;
}

QString XdgBaseDirsSingleton::homePath( const char *variable, const char *defaultSubDir )
{
  const QByteArray env = qgetenv( variable );

  QString xdgPath;
  if ( env.isEmpty() ) {
    xdgPath = QDir::homePath() + QLatin1Char( '/' ) + QLatin1String( defaultSubDir );
#if defined(Q_OS_WIN) //krazy:exclude=cpp
  } else if ( QDir::isAbsolutePath( QString::fromLocal8Bit( env ) ) ) {
#else
  } else if ( env.startsWith( '/' ) ) {
#endif
    xdgPath = QString::fromLocal8Bit( env );
  } else {
    xdgPath = QDir::homePath() + QLatin1Char( '/' ) + QString::fromLocal8Bit( env );
  }

  return xdgPath;
}

QStringList XdgBaseDirsSingleton::systemPathList( const char *variable, const char *defaultDirList )
{
  const QByteArray env = qgetenv( variable );

  QString xdgDirList;
  if ( env.isEmpty() ) {
    xdgDirList = QLatin1String( defaultDirList );
  } else {
    xdgDirList = QString::fromLocal8Bit( env );
  }

#if defined(Q_OS_WIN) //krazy:exclude=cpp
  return xdgDirList.split( QLatin1Char( ';' ) );
#else
  return xdgDirList.split( QLatin1Char( ':' ) );
#endif
}
<|endoftext|>


<commit_before>// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License

#pragma once

#include <ArduinoJson/Memory/Alignment.hpp>
#include <ArduinoJson/Polyfills/assert.hpp>
#include <ArduinoJson/Polyfills/mpl/max.hpp>
#include <ArduinoJson/Variant/VariantSlot.hpp>

#include <string.h>  // memmove

#define JSON_STRING_SIZE(SIZE) (SIZE + 1)

namespace ARDUINOJSON_NAMESPACE {

// _begin                                   _end
// v                                           v
// +-------------+--------------+--------------+
// | strings...  |   (free)     |  ...variants |
// +-------------+--------------+--------------+
//               ^              ^
//             _left          _right

class MemoryPool {
 public:
  MemoryPool(char* buf, size_t capa)
      : _begin(buf),
        _left(buf),
        _right(buf ? buf + capa : 0),
        _end(buf ? buf + capa : 0),
        _overflowed(false) {
    ARDUINOJSON_ASSERT(isAligned(_begin));
    ARDUINOJSON_ASSERT(isAligned(_right));
    ARDUINOJSON_ASSERT(isAligned(_end));
  }

  void* buffer() {
    return _begin;
  }

  // Gets the capacity of the memoryPool in bytes
  size_t capacity() const {
    return size_t(_end - _begin);
  }

  size_t size() const {
    return size_t(_left - _begin + _end - _right);
  }

  bool overflowed() const {
    return _overflowed;
  }

  VariantSlot* allocVariant() {
    return allocRight<VariantSlot>();
  }

  template <typename TAdaptedString>
  const char* saveString(const TAdaptedString& str) {
    if (str.isNull())
      return 0;

#if ARDUINOJSON_ENABLE_STRING_DEDUPLICATION
    const char* existingCopy = findString(str.begin());
    if (existingCopy)
      return existingCopy;
#endif

    size_t n = str.size();

    char* newCopy = allocString(n + 1);
    if (newCopy) {
      str.copyTo(newCopy, n);
      newCopy[n] = 0;  // force null-terminator
    }
    return newCopy;
  }

  void getFreeZone(char** zoneStart, size_t* zoneSize) const {
    *zoneStart = _left;
    *zoneSize = size_t(_right - _left);
  }

  const char* saveStringFromFreeZone(size_t len) {
#if ARDUINOJSON_ENABLE_STRING_DEDUPLICATION
    const char* dup = findString(_left);
    if (dup)
      return dup;
#endif

    const char* str = _left;
    _left += len;
    checkInvariants();
    return str;
  }

  void markAsOverflowed() {
    _overflowed = true;
  }

  void clear() {
    _left = _begin;
    _right = _end;
    _overflowed = false;
  }

  bool canAlloc(size_t bytes) const {
    return _left + bytes <= _right;
  }

  bool owns(void* p) const {
    return _begin <= p && p < _end;
  }

  // Workaround for missing placement new
  void* operator new(size_t, void* p) {
    return p;
  }

  // Squash the free space between strings and variants
  //
  // _begin                    _end
  // v                            v
  // +-------------+--------------+
  // | strings...  |  ...variants |
  // +-------------+--------------+
  //               ^
  //          _left _right
  //
  // This funcion is called before a realloc.
  ptrdiff_t squash() {
    char* new_right = addPadding(_left);
    if (new_right >= _right)
      return 0;

    size_t right_size = static_cast<size_t>(_end - _right);
    memmove(new_right, _right, right_size);

    ptrdiff_t bytes_reclaimed = _right - new_right;
    _right = new_right;
    _end = new_right + right_size;
    return bytes_reclaimed;
  }

  // Move all pointers together
  // This funcion is called after a realloc.
  void movePointers(ptrdiff_t offset) {
    _begin += offset;
    _left += offset;
    _right += offset;
    _end += offset;
  }

 private:
  void checkInvariants() {
    ARDUINOJSON_ASSERT(_begin <= _left);
    ARDUINOJSON_ASSERT(_left <= _right);
    ARDUINOJSON_ASSERT(_right <= _end);
    ARDUINOJSON_ASSERT(isAligned(_right));
  }

#if ARDUINOJSON_ENABLE_STRING_DEDUPLICATION
  template <typename TIterator>
  const char* findString(TIterator str) {
    for (char* next = _begin; next < _left; ++next) {
      char* begin = next;

      // try to match
      for (TIterator it = str; *it == *next; ++it) {
        if (*next++ == 0)
          return begin;
      }

      // jump to next terminator
      while (*next) ++next;
    }
    return 0;
  }
#endif

  char* allocString(size_t n) {
    if (!canAlloc(n)) {
      _overflowed = true;
      return 0;
    }
    char* s = _left;
    _left += n;
    checkInvariants();
    return s;
  }

  template <typename T>
  T* allocRight() {
    return reinterpret_cast<T*>(allocRight(sizeof(T)));
  }

  void* allocRight(size_t bytes) {
    if (!canAlloc(bytes)) {
      _overflowed = true;
      return 0;
    }
    _right -= bytes;
    return _right;
  }

  char *_begin, *_left, *_right, *_end;
  bool _overflowed;
};

}  // namespace ARDUINOJSON_NAMESPACE
<commit_msg>clang-tidy: muted "use of memory after it is freed" in MemoryPool<commit_after>// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License

#pragma once

#include <ArduinoJson/Memory/Alignment.hpp>
#include <ArduinoJson/Polyfills/assert.hpp>
#include <ArduinoJson/Polyfills/mpl/max.hpp>
#include <ArduinoJson/Variant/VariantSlot.hpp>

#include <string.h>  // memmove

#define JSON_STRING_SIZE(SIZE) (SIZE + 1)

namespace ARDUINOJSON_NAMESPACE {

// _begin                                   _end
// v                                           v
// +-------------+--------------+--------------+
// | strings...  |   (free)     |  ...variants |
// +-------------+--------------+--------------+
//               ^              ^
//             _left          _right

class MemoryPool {
 public:
  MemoryPool(char* buf, size_t capa)
      : _begin(buf),
        _left(buf),
        _right(buf ? buf + capa : 0),
        _end(buf ? buf + capa : 0),
        _overflowed(false) {
    ARDUINOJSON_ASSERT(isAligned(_begin));
    ARDUINOJSON_ASSERT(isAligned(_right));
    ARDUINOJSON_ASSERT(isAligned(_end));
  }

  void* buffer() {
    return _begin;  // NOLINT(clang-analyzer-unix.Malloc)
                    // movePointers() alters this pointer
  }

  // Gets the capacity of the memoryPool in bytes
  size_t capacity() const {
    return size_t(_end - _begin);
  }

  size_t size() const {
    return size_t(_left - _begin + _end - _right);
  }

  bool overflowed() const {
    return _overflowed;
  }

  VariantSlot* allocVariant() {
    return allocRight<VariantSlot>();
  }

  template <typename TAdaptedString>
  const char* saveString(const TAdaptedString& str) {
    if (str.isNull())
      return 0;

#if ARDUINOJSON_ENABLE_STRING_DEDUPLICATION
    const char* existingCopy = findString(str.begin());
    if (existingCopy)
      return existingCopy;
#endif

    size_t n = str.size();

    char* newCopy = allocString(n + 1);
    if (newCopy) {
      str.copyTo(newCopy, n);
      newCopy[n] = 0;  // force null-terminator
    }
    return newCopy;
  }

  void getFreeZone(char** zoneStart, size_t* zoneSize) const {
    *zoneStart = _left;
    *zoneSize = size_t(_right - _left);
  }

  const char* saveStringFromFreeZone(size_t len) {
#if ARDUINOJSON_ENABLE_STRING_DEDUPLICATION
    const char* dup = findString(_left);
    if (dup)
      return dup;
#endif

    const char* str = _left;
    _left += len;
    checkInvariants();
    return str;
  }

  void markAsOverflowed() {
    _overflowed = true;
  }

  void clear() {
    _left = _begin;
    _right = _end;
    _overflowed = false;
  }

  bool canAlloc(size_t bytes) const {
    return _left + bytes <= _right;
  }

  bool owns(void* p) const {
    return _begin <= p && p < _end;
  }

  // Workaround for missing placement new
  void* operator new(size_t, void* p) {
    return p;
  }

  // Squash the free space between strings and variants
  //
  // _begin                    _end
  // v                            v
  // +-------------+--------------+
  // | strings...  |  ...variants |
  // +-------------+--------------+
  //               ^
  //          _left _right
  //
  // This funcion is called before a realloc.
  ptrdiff_t squash() {
    char* new_right = addPadding(_left);
    if (new_right >= _right)
      return 0;

    size_t right_size = static_cast<size_t>(_end - _right);
    memmove(new_right, _right, right_size);

    ptrdiff_t bytes_reclaimed = _right - new_right;
    _right = new_right;
    _end = new_right + right_size;
    return bytes_reclaimed;
  }

  // Move all pointers together
  // This funcion is called after a realloc.
  void movePointers(ptrdiff_t offset) {
    _begin += offset;
    _left += offset;
    _right += offset;
    _end += offset;
  }

 private:
  void checkInvariants() {
    ARDUINOJSON_ASSERT(_begin <= _left);
    ARDUINOJSON_ASSERT(_left <= _right);
    ARDUINOJSON_ASSERT(_right <= _end);
    ARDUINOJSON_ASSERT(isAligned(_right));
  }

#if ARDUINOJSON_ENABLE_STRING_DEDUPLICATION
  template <typename TIterator>
  const char* findString(TIterator str) {
    for (char* next = _begin; next < _left; ++next) {
      char* begin = next;

      // try to match
      for (TIterator it = str; *it == *next; ++it) {
        if (*next++ == 0)
          return begin;
      }

      // jump to next terminator
      while (*next) ++next;
    }
    return 0;
  }
#endif

  char* allocString(size_t n) {
    if (!canAlloc(n)) {
      _overflowed = true;
      return 0;
    }
    char* s = _left;
    _left += n;
    checkInvariants();
    return s;
  }

  template <typename T>
  T* allocRight() {
    return reinterpret_cast<T*>(allocRight(sizeof(T)));
  }

  void* allocRight(size_t bytes) {
    if (!canAlloc(bytes)) {
      _overflowed = true;
      return 0;
    }
    _right -= bytes;
    return _right;
  }

  char *_begin, *_left, *_right, *_end;
  bool _overflowed;
};

}  // namespace ARDUINOJSON_NAMESPACE
<|endoftext|>


<commit_before>// vim:ts=2:sw=2:expandtab:autoindent:filetype=cpp:
/*
The MIT License

Copyright (c) 2008, 2009 Aristid Breitkreuz, Ash Berlin, Ruediger Sonderfeld
                         Vinzenz Feenstra

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#include "sqlite.hpp"
#include <boost/lexical_cast.hpp>

namespace sqlite3_plugin {

using namespace flusspferd;

void raise_sqlite_error(::sqlite3* db)
{
    std::string s = "SQLite3 Error: ";
    s += sqlite3_errmsg(db);
    throw exception(s.c_str());
}

sqlite3::sqlite3(object const &obj, call_context &x)
: base_type(obj)
, db(0)
{
    if (x.arg.size() == 0) {
        throw exception ("SQLite3 requires more than 0 arguments");
    }
    string dsn = x.arg[0];

    // TODO: pull arguments from 2nd/options argument
    if (sqlite3_open(dsn.c_str(), &db) != SQLITE_OK) {
        if (db) {
            raise_sqlite_error(db);
        }
        else {
            throw std::bad_alloc(); // out of memory. better way to signal this?
        }
    }
}
///////////////////////////
sqlite3::~sqlite3()
{
    close();
}

///////////////////////////
void sqlite3::close()
{
    if (db) {
        sqlite3_close(db);
        db = NULL;
    }
}

///////////////////////////
void sqlite3::cursor(call_context &x) {
    local_root_scope scope;
    ensure_opened();

    if (x.arg.size() < 1) {
        throw exception ("cursor requires more than 0 arguments");
    }

    string sql = x.arg[0].to_string();
    size_t n_bytes = sql.length() * 2;
    sqlite3_stmt *sth = 0;
    char16_t *tail = 0; // uncompiled part of the sql (when multiple stmts)

    if (sqlite3_prepare16_v2(db, sql.data(), n_bytes, &sth, (const void**)&tail) != SQLITE_OK)
    {
        raise_sqlite_error(db);
    }

    object cursor = create_native_object<sqlite3_cursor>(object(), sth);

    // TODO: remove tail and set it seperately
    cursor.define_property("sql", sql);

    x.result = cursor;
}

///////////////////////////
void sqlite3::last_insert_id(call_context & x) {
    local_root_scope scope;
    ensure_opened();

    x.result = boost::lexical_cast< std::string >( sqlite3_last_insert_rowid( db ) );
}

///////////////////////////
void sqlite3::ensure_opened() {
    if (!db) {
        throw exception("SQLite3.cursor called on closed dbh");
    }
}
}

<commit_msg>Fixed exception message<commit_after>// vim:ts=2:sw=2:expandtab:autoindent:filetype=cpp:
/*
The MIT License

Copyright (c) 2008, 2009 Aristid Breitkreuz, Ash Berlin, Ruediger Sonderfeld
                         Vinzenz Feenstra

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#include "sqlite.hpp"
#include <boost/lexical_cast.hpp>

namespace sqlite3_plugin {

using namespace flusspferd;

void raise_sqlite_error(::sqlite3* db)
{
    std::string s = "SQLite3 Error: ";
    s += sqlite3_errmsg(db);
    throw exception(s.c_str());
}

sqlite3::sqlite3(object const &obj, call_context &x)
: base_type(obj)
, db(0)
{
    if (x.arg.size() == 0) {
        throw exception ("SQLite3 requires more than 0 arguments");
    }
    string dsn = x.arg[0];

    // TODO: pull arguments from 2nd/options argument
    if (sqlite3_open(dsn.c_str(), &db) != SQLITE_OK) {
        if (db) {
            raise_sqlite_error(db);
        }
        else {
            throw std::bad_alloc(); // out of memory. better way to signal this?
        }
    }
}
///////////////////////////
sqlite3::~sqlite3()
{
    close();
}

///////////////////////////
void sqlite3::close()
{
    if (db) {
        sqlite3_close(db);
        db = NULL;
    }
}

///////////////////////////
void sqlite3::cursor(call_context &x) {
    local_root_scope scope;
    ensure_opened();

    if (x.arg.size() < 1) {
        throw exception ("cursor requires more than 0 arguments");
    }

    string sql = x.arg[0].to_string();
    size_t n_bytes = sql.length() * 2;
    sqlite3_stmt *sth = 0;
    char16_t *tail = 0; // uncompiled part of the sql (when multiple stmts)

    if (sqlite3_prepare16_v2(db, sql.data(), n_bytes, &sth, (const void**)&tail) != SQLITE_OK)
    {
        raise_sqlite_error(db);
    }

    object cursor = create_native_object<sqlite3_cursor>(object(), sth);

    // TODO: remove tail and set it seperately
    cursor.define_property("sql", sql);

    x.result = cursor;
}

///////////////////////////
void sqlite3::last_insert_id(call_context & x) {
    local_root_scope scope;
    ensure_opened();

    x.result = boost::lexical_cast< std::string >( sqlite3_last_insert_rowid( db ) );
}

///////////////////////////
void sqlite3::ensure_opened() {
    if (!db) {
        throw exception("SQLite3 method called on a closed database handle");
    }
}
}

<|endoftext|>