<commit_before>/******************************************************************************

  This source file is part of the MoleQueue project.

  Copyright 2012 Kitware, Inc.

  This source code is released under the New BSD License, (the "License").

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

******************************************************************************/

#include "programconfiguredialog.h"
#include "ui_programconfiguredialog.h"

#include "program.h"
#include "queue.h"
#include "templatekeyworddialog.h"

#include <QtGui/QFileDialog>
#include <QtGui/QMessageBox>
#include <QtGui/QTextDocument>

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

namespace MoleQueue
{

ProgramConfigureDialog::ProgramConfigureDialog(Program *program,
                                               QWidget *parentObject) :
  QDialog(parentObject),
  ui(new Ui::ProgramConfigureDialog),
  m_program(program),
  m_helpDialog(NULL),
  m_isCustomized((m_program->launchSyntax() == Program::CUSTOM)),
  m_dirty(false)
{
  ui->setupUi(this);

  populateSyntaxCombo();

  connect(ui->combo_syntax, SIGNAL(currentIndexChanged(int)),
          this, SLOT(launchSyntaxChanged(int)));
  connect(ui->push_customize, SIGNAL(clicked()),
          this, SLOT(customizeLauncherClicked()));
  connect(ui->edit_executableName, SIGNAL(textChanged(QString)),
          this, SLOT(updateLaunchEditor()));
  connect(ui->edit_executablePath, SIGNAL(textChanged(QString)),
          this, SLOT(updateLaunchEditor()));
  connect(ui->edit_arguments, SIGNAL(textChanged(QString)),
          this, SLOT(updateLaunchEditor()));
  connect(ui->edit_inputFilename, SIGNAL(textChanged(QString)),
          this, SLOT(updateLaunchEditor()));
  connect(ui->edit_outputFilename, SIGNAL(textChanged(QString)),
          this, SLOT(updateLaunchEditor()));
  connect(ui->gb_executablePath, SIGNAL(toggled(bool)),
          this, SLOT(updateLaunchEditor()));
  connect(ui->text_launchTemplate, SIGNAL(textChanged()),
          this, SLOT(launchEditorTextChanged()));
  connect(ui->templateHelpButton, SIGNAL(clicked()),
          this, SLOT(showHelpDialog()));

  connect(ui->edit_name, SIGNAL(textChanged(QString)),
          this, SLOT(setDirty()));
  connect(ui->edit_executableName, SIGNAL(textChanged(QString)),
          this, SLOT(setDirty()));
  connect(ui->edit_executablePath, SIGNAL(textChanged(QString)),
          this, SLOT(setDirty()));
  connect(ui->edit_arguments, SIGNAL(textChanged(QString)),
          this, SLOT(setDirty()));
  connect(ui->edit_inputFilename, SIGNAL(textChanged(QString)),
          this, SLOT(setDirty()));
  connect(ui->edit_outputFilename, SIGNAL(textChanged(QString)),
          this, SLOT(setDirty()));
  connect(ui->gb_executablePath, SIGNAL(toggled(bool)),
          this, SLOT(setDirty()));
  connect(ui->combo_syntax, SIGNAL(currentIndexChanged(int)),
          this, SLOT(setDirty()));
  connect(ui->push_customize, SIGNAL(clicked()),
          this, SLOT(setDirty()));
  connect(ui->text_launchTemplate, SIGNAL(textChanged()),
          this, SLOT(setDirty()));

  connect(ui->buttonBox, SIGNAL(clicked(QAbstractButton*)),
          this, SLOT(buttonBoxButtonClicked(QAbstractButton*)));

  updateGuiFromProgram();

  launchSyntaxChanged(ui->combo_syntax->currentIndex());
}

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

void ProgramConfigureDialog::accept()
{
  if (m_dirty)
    updateProgramFromGui();

  QDialog::accept();
}

void ProgramConfigureDialog::lockName(bool locked)
{
  ui->edit_name->setDisabled(locked);
}

void ProgramConfigureDialog::populateSyntaxCombo()
{
  QStringList syntaxList;
  for (int cur = 0; cur < static_cast<int>(Program::SYNTAX_COUNT); ++cur) {
    switch (static_cast<Program::LaunchSyntax>(cur)) {
    case Program::CUSTOM:
      syntaxList << tr("Custom");
      break;
    case Program::PLAIN:
      syntaxList << tr("Plain");
      break;
    case Program::INPUT_ARG:
      syntaxList << tr("Input as argument");
      break;
    case Program::INPUT_ARG_NO_EXT:
      syntaxList << tr("Input as argument (no extension)");
      break;
    case Program::REDIRECT:
      syntaxList << tr("Redirect input and output");
      break;
    case Program::INPUT_ARG_OUTPUT_REDIRECT:
      syntaxList << tr("Input as output, redirect output");
      break;
    case Program::SYNTAX_COUNT:
    default:
      continue;
    }
  }

  ui->combo_syntax->blockSignals(true);
  ui->combo_syntax->clear();
  ui->combo_syntax->addItems(syntaxList);
  ui->combo_syntax->blockSignals(false);
}

void ProgramConfigureDialog::updateGuiFromProgram()
{
  ui->edit_name->setText(m_program->name());
  ui->edit_executableName->setText(m_program->executable());
  ui->gb_executablePath->setChecked(m_program->useExecutablePath());
  ui->edit_executablePath->setText(m_program->executablePath());
  ui->edit_arguments->setText(m_program->arguments());
  ui->edit_inputFilename->setText(m_program->inputFilename());
  ui->edit_outputFilename->setText(m_program->outputFilename());

  Program::LaunchSyntax syntax = m_program->launchSyntax();
  ui->combo_syntax->blockSignals(true);
  ui->combo_syntax->setCurrentIndex(static_cast<int>(syntax));
  ui->combo_syntax->blockSignals(false);
  m_customLaunchText = m_program->customLaunchTemplate();

  updateLaunchEditor();
  m_dirty = false;
}

void ProgramConfigureDialog::updateProgramFromGui()
{
  m_program->setName(ui->edit_name->text());
  m_program->setExecutable(ui->edit_executableName->text());
  m_program->setUseExecutablePath(ui->gb_executablePath->isChecked());
  m_program->setExecutablePath(ui->edit_executablePath->text());
  m_program->setArguments(ui->edit_arguments->text());
  m_program->setInputFilename(ui->edit_inputFilename->text());
  m_program->setOutputFilename(ui->edit_outputFilename->text());

  Program::LaunchSyntax syntax = static_cast<Program::LaunchSyntax>(
        ui->combo_syntax->currentIndex());
  m_program->setLaunchSyntax(syntax);
  m_program->setCustomLaunchTemplate(m_customLaunchText);
  m_dirty = false;
}

void ProgramConfigureDialog::updateLaunchEditor()
{
  Program::LaunchSyntax syntax = static_cast<Program::LaunchSyntax>(
        ui->combo_syntax->currentIndex());

  if (syntax == Program::CUSTOM) {
    ui->text_launchTemplate->document()->setPlainText(m_customLaunchText);
    return;
  }

  QString launchText = m_program->queue() ? m_program->queue()->launchTemplate()
                                          : QString("$$programExecution$$\n");

  const QString executableName = ui->edit_executableName->text();
  const QString executablePath = ui->edit_executablePath->text();
  const QString arguments      = ui->edit_arguments->text();
  const QString inputFilename  = ui->edit_inputFilename->text();
  const QString outputFilename = ui->edit_outputFilename->text();
  const bool useExecutablePath = ui->gb_executablePath->isChecked();

  QString programExecution = Program::generateFormattedExecutionString(
        executableName, arguments, inputFilename, outputFilename,
        executablePath, useExecutablePath, syntax);

  launchText.replace("$$programExecution$$", programExecution);

  ui->text_launchTemplate->document()->setPlainText(launchText);
}

void ProgramConfigureDialog::launchEditorTextChanged()
{
  QString launchText = ui->text_launchTemplate->document()->toPlainText();
  Program::LaunchSyntax syntax = static_cast<Program::LaunchSyntax>(
        ui->combo_syntax->currentIndex());

  if (syntax == Program::CUSTOM)
    m_customLaunchText = launchText;

  /// @todo Syntax highlighting?

}

void ProgramConfigureDialog::launchSyntaxChanged(int enumVal)
{
  Q_UNUSED(enumVal);

  Program::LaunchSyntax syntax = static_cast<Program::LaunchSyntax>(enumVal);

  bool syntaxIsCustom = (syntax == Program::CUSTOM);

  ui->push_customize->setDisabled(syntaxIsCustom);
  ui->text_launchTemplate->setReadOnly(!syntaxIsCustom);

  updateLaunchEditor();
}

void ProgramConfigureDialog::customizeLauncherClicked()
{
  m_customLaunchText = ui->text_launchTemplate->document()->toPlainText();
  ui->combo_syntax->setCurrentIndex(static_cast<int>(Program::CUSTOM));
}

void ProgramConfigureDialog::closeEvent(QCloseEvent *e)
{
  if (m_dirty) {
    // apply or discard changes?
    QMessageBox::StandardButton reply =
        QMessageBox::warning(this, tr("Unsaved changes"),
                             tr("The changes to the program have not been "
                                "saved. Would you like to save or discard "
                                "them?"),
                             QMessageBox::Save | QMessageBox::Discard |
                             QMessageBox::Cancel,
                             QMessageBox::Save);

    switch (reply) {
    case QMessageBox::Cancel:
      e->ignore();
      return;
    case QMessageBox::Save:
      updateProgramFromGui();
    case QMessageBox::NoButton:
    case QMessageBox::Discard:
    default:
      e->accept();
      break;
    }
  }

  QDialog::closeEvent(e);
}

void ProgramConfigureDialog::keyPressEvent(QKeyEvent *e)
{
  // By default, the escape key bypasses the close event, but we still want to
  // check if the settings widget is dirty.
  if (e->key() == Qt::Key_Escape) {
    e->accept();
    close();
    return;
  }

  QDialog::keyPressEvent(e);
}

void ProgramConfigureDialog::showHelpDialog()
{
  if (!m_helpDialog)
    m_helpDialog = new TemplateKeywordDialog(this);
  m_helpDialog->show();
}

void ProgramConfigureDialog::buttonBoxButtonClicked(QAbstractButton *button)
{
  // "Ok" and "Cancel" are directly connected to accept() and reject(), so only
  // check for "apply" here:
  if (button == ui->buttonBox->button(QDialogButtonBox::Apply))
    updateProgramFromGui();
}

} // end namespace MoleQueue
<commit_msg>Use a more accurate preview of the local queue launch method.<commit_after>/******************************************************************************

  This source file is part of the MoleQueue project.

  Copyright 2012 Kitware, Inc.

  This source code is released under the New BSD License, (the "License").

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

******************************************************************************/

#include "programconfiguredialog.h"
#include "ui_programconfiguredialog.h"

#include "program.h"
#include "queue.h"
#include "queues/local.h"
#include "templatekeyworddialog.h"

#include <QtGui/QFileDialog>
#include <QtGui/QMessageBox>
#include <QtGui/QTextDocument>

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

namespace MoleQueue
{

ProgramConfigureDialog::ProgramConfigureDialog(Program *program,
                                               QWidget *parentObject) :
  QDialog(parentObject),
  ui(new Ui::ProgramConfigureDialog),
  m_program(program),
  m_helpDialog(NULL),
  m_isCustomized((m_program->launchSyntax() == Program::CUSTOM)),
  m_dirty(false)
{
  ui->setupUi(this);

  populateSyntaxCombo();

  connect(ui->combo_syntax, SIGNAL(currentIndexChanged(int)),
          this, SLOT(launchSyntaxChanged(int)));
  connect(ui->push_customize, SIGNAL(clicked()),
          this, SLOT(customizeLauncherClicked()));
  connect(ui->edit_executableName, SIGNAL(textChanged(QString)),
          this, SLOT(updateLaunchEditor()));
  connect(ui->edit_executablePath, SIGNAL(textChanged(QString)),
          this, SLOT(updateLaunchEditor()));
  connect(ui->edit_arguments, SIGNAL(textChanged(QString)),
          this, SLOT(updateLaunchEditor()));
  connect(ui->edit_inputFilename, SIGNAL(textChanged(QString)),
          this, SLOT(updateLaunchEditor()));
  connect(ui->edit_outputFilename, SIGNAL(textChanged(QString)),
          this, SLOT(updateLaunchEditor()));
  connect(ui->gb_executablePath, SIGNAL(toggled(bool)),
          this, SLOT(updateLaunchEditor()));
  connect(ui->text_launchTemplate, SIGNAL(textChanged()),
          this, SLOT(launchEditorTextChanged()));
  connect(ui->templateHelpButton, SIGNAL(clicked()),
          this, SLOT(showHelpDialog()));

  connect(ui->edit_name, SIGNAL(textChanged(QString)),
          this, SLOT(setDirty()));
  connect(ui->edit_executableName, SIGNAL(textChanged(QString)),
          this, SLOT(setDirty()));
  connect(ui->edit_executablePath, SIGNAL(textChanged(QString)),
          this, SLOT(setDirty()));
  connect(ui->edit_arguments, SIGNAL(textChanged(QString)),
          this, SLOT(setDirty()));
  connect(ui->edit_inputFilename, SIGNAL(textChanged(QString)),
          this, SLOT(setDirty()));
  connect(ui->edit_outputFilename, SIGNAL(textChanged(QString)),
          this, SLOT(setDirty()));
  connect(ui->gb_executablePath, SIGNAL(toggled(bool)),
          this, SLOT(setDirty()));
  connect(ui->combo_syntax, SIGNAL(currentIndexChanged(int)),
          this, SLOT(setDirty()));
  connect(ui->push_customize, SIGNAL(clicked()),
          this, SLOT(setDirty()));
  connect(ui->text_launchTemplate, SIGNAL(textChanged()),
          this, SLOT(setDirty()));

  connect(ui->buttonBox, SIGNAL(clicked(QAbstractButton*)),
          this, SLOT(buttonBoxButtonClicked(QAbstractButton*)));

  updateGuiFromProgram();

  launchSyntaxChanged(ui->combo_syntax->currentIndex());
}

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

void ProgramConfigureDialog::accept()
{
  if (m_dirty)
    updateProgramFromGui();

  QDialog::accept();
}

void ProgramConfigureDialog::lockName(bool locked)
{
  ui->edit_name->setDisabled(locked);
}

void ProgramConfigureDialog::populateSyntaxCombo()
{
  QStringList syntaxList;
  for (int cur = 0; cur < static_cast<int>(Program::SYNTAX_COUNT); ++cur) {
    switch (static_cast<Program::LaunchSyntax>(cur)) {
    case Program::CUSTOM:
      syntaxList << tr("Custom");
      break;
    case Program::PLAIN:
      syntaxList << tr("Plain");
      break;
    case Program::INPUT_ARG:
      syntaxList << tr("Input as argument");
      break;
    case Program::INPUT_ARG_NO_EXT:
      syntaxList << tr("Input as argument (no extension)");
      break;
    case Program::REDIRECT:
      syntaxList << tr("Redirect input and output");
      break;
    case Program::INPUT_ARG_OUTPUT_REDIRECT:
      syntaxList << tr("Input as output, redirect output");
      break;
    case Program::SYNTAX_COUNT:
    default:
      continue;
    }
  }

  ui->combo_syntax->blockSignals(true);
  ui->combo_syntax->clear();
  ui->combo_syntax->addItems(syntaxList);
  ui->combo_syntax->blockSignals(false);
}

void ProgramConfigureDialog::updateGuiFromProgram()
{
  ui->edit_name->setText(m_program->name());
  ui->edit_executableName->setText(m_program->executable());
  ui->gb_executablePath->setChecked(m_program->useExecutablePath());
  ui->edit_executablePath->setText(m_program->executablePath());
  ui->edit_arguments->setText(m_program->arguments());
  ui->edit_inputFilename->setText(m_program->inputFilename());
  ui->edit_outputFilename->setText(m_program->outputFilename());

  Program::LaunchSyntax syntax = m_program->launchSyntax();
  ui->combo_syntax->blockSignals(true);
  ui->combo_syntax->setCurrentIndex(static_cast<int>(syntax));
  ui->combo_syntax->blockSignals(false);
  m_customLaunchText = m_program->customLaunchTemplate();

  updateLaunchEditor();
  m_dirty = false;
}

void ProgramConfigureDialog::updateProgramFromGui()
{
  m_program->setName(ui->edit_name->text());
  m_program->setExecutable(ui->edit_executableName->text());
  m_program->setUseExecutablePath(ui->gb_executablePath->isChecked());
  m_program->setExecutablePath(ui->edit_executablePath->text());
  m_program->setArguments(ui->edit_arguments->text());
  m_program->setInputFilename(ui->edit_inputFilename->text());
  m_program->setOutputFilename(ui->edit_outputFilename->text());

  Program::LaunchSyntax syntax = static_cast<Program::LaunchSyntax>(
        ui->combo_syntax->currentIndex());
  m_program->setLaunchSyntax(syntax);
  m_program->setCustomLaunchTemplate(m_customLaunchText);
  m_dirty = false;
}

void ProgramConfigureDialog::updateLaunchEditor()
{
  Program::LaunchSyntax syntax = static_cast<Program::LaunchSyntax>(
        ui->combo_syntax->currentIndex());

  if (syntax == Program::CUSTOM) {
    ui->text_launchTemplate->document()->setPlainText(m_customLaunchText);
    return;
  }

  QString launchText;
  if (!m_program->queue() ||
      (qobject_cast<QueueLocal*>(m_program->queue()) &&
       syntax != Program::CUSTOM)) {
    launchText = "$$programExecution$$\n";
  }
  else {
    launchText = m_program->queue()->launchTemplate();
  }

  const QString executableName = ui->edit_executableName->text();
  const QString executablePath = ui->edit_executablePath->text();
  const QString arguments      = ui->edit_arguments->text();
  const QString inputFilename  = ui->edit_inputFilename->text();
  const QString outputFilename = ui->edit_outputFilename->text();
  const bool useExecutablePath = ui->gb_executablePath->isChecked();

  QString programExecution = Program::generateFormattedExecutionString(
        executableName, arguments, inputFilename, outputFilename,
        executablePath, useExecutablePath, syntax);

  launchText.replace("$$programExecution$$", programExecution);

  ui->text_launchTemplate->document()->setPlainText(launchText);
}

void ProgramConfigureDialog::launchEditorTextChanged()
{
  QString launchText = ui->text_launchTemplate->document()->toPlainText();
  Program::LaunchSyntax syntax = static_cast<Program::LaunchSyntax>(
        ui->combo_syntax->currentIndex());

  if (syntax == Program::CUSTOM)
    m_customLaunchText = launchText;

  /// @todo Syntax highlighting?

}

void ProgramConfigureDialog::launchSyntaxChanged(int enumVal)
{
  Q_UNUSED(enumVal);

  Program::LaunchSyntax syntax = static_cast<Program::LaunchSyntax>(enumVal);

  bool syntaxIsCustom = (syntax == Program::CUSTOM);

  ui->push_customize->setDisabled(syntaxIsCustom);
  ui->text_launchTemplate->setReadOnly(!syntaxIsCustom);

  updateLaunchEditor();
}

void ProgramConfigureDialog::customizeLauncherClicked()
{
  Program::LaunchSyntax syntax = static_cast<Program::LaunchSyntax>(
        ui->combo_syntax->currentIndex());

  if (qobject_cast<QueueLocal*>(m_program->queue()) &&
      syntax != Program::CUSTOM) {
    m_customLaunchText = m_program->queue()->launchTemplate();
    QString execStr = ui->text_launchTemplate->document()->toPlainText();
    m_customLaunchText.replace("$$programExecution$$", execStr);
  }
  else {
    m_customLaunchText = ui->text_launchTemplate->document()->toPlainText();
  }

  ui->combo_syntax->setCurrentIndex(static_cast<int>(Program::CUSTOM));
}

void ProgramConfigureDialog::closeEvent(QCloseEvent *e)
{
  if (m_dirty) {
    // apply or discard changes?
    QMessageBox::StandardButton reply =
        QMessageBox::warning(this, tr("Unsaved changes"),
                             tr("The changes to the program have not been "
                                "saved. Would you like to save or discard "
                                "them?"),
                             QMessageBox::Save | QMessageBox::Discard |
                             QMessageBox::Cancel,
                             QMessageBox::Save);

    switch (reply) {
    case QMessageBox::Cancel:
      e->ignore();
      return;
    case QMessageBox::Save:
      updateProgramFromGui();
    case QMessageBox::NoButton:
    case QMessageBox::Discard:
    default:
      e->accept();
      break;
    }
  }

  QDialog::closeEvent(e);
}

void ProgramConfigureDialog::keyPressEvent(QKeyEvent *e)
{
  // By default, the escape key bypasses the close event, but we still want to
  // check if the settings widget is dirty.
  if (e->key() == Qt::Key_Escape) {
    e->accept();
    close();
    return;
  }

  QDialog::keyPressEvent(e);
}

void ProgramConfigureDialog::showHelpDialog()
{
  if (!m_helpDialog)
    m_helpDialog = new TemplateKeywordDialog(this);
  m_helpDialog->show();
}

void ProgramConfigureDialog::buttonBoxButtonClicked(QAbstractButton *button)
{
  // "Ok" and "Cancel" are directly connected to accept() and reject(), so only
  // check for "apply" here:
  if (button == ui->buttonBox->button(QDialogButtonBox::Apply))
    updateProgramFromGui();
}

} // end namespace MoleQueue
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
**   * Redistributions of source code must retain the above copyright
**     notice, this list of conditions and the following disclaimer.
**   * Redistributions in binary form must reproduce the above copyright
**     notice, this list of conditions and the following disclaimer in
**     the documentation and/or other materials provided with the
**     distribution.
**   * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
**     of its contributors may be used to endorse or promote products derived
**     from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include <QtWidgets>

#include "glwidget.h"
#include "window.h"

Window::Window()
{
    QGridLayout *mainLayout = new QGridLayout;

    QColor clearColor;
    clearColor.setHsv(42, 255, 63);

    QSurfaceFormat fmt = QSurfaceFormat::defaultFormat();
    fmt.setSwapInterval(0);
    QSurfaceFormat::setDefaultFormat(fmt);

    qDebug() << QSurfaceFormat::defaultFormat();

    glWidgets = new GLWidget;
    glWidgets->setClearColor(clearColor);

    mainLayout->setMargin(0);
    mainLayout->addWidget(glWidgets);

    setLayout(mainLayout);

    setWindowTitle(tr("Textures"));
    showFullScreen();
}

<commit_msg>Added command line option --vsync to enable.<commit_after>/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
**   * Redistributions of source code must retain the above copyright
**     notice, this list of conditions and the following disclaimer.
**   * Redistributions in binary form must reproduce the above copyright
**     notice, this list of conditions and the following disclaimer in
**     the documentation and/or other materials provided with the
**     distribution.
**   * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
**     of its contributors may be used to endorse or promote products derived
**     from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include <QtWidgets>

#include "glwidget.h"
#include "window.h"

Window::Window()
{
    QGridLayout *mainLayout = new QGridLayout;

    QColor clearColor;
    clearColor.setHsv(42, 255, 63);

    QSurfaceFormat fmt = QSurfaceFormat::defaultFormat();
    QStringList args = QApplication::arguments();
    QCommandLineParser parser;
    QCommandLineOption vsync("vsync");
    parser.addOption(vsync);
    parser.process(args);
    fmt.setSwapInterval(parser.isSet(vsync));
    QSurfaceFormat::setDefaultFormat(fmt);

    qDebug() << QSurfaceFormat::defaultFormat();

    glWidgets = new GLWidget;
    glWidgets->setClearColor(clearColor);

    mainLayout->setMargin(0);
    mainLayout->addWidget(glWidgets);

    setLayout(mainLayout);

    setWindowTitle(tr("Textures"));
    showFullScreen();
}

<|endoftext|>


<commit_before>#include "srm/table.hpp"
#include "srm/count.hpp"
#include "srm/report.hpp"

#include "testutil.hpp"

#include <iostream>
#include <vector>
#include <array>

// Range matching tests that exhaustively try all 0-6 character strings with
// alphabet 0-2 / A-C.

using namespace std;

struct String {
	String(int size, int bits) : size(size) {
		chars[0] = bits & 3;
		chars[1] = (bits >> 2) & 3;
		chars[2] = (bits >> 4) & 3;
		chars[3] = (bits >> 6) & 3;
		chars[4] = (bits >> 8) & 3;
	}

	const char* begin() const {
		return &chars[0];
	}
	char* begin() {
		return &chars[0];
	}
	const char* end() const {
		return begin() + size;
	}
	char* end() {
		return begin() + size;
	}

	char chars[7];
	int size;
};

// For printing strings in debugging.
ostream& operator<<(ostream& out, const String& s) {
	for(char c : s) {
		out << (char)('A' + c);
	}
	return out;
}

void testRangeMatch(String X, String Y, String Z) {
	vector<int> reports;
	srm::reportRangeMatches(
		X.begin(), X.end(),
		Y.begin(), Y.end(),
		Z.begin(), Z.end(),
		[&](int i) { reports.push_back(i); }
	);

	int count = srm::makeRangeCounter(Y.begin(), Y.end(), Z.begin(), Z.end())
		.count(X.begin(), X.end());

	vector<bool> table(X.size);
	srm::computeRangeMatchTableToIterator(
		X.begin(), X.end(),
		Y.begin(), Y.end(),
		Z.begin(), Z.end(),
		table.begin()
	);

	// Cross-check all three.
	if((int)reports.size() != count) fail("report and count disagree.");

	vector<int> table_reports;
	for(int i = 0; i < X.size; ++i) {
		if(table[i]) {
			table_reports.push_back(i);
		}
	}

	sort(reports.begin(), reports.end());
	if(reports.size() != table_reports.size()) fail("report and table disagree.");
	if(!equal(reports.begin(), reports.end(), table_reports.begin())) fail("report and table disagree.");

	// Compare table to a trivial implementation.
	char* it = X.begin();
	for(int i = 0; i < X.size; ++i) {
		bool match =
			!lexicographical_compare(it, X.end(), Y.begin(), Y.end()) &&
			lexicographical_compare(it, X.end(), Z.begin(), Z.end());

		if(table[i] != match) fail("table and trivial implementation disagree.");

		++it;
	}
}

int main() {
	// Try all pairs X, Y, Z.
	int done = 0;
	for(int Xs = 0; Xs <= 6; ++Xs) {
	for(int Xb = 0; Xb < (1 << (2 * Xs)); ++Xb) {
		// Disallow 3.
		if(Xb & (Xb >> 1) & 0x555) continue;

		String X(Xs, Xb);

		for(int Ys = 0; Ys <= 6; ++Ys) {
		for(int Yb = 0; Yb < (1 << (2 * Ys)); ++Yb) {
			if(Yb & (Yb >> 1) & 0x555) continue;

			String Y(Ys, Yb);
			for(int Zs = 0; Zs <= 6; ++Zs) {
			for(int Zb = 0; Zb < (1 << (2 * Zs)); ++Zb) {
				if(Zb & (Zb >> 1) & 0x555) continue;

				String Z(Zs, Zb);

				// We require that Y <= Z.
				if(lexicographical_compare(Z.begin(), Z.end(), Y.begin(), Y.end())) continue;

				testRangeMatch(X, Y, Z);

				++done;
			}
			}
		}
		}

		cout << (double)done / 6534730.03 << "% done.\n";
	}
	}

	cout << "All OK!\n";

	return 0;
}
<commit_msg>Fixed another bug in smalltest...<commit_after>#include "srm/table.hpp"
#include "srm/count.hpp"
#include "srm/report.hpp"

#include "testutil.hpp"

#include <iostream>
#include <vector>
#include <array>

// Range matching tests that exhaustively try all 0-6 character strings with
// alphabet 0-2 / A-C.

using namespace std;

struct String {
	String(int size, int bits) : size(size) {
		chars[0] = bits & 3;
		chars[1] = (bits >> 2) & 3;
		chars[2] = (bits >> 4) & 3;
		chars[3] = (bits >> 6) & 3;
		chars[4] = (bits >> 8) & 3;
		chars[5] = (bits >> 10) & 3;
	}

	const char* begin() const {
		return &chars[0];
	}
	char* begin() {
		return &chars[0];
	}
	const char* end() const {
		return begin() + size;
	}
	char* end() {
		return begin() + size;
	}

	char chars[7];
	int size;
};

// For printing strings in debugging.
ostream& operator<<(ostream& out, const String& s) {
	for(char c : s) {
		out << (char)('A' + c);
	}
	return out;
}

void testRangeMatch(String X, String Y, String Z) {
	vector<int> reports;
	srm::reportRangeMatches(
		X.begin(), X.end(),
		Y.begin(), Y.end(),
		Z.begin(), Z.end(),
		[&](int i) { reports.push_back(i); }
	);

	int count = srm::makeRangeCounter(Y.begin(), Y.end(), Z.begin(), Z.end())
		.count(X.begin(), X.end());

	vector<bool> table(X.size);
	srm::computeRangeMatchTableToIterator(
		X.begin(), X.end(),
		Y.begin(), Y.end(),
		Z.begin(), Z.end(),
		table.begin()
	);

	// Cross-check all three.
	if((int)reports.size() != count) fail("report and count disagree.");

	vector<int> table_reports;
	for(int i = 0; i < X.size; ++i) {
		if(table[i]) {
			table_reports.push_back(i);
		}
	}

	sort(reports.begin(), reports.end());
	if(reports.size() != table_reports.size()) fail("report and table disagree.");
	if(!equal(reports.begin(), reports.end(), table_reports.begin())) fail("report and table disagree.");

	// Compare table to a trivial implementation.
	char* it = X.begin();
	for(int i = 0; i < X.size; ++i) {
		bool match =
			!lexicographical_compare(it, X.end(), Y.begin(), Y.end()) &&
			lexicographical_compare(it, X.end(), Z.begin(), Z.end());

		if(table[i] != match) fail("table and trivial implementation disagree.");

		++it;
	}
}

int main() {
	// Try all pairs X, Y, Z.
	int done = 0;
	for(int Xs = 0; Xs <= 6; ++Xs) {
	for(int Xb = 0; Xb < (1 << (2 * Xs)); ++Xb) {
		// Disallow 3.
		if(Xb & (Xb >> 1) & 0x555) continue;

		String X(Xs, Xb);

		for(int Ys = 0; Ys <= 6; ++Ys) {
		for(int Yb = 0; Yb < (1 << (2 * Ys)); ++Yb) {
			if(Yb & (Yb >> 1) & 0x555) continue;

			String Y(Ys, Yb);
			for(int Zs = 0; Zs <= 6; ++Zs) {
			for(int Zb = 0; Zb < (1 << (2 * Zs)); ++Zb) {
				if(Zb & (Zb >> 1) & 0x555) continue;

				String Z(Zs, Zb);

				// We require that Y <= Z.
				if(lexicographical_compare(Z.begin(), Z.end(), Y.begin(), Y.end())) continue;

				testRangeMatch(X, Y, Z);

				++done;
			}
			}
		}
		}

		cout << (double)done / 6534730.03 << "% done.\n";
	}
	}

	cout << "All OK!\n";

	return 0;
}
<|endoftext|>


<commit_before>//===-- asan_malloc_mac.cc ------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is a part of AddressSanitizer, an address sanity checker.
//
// Mac-specific malloc interception.
//===----------------------------------------------------------------------===//

#include "sanitizer_common/sanitizer_platform.h"
#if SANITIZER_MAC

#include <AvailabilityMacros.h>
#include <CoreFoundation/CFBase.h>
#include <dlfcn.h>
#include <malloc/malloc.h>
#include <sys/mman.h>

#include "asan_allocator.h"
#include "asan_interceptors.h"
#include "asan_internal.h"
#include "asan_mac.h"
#include "asan_report.h"
#include "asan_stack.h"
#include "asan_stats.h"

// Similar code is used in Google Perftools,
// http://code.google.com/p/google-perftools.

// ---------------------- Replacement functions ---------------- {{{1
using namespace __asan;  // NOLINT

// TODO(glider): do we need both zones?
static malloc_zone_t *system_malloc_zone = 0;
static malloc_zone_t asan_zone;

INTERCEPTOR(malloc_zone_t *, malloc_create_zone,
                             vm_size_t start_size, unsigned zone_flags) {
  if (!asan_inited) __asan_init();
  GET_STACK_TRACE_MALLOC;
  uptr page_size = GetPageSizeCached();
  uptr allocated_size = RoundUpTo(sizeof(asan_zone), page_size);
  malloc_zone_t *new_zone =
      (malloc_zone_t*)asan_memalign(page_size, allocated_size,
                                    &stack, FROM_MALLOC);
  internal_memcpy(new_zone, &asan_zone, sizeof(asan_zone));
  new_zone->zone_name = NULL;  // The name will be changed anyway.
  // Prevent the client app from overwriting the zone contents.
  // Library functions that need to modify the zone will set PROT_WRITE on it.
  mprotect(new_zone, allocated_size, PROT_READ);
  return new_zone;
}

INTERCEPTOR(malloc_zone_t *, malloc_default_zone, void) {
  if (!asan_inited) __asan_init();
  return &asan_zone;
}

INTERCEPTOR(malloc_zone_t *, malloc_default_purgeable_zone, void) {
  // FIXME: ASan should support purgeable allocations.
  // https://code.google.com/p/address-sanitizer/issues/detail?id=139
  if (!asan_inited) __asan_init();
  return &asan_zone;
}

INTERCEPTOR(void, malloc_make_purgeable, void *ptr) {
  // FIXME: ASan should support purgeable allocations. Ignoring them is fine
  // for now.
  if (!asan_inited) __asan_init();
}

INTERCEPTOR(int, malloc_make_nonpurgeable, void *ptr) {
  // FIXME: ASan should support purgeable allocations. Ignoring them is fine
  // for now.
  if (!asan_inited) __asan_init();
  // Must return 0 if the contents were not purged since the last call to
  // malloc_make_purgeable().
  return 0;
}

INTERCEPTOR(void, malloc_set_zone_name, malloc_zone_t *zone, const char *name) {
  if (!asan_inited) __asan_init();
  // Allocate |strlen("asan-") + 1 + internal_strlen(name)| bytes.
  size_t buflen = 6 + (name ? internal_strlen(name) : 0);
  InternalScopedBuffer<char> new_name(buflen);
  if (name && zone->introspect == asan_zone.introspect) {
    internal_snprintf(new_name.data(), buflen, "asan-%s", name);
    name = new_name.data();
  }

  // Call the system malloc's implementation for both external and our zones,
  // since that appropriately changes VM region protections on the zone.
  REAL(malloc_set_zone_name)(zone, name);
}

INTERCEPTOR(void *, malloc, size_t size) {
  if (!asan_inited) __asan_init();
  GET_STACK_TRACE_MALLOC;
  void *res = asan_malloc(size, &stack);
  return res;
}

INTERCEPTOR(void, free, void *ptr) {
  if (!asan_inited) __asan_init();
  if (!ptr) return;
  GET_STACK_TRACE_FREE;
  asan_free(ptr, &stack, FROM_MALLOC);
}

INTERCEPTOR(void *, realloc, void *ptr, size_t size) {
  if (!asan_inited) __asan_init();
  GET_STACK_TRACE_MALLOC;
  return asan_realloc(ptr, size, &stack);
}

INTERCEPTOR(void *, calloc, size_t nmemb, size_t size) {
  if (!asan_inited) __asan_init();
  GET_STACK_TRACE_MALLOC;
  return asan_calloc(nmemb, size, &stack);
}

INTERCEPTOR(void *, valloc, size_t size) {
  if (!asan_inited) __asan_init();
  GET_STACK_TRACE_MALLOC;
  return asan_memalign(GetPageSizeCached(), size, &stack, FROM_MALLOC);
}

INTERCEPTOR(size_t, malloc_good_size, size_t size) {
  if (!asan_inited) __asan_init();
  return asan_zone.introspect->good_size(&asan_zone, size);
}

INTERCEPTOR(int, posix_memalign, void **memptr, size_t alignment, size_t size) {
  if (!asan_inited) __asan_init();
  CHECK(memptr);
  GET_STACK_TRACE_MALLOC;
  void *result = asan_memalign(alignment, size, &stack, FROM_MALLOC);
  if (result) {
    *memptr = result;
    return 0;
  }
  return -1;
}

namespace {

// TODO(glider): the mz_* functions should be united with the Linux wrappers,
// as they are basically copied from there.
size_t mz_size(malloc_zone_t* zone, const void* ptr) {
  return asan_mz_size(ptr);
}

void *mz_malloc(malloc_zone_t *zone, size_t size) {
  if (!asan_inited) {
    CHECK(system_malloc_zone);
    return malloc_zone_malloc(system_malloc_zone, size);
  }
  GET_STACK_TRACE_MALLOC;
  return asan_malloc(size, &stack);
}

void *mz_calloc(malloc_zone_t *zone, size_t nmemb, size_t size) {
  if (!asan_inited) {
    // Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym.
    const size_t kCallocPoolSize = 1024;
    static uptr calloc_memory_for_dlsym[kCallocPoolSize];
    static size_t allocated;
    size_t size_in_words = ((nmemb * size) + kWordSize - 1) / kWordSize;
    void *mem = (void*)&calloc_memory_for_dlsym[allocated];
    allocated += size_in_words;
    CHECK(allocated < kCallocPoolSize);
    return mem;
  }
  GET_STACK_TRACE_MALLOC;
  return asan_calloc(nmemb, size, &stack);
}

void *mz_valloc(malloc_zone_t *zone, size_t size) {
  if (!asan_inited) {
    CHECK(system_malloc_zone);
    return malloc_zone_valloc(system_malloc_zone, size);
  }
  GET_STACK_TRACE_MALLOC;
  return asan_memalign(GetPageSizeCached(), size, &stack, FROM_MALLOC);
}

#define GET_ZONE_FOR_PTR(ptr) \
  malloc_zone_t *zone_ptr = malloc_zone_from_ptr(ptr); \
  const char *zone_name = (zone_ptr == 0) ? 0 : zone_ptr->zone_name

void ALWAYS_INLINE free_common(void *context, void *ptr) {
  if (!ptr) return;
  GET_STACK_TRACE_FREE;
  // FIXME: need to retire this flag.
  if (!flags()->mac_ignore_invalid_free) {
    asan_free(ptr, &stack, FROM_MALLOC);
  } else {
    GET_ZONE_FOR_PTR(ptr);
    WarnMacFreeUnallocated((uptr)ptr, (uptr)zone_ptr, zone_name, &stack);
    return;
  }
}

// TODO(glider): the allocation callbacks need to be refactored.
void mz_free(malloc_zone_t *zone, void *ptr) {
  free_common(zone, ptr);
}

void *mz_realloc(malloc_zone_t *zone, void *ptr, size_t size) {
  if (!ptr) {
    GET_STACK_TRACE_MALLOC;
    return asan_malloc(size, &stack);
  } else {
    if (asan_mz_size(ptr)) {
      GET_STACK_TRACE_MALLOC;
      return asan_realloc(ptr, size, &stack);
    } else {
      // We can't recover from reallocating an unknown address, because
      // this would require reading at most |size| bytes from
      // potentially unaccessible memory.
      GET_STACK_TRACE_FREE;
      GET_ZONE_FOR_PTR(ptr);
      ReportMacMzReallocUnknown((uptr)ptr, (uptr)zone_ptr, zone_name, &stack);
    }
  }
}

void mz_destroy(malloc_zone_t* zone) {
  // A no-op -- we will not be destroyed!
  Report("mz_destroy() called -- ignoring\n");
}

  // from AvailabilityMacros.h
#if defined(MAC_OS_X_VERSION_10_6) && \
    MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
void *mz_memalign(malloc_zone_t *zone, size_t align, size_t size) {
  if (!asan_inited) {
    CHECK(system_malloc_zone);
    return malloc_zone_memalign(system_malloc_zone, align, size);
  }
  GET_STACK_TRACE_MALLOC;
  return asan_memalign(align, size, &stack, FROM_MALLOC);
}

// This function is currently unused, and we build with -Werror.
#if 0
void mz_free_definite_size(malloc_zone_t* zone, void *ptr, size_t size) {
  // TODO(glider): check that |size| is valid.
  UNIMPLEMENTED();
}
#endif
#endif

kern_return_t mi_enumerator(task_t task, void *,
                            unsigned type_mask, vm_address_t zone_address,
                            memory_reader_t reader,
                            vm_range_recorder_t recorder) {
  // Should enumerate all the pointers we have.  Seems like a lot of work.
  return KERN_FAILURE;
}

size_t mi_good_size(malloc_zone_t *zone, size_t size) {
  // I think it's always safe to return size, but we maybe could do better.
  return size;
}

boolean_t mi_check(malloc_zone_t *zone) {
  UNIMPLEMENTED();
}

void mi_print(malloc_zone_t *zone, boolean_t verbose) {
  UNIMPLEMENTED();
}

void mi_log(malloc_zone_t *zone, void *address) {
  // I don't think we support anything like this
}

void mi_force_lock(malloc_zone_t *zone) {
  asan_mz_force_lock();
}

void mi_force_unlock(malloc_zone_t *zone) {
  asan_mz_force_unlock();
}

void mi_statistics(malloc_zone_t *zone, malloc_statistics_t *stats) {
  AsanMallocStats malloc_stats;
  FillMallocStatistics(&malloc_stats);
  CHECK(sizeof(malloc_statistics_t) == sizeof(AsanMallocStats));
  internal_memcpy(stats, &malloc_stats, sizeof(malloc_statistics_t));
}

#if defined(MAC_OS_X_VERSION_10_6) && \
    MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
boolean_t mi_zone_locked(malloc_zone_t *zone) {
  // UNIMPLEMENTED();
  return false;
}
#endif

}  // unnamed namespace

namespace __asan {

void ReplaceSystemMalloc() {
  static malloc_introspection_t asan_introspection;
  // Ok to use internal_memset, these places are not performance-critical.
  internal_memset(&asan_introspection, 0, sizeof(asan_introspection));

  asan_introspection.enumerator = &mi_enumerator;
  asan_introspection.good_size = &mi_good_size;
  asan_introspection.check = &mi_check;
  asan_introspection.print = &mi_print;
  asan_introspection.log = &mi_log;
  asan_introspection.force_lock = &mi_force_lock;
  asan_introspection.force_unlock = &mi_force_unlock;
  asan_introspection.statistics = &mi_statistics;

  internal_memset(&asan_zone, 0, sizeof(malloc_zone_t));

  // Start with a version 4 zone which is used for OS X 10.4 and 10.5.
  asan_zone.version = 4;
  asan_zone.zone_name = "asan";
  asan_zone.size = &mz_size;
  asan_zone.malloc = &mz_malloc;
  asan_zone.calloc = &mz_calloc;
  asan_zone.valloc = &mz_valloc;
  asan_zone.free = &mz_free;
  asan_zone.realloc = &mz_realloc;
  asan_zone.destroy = &mz_destroy;
  asan_zone.batch_malloc = 0;
  asan_zone.batch_free = 0;
  asan_zone.introspect = &asan_introspection;

  // from AvailabilityMacros.h
#if defined(MAC_OS_X_VERSION_10_6) && \
    MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
  // Switch to version 6 on OSX 10.6 to support memalign.
  asan_zone.version = 6;
  asan_zone.free_definite_size = 0;
  asan_zone.memalign = &mz_memalign;
  asan_introspection.zone_locked = &mi_zone_locked;
#endif

  // Register the ASan zone.
  malloc_zone_register(&asan_zone);
}
}  // namespace __asan

#endif  // SANITIZER_MAC
<commit_msg>[ASan] Do not protect the malloc zone created by malloc_zone_create() on Snow Leopard and earlier systems. Fixes https://code.google.com/p/address-sanitizer/issues/detail?id=208<commit_after>//===-- asan_malloc_mac.cc ------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is a part of AddressSanitizer, an address sanity checker.
//
// Mac-specific malloc interception.
//===----------------------------------------------------------------------===//

#include "sanitizer_common/sanitizer_platform.h"
#if SANITIZER_MAC

#include <AvailabilityMacros.h>
#include <CoreFoundation/CFBase.h>
#include <dlfcn.h>
#include <malloc/malloc.h>
#include <sys/mman.h>

#include "asan_allocator.h"
#include "asan_interceptors.h"
#include "asan_internal.h"
#include "asan_mac.h"
#include "asan_report.h"
#include "asan_stack.h"
#include "asan_stats.h"

// Similar code is used in Google Perftools,
// http://code.google.com/p/google-perftools.

// ---------------------- Replacement functions ---------------- {{{1
using namespace __asan;  // NOLINT

// TODO(glider): do we need both zones?
static malloc_zone_t *system_malloc_zone = 0;
static malloc_zone_t asan_zone;

INTERCEPTOR(malloc_zone_t *, malloc_create_zone,
                             vm_size_t start_size, unsigned zone_flags) {
  if (!asan_inited) __asan_init();
  GET_STACK_TRACE_MALLOC;
  uptr page_size = GetPageSizeCached();
  uptr allocated_size = RoundUpTo(sizeof(asan_zone), page_size);
  malloc_zone_t *new_zone =
      (malloc_zone_t*)asan_memalign(page_size, allocated_size,
                                    &stack, FROM_MALLOC);
  internal_memcpy(new_zone, &asan_zone, sizeof(asan_zone));
  new_zone->zone_name = NULL;  // The name will be changed anyway.
  if (GetMacosVersion() >= MACOS_VERSION_LION) {
    // Prevent the client app from overwriting the zone contents.
    // Library functions that need to modify the zone will set PROT_WRITE on it.
    // This matches the behavior of malloc_create_zone() on OSX 10.7 and higher.
    mprotect(new_zone, allocated_size, PROT_READ);
  }
  return new_zone;
}

INTERCEPTOR(malloc_zone_t *, malloc_default_zone, void) {
  if (!asan_inited) __asan_init();
  return &asan_zone;
}

INTERCEPTOR(malloc_zone_t *, malloc_default_purgeable_zone, void) {
  // FIXME: ASan should support purgeable allocations.
  // https://code.google.com/p/address-sanitizer/issues/detail?id=139
  if (!asan_inited) __asan_init();
  return &asan_zone;
}

INTERCEPTOR(void, malloc_make_purgeable, void *ptr) {
  // FIXME: ASan should support purgeable allocations. Ignoring them is fine
  // for now.
  if (!asan_inited) __asan_init();
}

INTERCEPTOR(int, malloc_make_nonpurgeable, void *ptr) {
  // FIXME: ASan should support purgeable allocations. Ignoring them is fine
  // for now.
  if (!asan_inited) __asan_init();
  // Must return 0 if the contents were not purged since the last call to
  // malloc_make_purgeable().
  return 0;
}

INTERCEPTOR(void, malloc_set_zone_name, malloc_zone_t *zone, const char *name) {
  if (!asan_inited) __asan_init();
  // Allocate |strlen("asan-") + 1 + internal_strlen(name)| bytes.
  size_t buflen = 6 + (name ? internal_strlen(name) : 0);
  InternalScopedBuffer<char> new_name(buflen);
  if (name && zone->introspect == asan_zone.introspect) {
    internal_snprintf(new_name.data(), buflen, "asan-%s", name);
    name = new_name.data();
  }

  // Call the system malloc's implementation for both external and our zones,
  // since that appropriately changes VM region protections on the zone.
  REAL(malloc_set_zone_name)(zone, name);
}

INTERCEPTOR(void *, malloc, size_t size) {
  if (!asan_inited) __asan_init();
  GET_STACK_TRACE_MALLOC;
  void *res = asan_malloc(size, &stack);
  return res;
}

INTERCEPTOR(void, free, void *ptr) {
  if (!asan_inited) __asan_init();
  if (!ptr) return;
  GET_STACK_TRACE_FREE;
  asan_free(ptr, &stack, FROM_MALLOC);
}

INTERCEPTOR(void *, realloc, void *ptr, size_t size) {
  if (!asan_inited) __asan_init();
  GET_STACK_TRACE_MALLOC;
  return asan_realloc(ptr, size, &stack);
}

INTERCEPTOR(void *, calloc, size_t nmemb, size_t size) {
  if (!asan_inited) __asan_init();
  GET_STACK_TRACE_MALLOC;
  return asan_calloc(nmemb, size, &stack);
}

INTERCEPTOR(void *, valloc, size_t size) {
  if (!asan_inited) __asan_init();
  GET_STACK_TRACE_MALLOC;
  return asan_memalign(GetPageSizeCached(), size, &stack, FROM_MALLOC);
}

INTERCEPTOR(size_t, malloc_good_size, size_t size) {
  if (!asan_inited) __asan_init();
  return asan_zone.introspect->good_size(&asan_zone, size);
}

INTERCEPTOR(int, posix_memalign, void **memptr, size_t alignment, size_t size) {
  if (!asan_inited) __asan_init();
  CHECK(memptr);
  GET_STACK_TRACE_MALLOC;
  void *result = asan_memalign(alignment, size, &stack, FROM_MALLOC);
  if (result) {
    *memptr = result;
    return 0;
  }
  return -1;
}

namespace {

// TODO(glider): the mz_* functions should be united with the Linux wrappers,
// as they are basically copied from there.
size_t mz_size(malloc_zone_t* zone, const void* ptr) {
  return asan_mz_size(ptr);
}

void *mz_malloc(malloc_zone_t *zone, size_t size) {
  if (!asan_inited) {
    CHECK(system_malloc_zone);
    return malloc_zone_malloc(system_malloc_zone, size);
  }
  GET_STACK_TRACE_MALLOC;
  return asan_malloc(size, &stack);
}

void *mz_calloc(malloc_zone_t *zone, size_t nmemb, size_t size) {
  if (!asan_inited) {
    // Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym.
    const size_t kCallocPoolSize = 1024;
    static uptr calloc_memory_for_dlsym[kCallocPoolSize];
    static size_t allocated;
    size_t size_in_words = ((nmemb * size) + kWordSize - 1) / kWordSize;
    void *mem = (void*)&calloc_memory_for_dlsym[allocated];
    allocated += size_in_words;
    CHECK(allocated < kCallocPoolSize);
    return mem;
  }
  GET_STACK_TRACE_MALLOC;
  return asan_calloc(nmemb, size, &stack);
}

void *mz_valloc(malloc_zone_t *zone, size_t size) {
  if (!asan_inited) {
    CHECK(system_malloc_zone);
    return malloc_zone_valloc(system_malloc_zone, size);
  }
  GET_STACK_TRACE_MALLOC;
  return asan_memalign(GetPageSizeCached(), size, &stack, FROM_MALLOC);
}

#define GET_ZONE_FOR_PTR(ptr) \
  malloc_zone_t *zone_ptr = malloc_zone_from_ptr(ptr); \
  const char *zone_name = (zone_ptr == 0) ? 0 : zone_ptr->zone_name

void ALWAYS_INLINE free_common(void *context, void *ptr) {
  if (!ptr) return;
  GET_STACK_TRACE_FREE;
  // FIXME: need to retire this flag.
  if (!flags()->mac_ignore_invalid_free) {
    asan_free(ptr, &stack, FROM_MALLOC);
  } else {
    GET_ZONE_FOR_PTR(ptr);
    WarnMacFreeUnallocated((uptr)ptr, (uptr)zone_ptr, zone_name, &stack);
    return;
  }
}

// TODO(glider): the allocation callbacks need to be refactored.
void mz_free(malloc_zone_t *zone, void *ptr) {
  free_common(zone, ptr);
}

void *mz_realloc(malloc_zone_t *zone, void *ptr, size_t size) {
  if (!ptr) {
    GET_STACK_TRACE_MALLOC;
    return asan_malloc(size, &stack);
  } else {
    if (asan_mz_size(ptr)) {
      GET_STACK_TRACE_MALLOC;
      return asan_realloc(ptr, size, &stack);
    } else {
      // We can't recover from reallocating an unknown address, because
      // this would require reading at most |size| bytes from
      // potentially unaccessible memory.
      GET_STACK_TRACE_FREE;
      GET_ZONE_FOR_PTR(ptr);
      ReportMacMzReallocUnknown((uptr)ptr, (uptr)zone_ptr, zone_name, &stack);
    }
  }
}

void mz_destroy(malloc_zone_t* zone) {
  // A no-op -- we will not be destroyed!
  Report("mz_destroy() called -- ignoring\n");
}

  // from AvailabilityMacros.h
#if defined(MAC_OS_X_VERSION_10_6) && \
    MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
void *mz_memalign(malloc_zone_t *zone, size_t align, size_t size) {
  if (!asan_inited) {
    CHECK(system_malloc_zone);
    return malloc_zone_memalign(system_malloc_zone, align, size);
  }
  GET_STACK_TRACE_MALLOC;
  return asan_memalign(align, size, &stack, FROM_MALLOC);
}

// This function is currently unused, and we build with -Werror.
#if 0
void mz_free_definite_size(malloc_zone_t* zone, void *ptr, size_t size) {
  // TODO(glider): check that |size| is valid.
  UNIMPLEMENTED();
}
#endif
#endif

kern_return_t mi_enumerator(task_t task, void *,
                            unsigned type_mask, vm_address_t zone_address,
                            memory_reader_t reader,
                            vm_range_recorder_t recorder) {
  // Should enumerate all the pointers we have.  Seems like a lot of work.
  return KERN_FAILURE;
}

size_t mi_good_size(malloc_zone_t *zone, size_t size) {
  // I think it's always safe to return size, but we maybe could do better.
  return size;
}

boolean_t mi_check(malloc_zone_t *zone) {
  UNIMPLEMENTED();
}

void mi_print(malloc_zone_t *zone, boolean_t verbose) {
  UNIMPLEMENTED();
}

void mi_log(malloc_zone_t *zone, void *address) {
  // I don't think we support anything like this
}

void mi_force_lock(malloc_zone_t *zone) {
  asan_mz_force_lock();
}

void mi_force_unlock(malloc_zone_t *zone) {
  asan_mz_force_unlock();
}

void mi_statistics(malloc_zone_t *zone, malloc_statistics_t *stats) {
  AsanMallocStats malloc_stats;
  FillMallocStatistics(&malloc_stats);
  CHECK(sizeof(malloc_statistics_t) == sizeof(AsanMallocStats));
  internal_memcpy(stats, &malloc_stats, sizeof(malloc_statistics_t));
}

#if defined(MAC_OS_X_VERSION_10_6) && \
    MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
boolean_t mi_zone_locked(malloc_zone_t *zone) {
  // UNIMPLEMENTED();
  return false;
}
#endif

}  // unnamed namespace

namespace __asan {

void ReplaceSystemMalloc() {
  static malloc_introspection_t asan_introspection;
  // Ok to use internal_memset, these places are not performance-critical.
  internal_memset(&asan_introspection, 0, sizeof(asan_introspection));

  asan_introspection.enumerator = &mi_enumerator;
  asan_introspection.good_size = &mi_good_size;
  asan_introspection.check = &mi_check;
  asan_introspection.print = &mi_print;
  asan_introspection.log = &mi_log;
  asan_introspection.force_lock = &mi_force_lock;
  asan_introspection.force_unlock = &mi_force_unlock;
  asan_introspection.statistics = &mi_statistics;

  internal_memset(&asan_zone, 0, sizeof(malloc_zone_t));

  // Start with a version 4 zone which is used for OS X 10.4 and 10.5.
  asan_zone.version = 4;
  asan_zone.zone_name = "asan";
  asan_zone.size = &mz_size;
  asan_zone.malloc = &mz_malloc;
  asan_zone.calloc = &mz_calloc;
  asan_zone.valloc = &mz_valloc;
  asan_zone.free = &mz_free;
  asan_zone.realloc = &mz_realloc;
  asan_zone.destroy = &mz_destroy;
  asan_zone.batch_malloc = 0;
  asan_zone.batch_free = 0;
  asan_zone.introspect = &asan_introspection;

  // from AvailabilityMacros.h
#if defined(MAC_OS_X_VERSION_10_6) && \
    MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
  // Switch to version 6 on OSX 10.6 to support memalign.
  asan_zone.version = 6;
  asan_zone.free_definite_size = 0;
  asan_zone.memalign = &mz_memalign;
  asan_introspection.zone_locked = &mi_zone_locked;
#endif

  // Register the ASan zone.
  malloc_zone_register(&asan_zone);
}
}  // namespace __asan

#endif  // SANITIZER_MAC
<|endoftext|>


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

Author: Leonardo de Moura
*/
#include <algorithm>
#include <limits>
#include <unordered_map>
#include "util/list.h"
#include "util/flet.h"
#include "util/freset.h"
#include "util/buffer.h"
#include "util/interrupt.h"
#include "util/sexpr/options.h"
#include "kernel/normalizer.h"
#include "kernel/expr.h"
#include "kernel/context.h"
#include "kernel/environment.h"
#include "kernel/builtin.h"
#include "kernel/metavar.h"
#include "kernel/free_vars.h"
#include "kernel/instantiate.h"
#include "kernel/kernel_exception.h"

#ifndef LEAN_KERNEL_NORMALIZER_MAX_DEPTH
#define LEAN_KERNEL_NORMALIZER_MAX_DEPTH std::numeric_limits<unsigned>::max()
#endif

namespace lean {
static name g_kernel_normalizer_max_depth       {"kernel", "normalizer", "max_depth"};
RegisterUnsignedOption(g_kernel_normalizer_max_depth, LEAN_KERNEL_NORMALIZER_MAX_DEPTH, "(kernel) maximum recursion depth for expression normalizer");
unsigned get_normalizer_max_depth(options const & opts) {
    return opts.get_unsigned(g_kernel_normalizer_max_depth, LEAN_KERNEL_NORMALIZER_MAX_DEPTH);
}

typedef list<expr> value_stack;
value_stack extend(value_stack const & s, expr const & v) {
    lean_assert(!is_lambda(v) && !is_pi(v) && !is_metavar(v) && !is_let(v));
    return cons(v, s);
}

/**
   \brief Internal value used to store closures.
   This is a transient value that is only used during normalization.
*/
class closure : public value {
    expr         m_expr;
    context      m_ctx;
    value_stack  m_stack;
public:
    closure(expr const & e, context const & ctx, value_stack const & s):m_expr(e), m_ctx(ctx), m_stack(s) {}
    virtual ~closure() {}
    virtual expr get_type() const { lean_unreachable(); } // LCOV_EXCL_LINE
    virtual name get_name() const { return name("Closure"); }
    virtual void display(std::ostream & out) const {
        out << "(Closure " << m_expr << " [";
        bool first = true;
        for (auto v : m_stack) {
            if (first) first = false; else out << " ";
            out << v;
        }
        out << "])";
    }
    expr const & get_expr() const { return m_expr; }
    context const & get_context() const { return m_ctx; }
    value_stack const & get_stack() const { return m_stack; }
};

expr mk_closure(expr const & e, context const & ctx, value_stack const & s) { return mk_value(*(new closure(e, ctx, s))); }
bool is_closure(expr const & e) { return is_value(e) && dynamic_cast<closure const *>(&to_value(e)) != nullptr; }
closure const & to_closure(expr const & e) { lean_assert(is_closure(e));   return static_cast<closure const &>(to_value(e)); }

/** \brief Expression normalizer. */
class normalizer::imp {
    typedef std::unordered_map<expr, expr, expr_hash_alloc, expr_eqp> cache;

    ro_environment::weak_ref m_env;
    context                  m_ctx;
    cached_metavar_env       m_menv;
    cache                    m_cache;
    unsigned                 m_max_depth;
    unsigned                 m_depth;

    ro_environment env() const { return ro_environment(m_env); }

    expr instantiate(expr const & e, unsigned n, expr const * s) {
        return ::lean::instantiate(e, n, s, m_menv.to_some_menv());
    }

    expr add_lift(expr const & m, unsigned s, unsigned n) {
        return ::lean::add_lift(m, s, n, m_menv.to_some_menv());
    }

    expr lookup(value_stack const & s, unsigned i) {
        unsigned j = i;
        value_stack const * it1 = &s;
        while (*it1) {
            if (j == 0)
                return head(*it1);
            --j;
            it1 = &tail(*it1);
        }
        auto p = lookup_ext(m_ctx, j);
        context_entry const & entry = p.first;
        context const & entry_c     = p.second;
        if (entry.get_body()) {
            // Save the current context and cache
            freset<cache>    reset(m_cache);
            flet<context>    set(m_ctx, entry_c);
            unsigned k = m_ctx.size();
            return normalize(*(entry.get_body()), value_stack(), k);
        } else {
            return mk_var(entry_c.size());
        }
    }

    /** \brief Convert the value \c v back into an expression in a context that contains \c k binders. */
    expr reify(expr const & v, unsigned k) {
        return replace(v, [&](expr const & e, unsigned DEBUG_CODE(offset)) {
                lean_assert(offset == 0);
                lean_assert(!is_lambda(e) && !is_pi(e) && !is_metavar(e) && !is_let(e));
                if (is_var(e)) {
                    // de Bruijn level --> de Bruijn index
                    return mk_var(k - var_idx(e) - 1);
                } else if (is_closure(e)) {
                    return reify_closure(to_closure(e), k);
                } else {
                    return e;
                }
            });
    }

    /** \brief Return true iff the value_stack does affect the context of a metavariable */
    bool is_identity_stack(value_stack const & s, unsigned k) {
        unsigned i = 0;
        for (auto e : s) {
            if (!is_var(e) || k - var_idx(e) - 1 != i)
                return false;
            ++i;
        }
        return true;
    }

    /** \brief Convert the closure \c c into an expression in a context that contains \c k binders. */
    expr reify_closure(closure const & c, unsigned k) {
        expr const & e        = c.get_expr();
        context const & ctx   = c.get_context();
        value_stack const & s = c.get_stack();
        freset<cache>    reset(m_cache);
        flet<context>    set(m_ctx, ctx);
        if (is_abstraction(e)) {
            return update_abst(e, [&](expr const & d, expr const & b) {
                    expr new_d = reify(normalize(d, s, k), k);
                    m_cache.clear(); // make sure we do not reuse cached values from the previous call
                    expr new_b = reify(normalize(b, extend(s, mk_var(k)), k+1), k+1);
                    return mk_pair(new_d, new_b);
                });
        } else {
            lean_assert(is_metavar(e));
            if (is_identity_stack(s, k))
                return e; // nothing to be done
            local_context lctx = metavar_lctx(e);
            unsigned len_s     = length(s);
            unsigned len_ctx   = ctx.size();
            lean_assert(k >= len_ctx);
            expr r;
            if (k > len_ctx)
                r = add_lift(e, len_s, k - len_ctx);
            else
                r = e;
            buffer<expr> subst;
            for (auto v : s)
                subst.push_back(reify(v, k));
            std::reverse(subst.begin(), subst.end());
            return instantiate(r, subst.size(), subst.data());
        }
    }

    /** \brief Normalize the expression \c a in a context composed of stack \c s and \c k binders. */
    expr normalize(expr const & a, value_stack const & s, unsigned k) {
        flet<unsigned> l(m_depth, m_depth+1);
        check_system("normalizer");
        if (m_depth > m_max_depth)
            throw kernel_exception(env(), "normalizer maximum recursion depth exceeded");
        bool shared = false;
        if (is_shared(a)) {
            shared = true;
            auto it = m_cache.find(a);
            if (it != m_cache.end())
                return it->second;
        }

        expr r;
        switch (a.kind()) {
        case expr_kind::MetaVar: case expr_kind::Pi: case expr_kind::Lambda:
            r = mk_closure(a, m_ctx, s);
            break;
        case expr_kind::Var:
            r = lookup(s, var_idx(a));
            break;
        case expr_kind::Constant: {
            object const & obj = env()->get_object(const_name(a));
            if (obj.is_definition() && !obj.is_opaque()) {
                freset<cache> reset(m_cache);
                r = normalize(obj.get_value(), value_stack(), 0);
            } else {
                r = a;
            }
            break;
        }
        case expr_kind::Type: case expr_kind::Value:
            r = a;
            break;
        case expr_kind::App: {
            expr f      = normalize(arg(a, 0), s, k);
            unsigned i  = 1;
            unsigned n  = num_args(a);
            while (true) {
                if (is_closure(f) && is_lambda(to_closure(f).get_expr())) {
                    // beta reduction
                    expr fv = to_closure(f).get_expr();
                    value_stack new_s = to_closure(f).get_stack();
                    while (is_lambda(fv) && i < n) {
                        new_s = extend(new_s, normalize(arg(a, i), s, k));
                        i++;
                        fv = abst_body(fv);
                    }
                    {
                        freset<cache> reset(m_cache);
                        flet<context> set(m_ctx, to_closure(f).get_context());
                        f = normalize(fv, new_s, k);
                    }
                    if (i == n) {
                        r = f;
                        break;
                    }
                } else {
                    buffer<expr> new_args;
                    new_args.push_back(f);
                    for (; i < n; i++)
                        new_args.push_back(normalize(arg(a, i), s, k));
                    if (is_value(f) && !is_closure(f)) {
                        buffer<expr> reified_args;
                        for (auto arg : new_args) reified_args.push_back(reify(arg, k));
                        optional<expr> m = to_value(f).normalize(reified_args.size(), reified_args.data());
                        if (m) {
                            r = normalize(*m, s, k);
                            break;
                        }
                    }
                    r = mk_app(new_args);
                    break;
                }
            }
            break;
        }
        case expr_kind::Eq: {
            expr new_lhs = normalize(eq_lhs(a), s, k);
            expr new_rhs = normalize(eq_rhs(a), s, k);
            if (is_value(new_lhs) && is_value(new_rhs) && !is_closure(new_lhs) && !is_closure(new_rhs)) {
                r = mk_bool_value(new_lhs == new_rhs);
            } else {
                r = mk_eq(new_lhs, new_rhs);
            }
            break;
        }
        case expr_kind::Let: {
            expr v = normalize(let_value(a), s, k);
            {
                freset<cache> reset(m_cache);
                r = normalize(let_body(a), extend(s, v), k);
            }
            break;
        }}
        if (shared) {
            m_cache[a] = r;
        }
        return r;
    }

    void set_ctx(context const & ctx) {
        if (!is_eqp(ctx, m_ctx)) {
            m_ctx = ctx;
            m_cache.clear();
        }
    }

public:
    imp(ro_environment const & env, unsigned max_depth):
        m_env(env) {
        m_max_depth      = max_depth;
        m_depth          = 0;
    }

    expr operator()(expr const & e, context const & ctx, optional<metavar_env> const & menv) {
        set_ctx(ctx);
        if (m_menv.update(menv))
            m_cache.clear();
        unsigned k = m_ctx.size();
        return reify(normalize(e, value_stack(), k), k);
    }

    void clear() { m_ctx = context(); m_cache.clear(); m_menv.clear(); }
};

normalizer::normalizer(ro_environment const & env, unsigned max_depth):m_ptr(new imp(env, max_depth)) {}
normalizer::normalizer(ro_environment const & env):normalizer(env, std::numeric_limits<unsigned>::max()) {}
normalizer::normalizer(ro_environment const & env, options const & opts):normalizer(env, get_normalizer_max_depth(opts)) {}
normalizer::~normalizer() {}
expr normalizer::operator()(expr const & e, context const & ctx, optional<metavar_env> const & menv) { return (*m_ptr)(e, ctx, menv); }
expr normalizer::operator()(expr const & e, context const & ctx, metavar_env const & menv) { return operator()(e, ctx, some_menv(menv)); }
expr normalizer::operator()(expr const & e, context const & ctx) { return operator()(e, ctx, none_menv()); }
void normalizer::clear() { m_ptr->clear(); }

expr normalize(expr const & e, ro_environment const & env, context const & ctx) {
    return normalizer(env)(e, ctx);
}
}

/*
  Remark:

  Eta-reduction + Cumulativity + Set theoretic interpretation is unsound.
  Example:
     f : (Type 2) -> (Type 2)
     (fun (x : (Type 1)) (f x)) : (Type 1) -> (Type 2)
     The domains of these two terms are different. So, they must have different denotations.

     However, by eta-reduction, we have:
     (fun (x : (Type 1)) (f x)) == f

     For now, we will disable it.
     REMARK: we can workaround this problem by applying only when the domain of f is equal
     to the domain of the lambda abstraction.

  Cody Roux suggested we use Eta-expanded normal forms.

  Remark: The source code for eta-reduction can be found in the commit 519a290f320c6a
*/
<commit_msg>fix(kernel/normalizer): compilation problem with clang++<commit_after>/*
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.

Author: Leonardo de Moura
*/
#include <algorithm>
#include <limits>
#include <unordered_map>
#include "util/list.h"
#include "util/flet.h"
#include "util/freset.h"
#include "util/buffer.h"
#include "util/interrupt.h"
#include "util/sexpr/options.h"
#include "kernel/normalizer.h"
#include "kernel/expr.h"
#include "kernel/context.h"
#include "kernel/environment.h"
#include "kernel/builtin.h"
#include "kernel/metavar.h"
#include "kernel/free_vars.h"
#include "kernel/instantiate.h"
#include "kernel/kernel_exception.h"

#ifndef LEAN_KERNEL_NORMALIZER_MAX_DEPTH
#define LEAN_KERNEL_NORMALIZER_MAX_DEPTH std::numeric_limits<unsigned>::max()
#endif

namespace lean {
static name g_kernel_normalizer_max_depth       {"kernel", "normalizer", "max_depth"};
RegisterUnsignedOption(g_kernel_normalizer_max_depth, LEAN_KERNEL_NORMALIZER_MAX_DEPTH, "(kernel) maximum recursion depth for expression normalizer");
unsigned get_normalizer_max_depth(options const & opts) {
    return opts.get_unsigned(g_kernel_normalizer_max_depth, LEAN_KERNEL_NORMALIZER_MAX_DEPTH);
}

typedef list<expr> value_stack;
value_stack extend(value_stack const & s, expr const & v) {
    lean_assert(!is_lambda(v) && !is_pi(v) && !is_metavar(v) && !is_let(v));
    return cons(v, s);
}

/**
   \brief Internal value used to store closures.
   This is a transient value that is only used during normalization.
*/
class closure : public value {
    expr         m_expr;
    context      m_ctx;
    value_stack  m_stack;
public:
    closure(expr const & e, context const & ctx, value_stack const & s):m_expr(e), m_ctx(ctx), m_stack(s) {}
    virtual ~closure() {}
    virtual expr get_type() const { lean_unreachable(); } // LCOV_EXCL_LINE
    virtual name get_name() const { return name("Closure"); }
    virtual void display(std::ostream & out) const {
        out << "(Closure " << m_expr << " [";
        bool first = true;
        for (auto v : m_stack) {
            if (first) first = false; else out << " ";
            out << v;
        }
        out << "])";
    }
    expr const & get_expr() const { return m_expr; }
    context const & get_context() const { return m_ctx; }
    value_stack const & get_stack() const { return m_stack; }
};

expr mk_closure(expr const & e, context const & ctx, value_stack const & s) { return mk_value(*(new closure(e, ctx, s))); }
bool is_closure(expr const & e) { return is_value(e) && dynamic_cast<closure const *>(&to_value(e)) != nullptr; }
closure const & to_closure(expr const & e) { lean_assert(is_closure(e));   return static_cast<closure const &>(to_value(e)); }

/** \brief Expression normalizer. */
class normalizer::imp {
    typedef std::unordered_map<expr, expr, expr_hash_alloc, expr_eqp> cache;

    ro_environment::weak_ref m_env;
    context                  m_ctx;
    cached_metavar_env       m_menv;
    cache                    m_cache;
    unsigned                 m_max_depth;
    unsigned                 m_depth;

    ro_environment env() const { return ro_environment(m_env); }

    expr instantiate(expr const & e, unsigned n, expr const * s) {
        return ::lean::instantiate(e, n, s, m_menv.to_some_menv());
    }

    expr add_lift(expr const & m, unsigned s, unsigned n) {
        return ::lean::add_lift(m, s, n, m_menv.to_some_menv());
    }

    expr lookup(value_stack const & s, unsigned i) {
        unsigned j = i;
        value_stack const * it1 = &s;
        while (*it1) {
            if (j == 0)
                return head(*it1);
            --j;
            it1 = &tail(*it1);
        }
        auto p = lookup_ext(m_ctx, j);
        context_entry const & entry = p.first;
        context const & entry_c     = p.second;
        if (entry.get_body()) {
            // Save the current context and cache
            freset<cache>    reset(m_cache);
            flet<context>    set(m_ctx, entry_c);
            unsigned k = m_ctx.size();
            return normalize(*(entry.get_body()), value_stack(), k);
        } else {
            return mk_var(entry_c.size());
        }
    }

    /** \brief Convert the value \c v back into an expression in a context that contains \c k binders. */
    expr reify(expr const & v, unsigned k) {
        return replace(v, [&](expr const & e, unsigned DEBUG_CODE(offset)) -> expr {
                lean_assert(offset == 0);
                lean_assert(!is_lambda(e) && !is_pi(e) && !is_metavar(e) && !is_let(e));
                if (is_var(e)) {
                    // de Bruijn level --> de Bruijn index
                    return mk_var(k - var_idx(e) - 1);
                } else if (is_closure(e)) {
                    return reify_closure(to_closure(e), k);
                } else {
                    return e;
                }
            });
    }

    /** \brief Return true iff the value_stack does affect the context of a metavariable */
    bool is_identity_stack(value_stack const & s, unsigned k) {
        unsigned i = 0;
        for (auto e : s) {
            if (!is_var(e) || k - var_idx(e) - 1 != i)
                return false;
            ++i;
        }
        return true;
    }

    /** \brief Convert the closure \c c into an expression in a context that contains \c k binders. */
    expr reify_closure(closure const & c, unsigned k) {
        expr const & e        = c.get_expr();
        context const & ctx   = c.get_context();
        value_stack const & s = c.get_stack();
        freset<cache>    reset(m_cache);
        flet<context>    set(m_ctx, ctx);
        if (is_abstraction(e)) {
            return update_abst(e, [&](expr const & d, expr const & b) {
                    expr new_d = reify(normalize(d, s, k), k);
                    m_cache.clear(); // make sure we do not reuse cached values from the previous call
                    expr new_b = reify(normalize(b, extend(s, mk_var(k)), k+1), k+1);
                    return mk_pair(new_d, new_b);
                });
        } else {
            lean_assert(is_metavar(e));
            if (is_identity_stack(s, k))
                return e; // nothing to be done
            local_context lctx = metavar_lctx(e);
            unsigned len_s     = length(s);
            unsigned len_ctx   = ctx.size();
            lean_assert(k >= len_ctx);
            expr r;
            if (k > len_ctx)
                r = add_lift(e, len_s, k - len_ctx);
            else
                r = e;
            buffer<expr> subst;
            for (auto v : s)
                subst.push_back(reify(v, k));
            std::reverse(subst.begin(), subst.end());
            return instantiate(r, subst.size(), subst.data());
        }
    }

    /** \brief Normalize the expression \c a in a context composed of stack \c s and \c k binders. */
    expr normalize(expr const & a, value_stack const & s, unsigned k) {
        flet<unsigned> l(m_depth, m_depth+1);
        check_system("normalizer");
        if (m_depth > m_max_depth)
            throw kernel_exception(env(), "normalizer maximum recursion depth exceeded");
        bool shared = false;
        if (is_shared(a)) {
            shared = true;
            auto it = m_cache.find(a);
            if (it != m_cache.end())
                return it->second;
        }

        expr r;
        switch (a.kind()) {
        case expr_kind::MetaVar: case expr_kind::Pi: case expr_kind::Lambda:
            r = mk_closure(a, m_ctx, s);
            break;
        case expr_kind::Var:
            r = lookup(s, var_idx(a));
            break;
        case expr_kind::Constant: {
            object const & obj = env()->get_object(const_name(a));
            if (obj.is_definition() && !obj.is_opaque()) {
                freset<cache> reset(m_cache);
                r = normalize(obj.get_value(), value_stack(), 0);
            } else {
                r = a;
            }
            break;
        }
        case expr_kind::Type: case expr_kind::Value:
            r = a;
            break;
        case expr_kind::App: {
            expr f      = normalize(arg(a, 0), s, k);
            unsigned i  = 1;
            unsigned n  = num_args(a);
            while (true) {
                if (is_closure(f) && is_lambda(to_closure(f).get_expr())) {
                    // beta reduction
                    expr fv = to_closure(f).get_expr();
                    value_stack new_s = to_closure(f).get_stack();
                    while (is_lambda(fv) && i < n) {
                        new_s = extend(new_s, normalize(arg(a, i), s, k));
                        i++;
                        fv = abst_body(fv);
                    }
                    {
                        freset<cache> reset(m_cache);
                        flet<context> set(m_ctx, to_closure(f).get_context());
                        f = normalize(fv, new_s, k);
                    }
                    if (i == n) {
                        r = f;
                        break;
                    }
                } else {
                    buffer<expr> new_args;
                    new_args.push_back(f);
                    for (; i < n; i++)
                        new_args.push_back(normalize(arg(a, i), s, k));
                    if (is_value(f) && !is_closure(f)) {
                        buffer<expr> reified_args;
                        for (auto arg : new_args) reified_args.push_back(reify(arg, k));
                        optional<expr> m = to_value(f).normalize(reified_args.size(), reified_args.data());
                        if (m) {
                            r = normalize(*m, s, k);
                            break;
                        }
                    }
                    r = mk_app(new_args);
                    break;
                }
            }
            break;
        }
        case expr_kind::Eq: {
            expr new_lhs = normalize(eq_lhs(a), s, k);
            expr new_rhs = normalize(eq_rhs(a), s, k);
            if (is_value(new_lhs) && is_value(new_rhs) && !is_closure(new_lhs) && !is_closure(new_rhs)) {
                r = mk_bool_value(new_lhs == new_rhs);
            } else {
                r = mk_eq(new_lhs, new_rhs);
            }
            break;
        }
        case expr_kind::Let: {
            expr v = normalize(let_value(a), s, k);
            {
                freset<cache> reset(m_cache);
                r = normalize(let_body(a), extend(s, v), k);
            }
            break;
        }}
        if (shared) {
            m_cache[a] = r;
        }
        return r;
    }

    void set_ctx(context const & ctx) {
        if (!is_eqp(ctx, m_ctx)) {
            m_ctx = ctx;
            m_cache.clear();
        }
    }

public:
    imp(ro_environment const & env, unsigned max_depth):
        m_env(env) {
        m_max_depth      = max_depth;
        m_depth          = 0;
    }

    expr operator()(expr const & e, context const & ctx, optional<metavar_env> const & menv) {
        set_ctx(ctx);
        if (m_menv.update(menv))
            m_cache.clear();
        unsigned k = m_ctx.size();
        return reify(normalize(e, value_stack(), k), k);
    }

    void clear() { m_ctx = context(); m_cache.clear(); m_menv.clear(); }
};

normalizer::normalizer(ro_environment const & env, unsigned max_depth):m_ptr(new imp(env, max_depth)) {}
normalizer::normalizer(ro_environment const & env):normalizer(env, std::numeric_limits<unsigned>::max()) {}
normalizer::normalizer(ro_environment const & env, options const & opts):normalizer(env, get_normalizer_max_depth(opts)) {}
normalizer::~normalizer() {}
expr normalizer::operator()(expr const & e, context const & ctx, optional<metavar_env> const & menv) { return (*m_ptr)(e, ctx, menv); }
expr normalizer::operator()(expr const & e, context const & ctx, metavar_env const & menv) { return operator()(e, ctx, some_menv(menv)); }
expr normalizer::operator()(expr const & e, context const & ctx) { return operator()(e, ctx, none_menv()); }
void normalizer::clear() { m_ptr->clear(); }

expr normalize(expr const & e, ro_environment const & env, context const & ctx) {
    return normalizer(env)(e, ctx);
}
}

/*
  Remark:

  Eta-reduction + Cumulativity + Set theoretic interpretation is unsound.
  Example:
     f : (Type 2) -> (Type 2)
     (fun (x : (Type 1)) (f x)) : (Type 1) -> (Type 2)
     The domains of these two terms are different. So, they must have different denotations.

     However, by eta-reduction, we have:
     (fun (x : (Type 1)) (f x)) == f

     For now, we will disable it.
     REMARK: we can workaround this problem by applying only when the domain of f is equal
     to the domain of the lambda abstraction.

  Cody Roux suggested we use Eta-expanded normal forms.

  Remark: The source code for eta-reduction can be found in the commit 519a290f320c6a
*/
<|endoftext|>


<commit_before>/*
    kopeteglobal.cpp - Kopete Globals

    Copyright (c) 2004      by Richard Smith         <kde@metafoo.co.uk>

    Kopete    (c) 2004      by the Kopete developers <kopete-devel@kde.org>

    *************************************************************************
    *                                                                       *
    * This library is free software; you can redistribute it and/or         *
    * modify it under the terms of the GNU Lesser General Public            *
    * License as published by the Free Software Foundation; either          *
    * version 2 of the License, or (at your option) any later version.      *
    *                                                                       *
    *************************************************************************
*/

#include "kopeteglobal.h"
#include "kopeteuiglobal.h"

#include <QtCore/QLatin1String>
#include <QtGui/QApplication>

#include <kdebug.h>
#include <klocale.h>
#include <kio/netaccess.h>
#include <kmimetype.h>
#include <kmessagebox.h>
#include <kprogressdialog.h>

#include <kstandarddirs.h>
#include <ktar.h>
#include <kzip.h>
#include <kmimetype.h>

namespace Kopete
{

namespace Global
{

class PropertiesPrivate
{
	public:
		ContactPropertyTmpl::Map mTemplates;
};

Properties *Properties::mSelf = 0L;

Properties *Properties::self()
{
	if(!mSelf)
	{
		//kDebug(14000) << k_funcinfo << endl;
		mSelf = new Properties();
	}
	return mSelf;
}

Properties::Properties()
{
	kDebug(14000) << k_funcinfo << endl;
	d = new PropertiesPrivate();
}

Properties::~Properties()
{
	kDebug(14000) << k_funcinfo << endl;
	delete d;
}

const ContactPropertyTmpl &Properties::tmpl(const QString &key) const
{
	if(d->mTemplates.contains(key))
	{
		/*kDebug(14000) << k_funcinfo <<
			"Found template for key = '" << key << "'" << endl;*/
		return d->mTemplates[key];
	}
	else
		return ContactPropertyTmpl::null;
}

bool Properties::registerTemplate(const QString &key,
	const ContactPropertyTmpl &tmpl)
{
	if(d->mTemplates.contains(key))
	{
		kDebug(14000) << k_funcinfo <<
			"Called for EXISTING key = '" << key << "'" << endl;
		return false;
	}
	else
	{
		d->mTemplates.insert(key, tmpl);
		return true;
	}
}

void Properties::unregisterTemplate(const QString &key)
{
	kDebug(14000) << k_funcinfo << "called for key: '" << key << "'" << endl;
	d->mTemplates.remove(key);
}

bool Properties::isRegistered(const QString &key)
{
	return d->mTemplates.contains(key);
}

const ContactPropertyTmpl &Properties::fullName() const
{
	return createProp(QLatin1String("FormattedName"),
		i18n("Full Name"));
}

const ContactPropertyTmpl &Properties::idleTime() const
{
	return createProp(QLatin1String("idleTime"),
		i18n("Idle Time"));
}

const ContactPropertyTmpl &Properties::onlineSince() const
{
	return createProp(QLatin1String("onlineSince"),
		i18n("Online Since"));
}

const ContactPropertyTmpl &Properties::lastSeen() const
{
	return createProp(QLatin1String("lastSeen"),
		i18n("Last Seen"), QString::null, true);
}

const ContactPropertyTmpl &Properties::statusMessage() const
{
	return createProp(QLatin1String("statusMessage"),
		i18n("Status Message"));
}

const ContactPropertyTmpl &Properties::firstName() const
{
	return createProp(QLatin1String("firstName"),
		i18n("First Name"), QString::null, true);
}

const ContactPropertyTmpl &Properties::lastName() const
{
	return createProp(QLatin1String("lastName"),
		i18n("Last Name"), QString::null, true);
}

const ContactPropertyTmpl &Properties::privatePhone() const
{
	return createProp(QLatin1String("privatePhoneNumber"),
		i18n("Private Phone"), QString::null, true);
}

const ContactPropertyTmpl &Properties::privateMobilePhone() const
{
	return createProp(QLatin1String("privateMobilePhoneNumber"),
		i18n("Private Mobile Phone"), QString::null, true);
}

const ContactPropertyTmpl &Properties::workPhone() const
{
	return createProp(QLatin1String("workPhoneNumber"),
		i18n("Work Phone"), QString::null, true);
}

const ContactPropertyTmpl &Properties::workMobilePhone() const
{
	return createProp(QLatin1String("workMobilePhoneNumber"),
		i18n("Work Mobile Phone"), QString::null, true);
}

const ContactPropertyTmpl &Properties::emailAddress() const
{
	return createProp(QLatin1String("emailAddress"),
		i18n("Email Address"), QLatin1String("mail"), true);
}

const ContactPropertyTmpl &Properties::nickName() const
{
	return createProp(QLatin1String("nickName"),
		i18n("Nick Name"), QString::null, true);
}

const ContactPropertyTmpl &Properties::photo() const
{
	return createProp(QLatin1String("photo"),
					  i18n("Photo"), QString::null, true);
}

const ContactPropertyTmpl &Properties::createProp(const QString &key,
	const QString &label, const QString &icon, bool persistent) const
{
	/*kDebug(14000) << k_funcinfo <<
		"key = " << key  << ", label = " << label << endl;*/

	if(!d->mTemplates.contains(key))
	{
/*		kDebug(14000) << k_funcinfo <<
			"CREATING NEW ContactPropertyTmpl WITH key = " << key  <<
			", label = " << label << ", persisten = " << persistent << endl;*/
		d->mTemplates.insert(key,  ContactPropertyTmpl(key, label, icon, persistent ? ContactPropertyTmpl::PersistentProperty : ContactPropertyTmpl::NoProperty));
	}
	return tmpl(key);
}

const ContactPropertyTmpl::Map &Properties::templateMap() const
{
	return d->mTemplates;
}

// -----------------------------------------------------------------------------

void installEmoticonTheme(const QString &archiveName)
{
	QStringList foundThemes;
	KArchiveEntry *currentEntry = 0L;
	KArchiveDirectory* currentDir = 0L;
	KProgressDialog *progressDlg = 0L;
	KArchive *archive = 0L;

	QString localThemesDir(KStandardDirs::locateLocal("emoticons", QString::null) );

	if(localThemesDir.isEmpty())
	{
		KMessageBox::queuedMessageBox(Kopete::UI::Global::mainWidget(),
			KMessageBox::Error, i18n("Could not find suitable place " \
			"to install emoticon themes into."));
		return;
	}

	progressDlg = new KProgressDialog(0,
	 	i18n("Installing Emoticon Themes..."));
	progressDlg->setModal(true);
	progressDlg->progressBar()->setMaximum(foundThemes.count());
	progressDlg->show();
	qApp->processEvents();

	QString currentBundleMimeType = KMimeType::findByPath(archiveName, 0, false)->name();
	if( currentBundleMimeType == QLatin1String("application/zip") )
		archive = new KZip(archiveName);
	else if( currentBundleMimeType == QLatin1String("application/x-compressed-tar") ||
				currentBundleMimeType == QLatin1String("application/x-bzip-compressed-tar") ||
				currentBundleMimeType == QLatin1String("application/x-gzip") ||
				currentBundleMimeType == QLatin1String("application/x-bzip") )
		archive = new KTar(archiveName);
	else if(archiveName.endsWith(QLatin1String("jisp")) || archiveName.endsWith(QLatin1String("zip")) )
		archive = new KZip(archiveName);
	else
		archive = new KTar(archiveName);

	if ( !archive || !archive->open(QIODevice::ReadOnly) )
	{
		KMessageBox::queuedMessageBox(Kopete::UI::Global::mainWidget(),
			KMessageBox::Error,
			i18n("Could not open \"%1\" for unpacking.", archiveName));
		delete archive;
		delete progressDlg;
		return;
	}

	const KArchiveDirectory* rootDir = archive->directory();

	// iterate all the dirs looking for an emoticons.xml file
	QStringList entries = rootDir->entries();
	for (QStringList::Iterator it = entries.begin(); it != entries.end(); ++it)
	{
		currentEntry = const_cast<KArchiveEntry*>(rootDir->entry(*it));
		if (currentEntry->isDirectory())
		{
			currentDir = dynamic_cast<KArchiveDirectory*>( currentEntry );
			if (currentDir && ( currentDir->entry(QLatin1String("emoticons.xml")) != NULL ||
						 		currentDir->entry(QLatin1String("icondef.xml")) != NULL ) )
				foundThemes.append(currentDir->name());
		}
	}

	if (foundThemes.isEmpty())
	{
		KMessageBox::queuedMessageBox(Kopete::UI::Global::mainWidget(),
			KMessageBox::Error, i18n("<qt>The file \"%1\" is not a valid" \
				" emoticon theme archive.</qt>", archiveName));
		archive->close();
		delete archive;
		delete progressDlg;
		return;
	}

	for (int themeIndex = 0; themeIndex < foundThemes.size(); ++themeIndex)
	{
		const QString &theme = foundThemes[themeIndex];

		progressDlg->setLabelText(
			i18n("<qt>Installing %1 emoticon theme</qt>",
			theme));
		progressDlg->progressBar()->setValue(themeIndex);
		progressDlg->resize(progressDlg->sizeHint());
		qApp->processEvents();

		if (progressDlg->wasCancelled())
			break;

		currentEntry = const_cast<KArchiveEntry *>(rootDir->entry(theme));
		if (currentEntry == 0)
		{
			kDebug(14010) << k_funcinfo << "couldn't get next archive entry" << endl;
			continue;
		}

		if(currentEntry->isDirectory())
		{
			currentDir = dynamic_cast<KArchiveDirectory*>(currentEntry);
			if (currentDir == 0)
			{
				kDebug(14010) << k_funcinfo <<
					"couldn't cast archive entry to KArchiveDirectory" << endl;
				continue;
			}
			currentDir->copyTo(localThemesDir + theme);
		}
	}

	archive->close();
	delete archive;

	// check if all steps were done, if there are skipped ones then we didn't
	// succeed copying all dirs from the tarball
	if (progressDlg->progressBar()->maximum() > progressDlg->progressBar()->value())
	{
		KMessageBox::queuedMessageBox(Kopete::UI::Global::mainWidget(),
			KMessageBox::Error,
			i18n("<qt>A problem occurred during the installation process. "
			"However, some of the emoticon themes in the archive may have been "
			"installed.</qt>"));
	}

	delete progressDlg;
}

} // END namespace Global

} // END namespace Kopete

// vim: set noet ts=4 sts=4 sw=4:
<commit_msg>Add support for other Zip mimetypes Signed-off: gustavo.boiko@kdemail.net<commit_after>/*
    kopeteglobal.cpp - Kopete Globals

    Copyright (c) 2004      by Richard Smith         <kde@metafoo.co.uk>

    Kopete    (c) 2004      by the Kopete developers <kopete-devel@kde.org>

    *************************************************************************
    *                                                                       *
    * This library is free software; you can redistribute it and/or         *
    * modify it under the terms of the GNU Lesser General Public            *
    * License as published by the Free Software Foundation; either          *
    * version 2 of the License, or (at your option) any later version.      *
    *                                                                       *
    *************************************************************************
*/

#include "kopeteglobal.h"
#include "kopeteuiglobal.h"

#include <QtCore/QLatin1String>
#include <QtGui/QApplication>

#include <kdebug.h>
#include <klocale.h>
#include <kio/netaccess.h>
#include <kmimetype.h>
#include <kmessagebox.h>
#include <kprogressdialog.h>

#include <kstandarddirs.h>
#include <ktar.h>
#include <kzip.h>
#include <kmimetype.h>

namespace Kopete
{

namespace Global
{

class PropertiesPrivate
{
	public:
		ContactPropertyTmpl::Map mTemplates;
};

Properties *Properties::mSelf = 0L;

Properties *Properties::self()
{
	if(!mSelf)
	{
		//kDebug(14000) << k_funcinfo << endl;
		mSelf = new Properties();
	}
	return mSelf;
}

Properties::Properties()
{
	kDebug(14000) << k_funcinfo << endl;
	d = new PropertiesPrivate();
}

Properties::~Properties()
{
	kDebug(14000) << k_funcinfo << endl;
	delete d;
}

const ContactPropertyTmpl &Properties::tmpl(const QString &key) const
{
	if(d->mTemplates.contains(key))
	{
		/*kDebug(14000) << k_funcinfo <<
			"Found template for key = '" << key << "'" << endl;*/
		return d->mTemplates[key];
	}
	else
		return ContactPropertyTmpl::null;
}

bool Properties::registerTemplate(const QString &key,
	const ContactPropertyTmpl &tmpl)
{
	if(d->mTemplates.contains(key))
	{
		kDebug(14000) << k_funcinfo <<
			"Called for EXISTING key = '" << key << "'" << endl;
		return false;
	}
	else
	{
		d->mTemplates.insert(key, tmpl);
		return true;
	}
}

void Properties::unregisterTemplate(const QString &key)
{
	kDebug(14000) << k_funcinfo << "called for key: '" << key << "'" << endl;
	d->mTemplates.remove(key);
}

bool Properties::isRegistered(const QString &key)
{
	return d->mTemplates.contains(key);
}

const ContactPropertyTmpl &Properties::fullName() const
{
	return createProp(QLatin1String("FormattedName"),
		i18n("Full Name"));
}

const ContactPropertyTmpl &Properties::idleTime() const
{
	return createProp(QLatin1String("idleTime"),
		i18n("Idle Time"));
}

const ContactPropertyTmpl &Properties::onlineSince() const
{
	return createProp(QLatin1String("onlineSince"),
		i18n("Online Since"));
}

const ContactPropertyTmpl &Properties::lastSeen() const
{
	return createProp(QLatin1String("lastSeen"),
		i18n("Last Seen"), QString::null, true);
}

const ContactPropertyTmpl &Properties::statusMessage() const
{
	return createProp(QLatin1String("statusMessage"),
		i18n("Status Message"));
}

const ContactPropertyTmpl &Properties::firstName() const
{
	return createProp(QLatin1String("firstName"),
		i18n("First Name"), QString::null, true);
}

const ContactPropertyTmpl &Properties::lastName() const
{
	return createProp(QLatin1String("lastName"),
		i18n("Last Name"), QString::null, true);
}

const ContactPropertyTmpl &Properties::privatePhone() const
{
	return createProp(QLatin1String("privatePhoneNumber"),
		i18n("Private Phone"), QString::null, true);
}

const ContactPropertyTmpl &Properties::privateMobilePhone() const
{
	return createProp(QLatin1String("privateMobilePhoneNumber"),
		i18n("Private Mobile Phone"), QString::null, true);
}

const ContactPropertyTmpl &Properties::workPhone() const
{
	return createProp(QLatin1String("workPhoneNumber"),
		i18n("Work Phone"), QString::null, true);
}

const ContactPropertyTmpl &Properties::workMobilePhone() const
{
	return createProp(QLatin1String("workMobilePhoneNumber"),
		i18n("Work Mobile Phone"), QString::null, true);
}

const ContactPropertyTmpl &Properties::emailAddress() const
{
	return createProp(QLatin1String("emailAddress"),
		i18n("Email Address"), QLatin1String("mail"), true);
}

const ContactPropertyTmpl &Properties::nickName() const
{
	return createProp(QLatin1String("nickName"),
		i18n("Nick Name"), QString::null, true);
}

const ContactPropertyTmpl &Properties::photo() const
{
	return createProp(QLatin1String("photo"),
					  i18n("Photo"), QString::null, true);
}

const ContactPropertyTmpl &Properties::createProp(const QString &key,
	const QString &label, const QString &icon, bool persistent) const
{
	/*kDebug(14000) << k_funcinfo <<
		"key = " << key  << ", label = " << label << endl;*/

	if(!d->mTemplates.contains(key))
	{
/*		kDebug(14000) << k_funcinfo <<
			"CREATING NEW ContactPropertyTmpl WITH key = " << key  <<
			", label = " << label << ", persisten = " << persistent << endl;*/
		d->mTemplates.insert(key,  ContactPropertyTmpl(key, label, icon, persistent ? ContactPropertyTmpl::PersistentProperty : ContactPropertyTmpl::NoProperty));
	}
	return tmpl(key);
}

const ContactPropertyTmpl::Map &Properties::templateMap() const
{
	return d->mTemplates;
}

// -----------------------------------------------------------------------------

void installEmoticonTheme(const QString &archiveName)
{
	QStringList foundThemes;
	KArchiveEntry *currentEntry = 0L;
	KArchiveDirectory* currentDir = 0L;
	KProgressDialog *progressDlg = 0L;
	KArchive *archive = 0L;

	QString localThemesDir(KStandardDirs::locateLocal("emoticons", QString::null) );

	if(localThemesDir.isEmpty())
	{
		KMessageBox::queuedMessageBox(Kopete::UI::Global::mainWidget(),
			KMessageBox::Error, i18n("Could not find suitable place " \
			"to install emoticon themes into."));
		return;
	}

	progressDlg = new KProgressDialog(0,
	 	i18n("Installing Emoticon Themes..."));
	progressDlg->setModal(true);
	progressDlg->progressBar()->setMaximum(foundThemes.count());
	progressDlg->show();
	qApp->processEvents();

	QString currentBundleMimeType = KMimeType::findByPath(archiveName, 0, false)->name();
	if( currentBundleMimeType == QLatin1String("application/zip") ||
        currentBundleMimeType == QLatin1String("application/x-zip") ||
        currentBundleMimeType ==  QLatin1String("application/x-zip-compressed"))
		archive = new KZip(archiveName);
	else if( currentBundleMimeType == QLatin1String("application/x-compressed-tar") ||
				currentBundleMimeType == QLatin1String("application/x-bzip-compressed-tar") ||
				currentBundleMimeType == QLatin1String("application/x-gzip") ||
				currentBundleMimeType == QLatin1String("application/x-bzip") )
		archive = new KTar(archiveName);
	else if(archiveName.endsWith(QLatin1String("jisp")) || archiveName.endsWith(QLatin1String("zip")) )
		archive = new KZip(archiveName);
	else
		archive = new KTar(archiveName);

	if ( !archive || !archive->open(QIODevice::ReadOnly) )
	{
		KMessageBox::queuedMessageBox(Kopete::UI::Global::mainWidget(),
			KMessageBox::Error,
			i18n("Could not open \"%1\" for unpacking.", archiveName));
		delete archive;
		delete progressDlg;
		return;
	}

	const KArchiveDirectory* rootDir = archive->directory();

	// iterate all the dirs looking for an emoticons.xml file
	QStringList entries = rootDir->entries();
	for (QStringList::Iterator it = entries.begin(); it != entries.end(); ++it)
	{
		currentEntry = const_cast<KArchiveEntry*>(rootDir->entry(*it));
		if (currentEntry->isDirectory())
		{
			currentDir = dynamic_cast<KArchiveDirectory*>( currentEntry );
			if (currentDir && ( currentDir->entry(QLatin1String("emoticons.xml")) != NULL ||
						 		currentDir->entry(QLatin1String("icondef.xml")) != NULL ) )
				foundThemes.append(currentDir->name());
		}
	}

	if (foundThemes.isEmpty())
	{
		KMessageBox::queuedMessageBox(Kopete::UI::Global::mainWidget(),
			KMessageBox::Error, i18n("<qt>The file \"%1\" is not a valid" \
				" emoticon theme archive.</qt>", archiveName));
		archive->close();
		delete archive;
		delete progressDlg;
		return;
	}

	for (int themeIndex = 0; themeIndex < foundThemes.size(); ++themeIndex)
	{
		const QString &theme = foundThemes[themeIndex];

		progressDlg->setLabelText(
			i18n("<qt>Installing %1 emoticon theme</qt>",
			theme));
		progressDlg->progressBar()->setValue(themeIndex);
		progressDlg->resize(progressDlg->sizeHint());
		qApp->processEvents();

		if (progressDlg->wasCancelled())
			break;

		currentEntry = const_cast<KArchiveEntry *>(rootDir->entry(theme));
		if (currentEntry == 0)
		{
			kDebug(14010) << k_funcinfo << "couldn't get next archive entry" << endl;
			continue;
		}

		if(currentEntry->isDirectory())
		{
			currentDir = dynamic_cast<KArchiveDirectory*>(currentEntry);
			if (currentDir == 0)
			{
				kDebug(14010) << k_funcinfo <<
					"couldn't cast archive entry to KArchiveDirectory" << endl;
				continue;
			}
			currentDir->copyTo(localThemesDir + theme);
		}
	}

	archive->close();
	delete archive;

	// check if all steps were done, if there are skipped ones then we didn't
	// succeed copying all dirs from the tarball
	if (progressDlg->progressBar()->maximum() > progressDlg->progressBar()->value())
	{
		KMessageBox::queuedMessageBox(Kopete::UI::Global::mainWidget(),
			KMessageBox::Error,
			i18n("<qt>A problem occurred during the installation process. "
			"However, some of the emoticon themes in the archive may have been "
			"installed.</qt>"));
	}

	delete progressDlg;
}

} // END namespace Global

} // END namespace Kopete

// vim: set noet ts=4 sts=4 sw=4:
<|endoftext|>