<commit_before>/*
 * PrimeSieveGUI.cpp -- This file is part of primesieve
 *
 * Copyright (C) 2011 Kim Walisch, <kim.walisch@gmail.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
 */

#include "PrimeSieveGUI.h"
#include "ui_PrimeSieveGUI.h"
#include "PrimeSieveProcess.h"
#include "../soe/ParallelPrimeSieve.h"
#include "../expr/ExpressionParser.h"

#include <QtGlobal>
#include <QCoreApplication>
#include <QByteArray>
#include <QTextStream>
#include <QFile>
#include <QSize>
#include <QMessageBox>
#include <QTextCursor>
#include <stdexcept>

PrimeSieveGUI::PrimeSieveGUI(QWidget *parent) :
  QMainWindow(parent), ui(new Ui::PrimeSieveGUI), validator_(0),
  primeSieveProcess_(0), saveAct_(0), quitAct_(0), aboutAct_(0),
  alignmentGroup_(0) {
  ui->setupUi(this);
  primeText_.push_back("Prime numbers");
  primeText_.push_back("Twin primes");
  primeText_.push_back("Prime triplets");
  primeText_.push_back("Prime quadruplets");
  primeText_.push_back("Prime quintuplets");
  primeText_.push_back("Prime sextuplets");
  primeText_.push_back("Prime septuplets");
  this->initGUI();
  this->initConnections();
}

PrimeSieveGUI::~PrimeSieveGUI() {
  this->cleanUp();
  delete validator_;
  delete saveAct_;
  delete quitAct_;
  delete aboutAct_;
  delete alignmentGroup_;
  for (; !countAct_.isEmpty(); countAct_.pop_back())
    delete countAct_.back();
  for (; !printAct_.isEmpty(); printAct_.pop_back())
    delete printAct_.back();
  // Qt code
  delete ui;
}

void PrimeSieveGUI::changeEvent(QEvent *e) {
  QMainWindow::changeEvent(e);
  switch (e->type()) {
  case QEvent::LanguageChange:
    ui->retranslateUi(this);
    break;
  default:
    break;
  }
}

void PrimeSieveGUI::initGUI() {
  this->setWindowTitle(APPLICATION_NAME + " " + APPLICATION_VERSION);
  this->createMenu(primeText_);

  // fill the sieveSizeComboBox with power of 2 values <= "8192 KB"
  for (int i = MINIMUM_SIEVE_SIZE; i <= MAXIMUM_SIEVE_SIZE; i *= 2)
    ui->sieveSizeComboBox->addItem(QString::number(i) + " KB");
  this->setTo(ui->sieveSizeComboBox, DEFAULT_SIEVE_SIZE);

  // fill the threadsComboBox with power of 2 values <= maxThreads_
  maxThreads_ = ParallelPrimeSieve::getMaxThreads();
  for (int i = 1; i < maxThreads_; i *= 2)
    ui->threadsComboBox->addItem(QString::number(i));
  ui->threadsComboBox->addItem(QString::number(maxThreads_));
  this->setTo(ui->threadsComboBox, "1");

  // set an ideal ComboBox width
  int width = ui->sieveSizeComboBox->minimumSizeHint().width();
  ui->sieveSizeComboBox->setFixedWidth(width);
  ui->threadsComboBox->setFixedWidth(width);

  // set a nice GUI size
  QSize size = this->sizeHint();
  size.setWidth(this->minimumSizeHint().width());
#if defined(Q_OS_WIN)
  size.setHeight(size.height() - size.height() / 10);
#endif
  this->resize(size);

  // limit input for arithmetic expressions
  QRegExp rx("[0-9\\+\\-\\*\\/\\%\\^\\(\\)\\e\\E]*");
  validator_ = new QRegExpValidator(rx, this);
  ui->lowerBoundLineEdit->setValidator(validator_);
  ui->upperBoundLineEdit->setValidator(validator_);
}

void PrimeSieveGUI::initConnections() {
  connect(&progressBarTimer_,     SIGNAL(timeout()),                    this, SLOT(advanceProgressBar()));
  connect(ui->lowerBoundLineEdit, SIGNAL(textChanged(const QString &)), this, SLOT(autoSetThreads()));
  connect(ui->upperBoundLineEdit, SIGNAL(textChanged(const QString &)), this, SLOT(autoSetThreads()));
  connect(ui->autoSetCheckBox,    SIGNAL(toggled(bool)),                this, SLOT(autoSetThreads()));
  connect(saveAct_,               SIGNAL(triggered()),                  this, SLOT(saveToFile()));
  connect(quitAct_,               SIGNAL(triggered()),                  qApp, SLOT(closeAllWindows()));
  connect(alignmentGroup_,        SIGNAL(triggered(QAction*)),          this, SLOT(printMenuClicked(QAction*)));
  connect(aboutAct_,              SIGNAL(triggered()),                  this, SLOT(showAboutDialog()));
}

/**
 * Get the sieve size in kilobytes from the sieveSizeComboBox.
 * @post sieveSize >= 1 && sieveSize <= 8192.
 */
int PrimeSieveGUI::getSieveSize() {
  QString sieveSize(ui->sieveSizeComboBox->currentText());
  // remove " KB"
  sieveSize.chop(3);
  return sieveSize.toInt();
}

/**
 * Get the number of threads from the threadsComboBox.
 */
int PrimeSieveGUI::getThreads() {
  return ui->threadsComboBox->currentText().toInt();
}

quint64 PrimeSieveGUI::getNumber(const QString& str) {
  if (str.isEmpty())
    throw std::invalid_argument("Missing number input.");

  ExpressionParser<quint64> parser;
  if (!parser.eval(str.toAscii().data()))
    throw std::invalid_argument(parser.getErrorMessage());

  int digits = str.count(QRegExp("[0-9]"));
  if (parser.getResult() >= UPPER_BOUND_LIMIT || (
      digits == str.size() && (
      digits >  UPPER_BOUND_STR.size() || (
      digits == UPPER_BOUND_STR.size() &&
      str    >= UPPER_BOUND_STR))))
    throw std::invalid_argument("Please use positive integers < (2^64-1)-(2^32-1)*10.");

  return parser.getResult();
}

void PrimeSieveGUI::setTo(QComboBox* comboBox, const QString& text) {
  comboBox->setCurrentIndex(comboBox->findText(text));
}

/**
 * If "Auto set" is enabled set an ideal number of threads for the
 * current lower bound, upper bound in the threadsComboBox.
 */
void PrimeSieveGUI::autoSetThreads() {
  if (ui->autoSetCheckBox->isEnabled() && ui->autoSetCheckBox->isChecked()) {
    try {
      quint64 lowerBound = this->getNumber(ui->lowerBoundLineEdit->text());
      quint64 upperBound = this->getNumber(ui->upperBoundLineEdit->text());
      ParallelPrimeSieve pps;
      pps.setStartNumber(lowerBound);
      pps.setStopNumber(upperBound);
      int idealNumThreads = pps.getNumThreads();
      if (idealNumThreads < maxThreads_) {
        // floor to the next power of 2 value
        int p = 1;
        for (; p <= idealNumThreads; p *= 2)
          ;
        idealNumThreads = p / 2;
      }
      this->setTo(ui->threadsComboBox, QString::number(idealNumThreads));
    } catch (...) {
      this->setTo(ui->threadsComboBox, "1");
    }
  }
}

/**
 * The user has chosen a custom number of threads, disable "Auto set".
 */
void PrimeSieveGUI::on_threadsComboBox_activated() {
  ui->autoSetCheckBox->setChecked(false);
}

/**
 * Start sieving primes.
 */
void PrimeSieveGUI::on_sieveButton_clicked() {
  // invert buttons, reset upon cleanUp()
  ui->sieveButton->setDisabled(true);
  ui->cancelButton->setEnabled(true);
  try {
    flags_ = this->getMenuSettings();
    if ((flags_ & (ParallelPrimeSieve::COUNT_FLAGS | ParallelPrimeSieve::PRINT_FLAGS)) == 0)
      throw std::invalid_argument("Nothing to do, no count or print options selected.");

    quint64 lowerBound = this->getNumber(ui->lowerBoundLineEdit->text());
    quint64 upperBound = this->getNumber(ui->upperBoundLineEdit->text());
    if (lowerBound > upperBound)
      throw std::invalid_argument("The lower bound must be <= upper bound.");

    // reset the GUI widgets
    ui->progressBar->setValue(ui->progressBar->minimum());
    ui->textEdit->clear();
    progressBarTimer_.start(25);

    // start a new process for sieving (avoids cancel
    // trouble with multiple threads)
    primeSieveProcess_ = new PrimeSieveProcess(this);
    if (flags_ & ParallelPrimeSieve::PRINT_FLAGS)
      connect(primeSieveProcess_, SIGNAL(readyReadStandardOutput()),
          this, SLOT(printProcessOutput()));
    connect(primeSieveProcess_, SIGNAL(finished(int, QProcess::ExitStatus)),
        this, SLOT(processFinished(int, QProcess::ExitStatus)));
    primeSieveProcess_->start(lowerBound, upperBound, this->getSieveSize(),
        flags_, this->getThreads());

  } catch (std::invalid_argument& ex) {
    this->cleanUp();
    QMessageBox::warning(this, APPLICATION_NAME, ex.what());
  } catch (std::exception& ex) {
    this->cleanUp();
    QMessageBox::critical(this, APPLICATION_NAME, ex.what());
  }
}

void PrimeSieveGUI::advanceProgressBar() {
  int permil = static_cast<int> (primeSieveProcess_->getStatus() * 10.0);
  ui->progressBar->setValue(permil);
}

/**
 * Redirects the standard output (prime numbers or prime k-tuplets) of
 * the primeSieveProcess_ to the TextEdit.
 */
void PrimeSieveGUI::printProcessOutput() {
  QByteArray buffer;
  buffer.reserve(PRINT_BUFFER_SIZE + 256);
  while (ui->cancelButton->isEnabled() && primeSieveProcess_->canReadLine()) {
    buffer.clear();
    while (primeSieveProcess_->canReadLine() && buffer.size() < PRINT_BUFFER_SIZE)
      buffer.append(primeSieveProcess_->readLine(256));
    // remove "\r\n" or '\n', '\r' at the back
    while (buffer.endsWith('\n') ||
           buffer.endsWith('\r'))
      buffer.chop(1);
    if (!buffer.isEmpty())
      ui->textEdit->appendPlainText(buffer);
/// Keep the GUI responsive.
/// @warning QApplication::processEvents() must not be used on
///          operating systems that use signal recursion (like Linux
///          X11) otherwise the stack will explode!
#if defined(Q_OS_WIN) || defined(Q_OS_MAC)
    QApplication::processEvents();
#else
    ui->textEdit->repaint();
#endif
  }
}

/**
 * Is executed when the primeSieveProcess_ finishes, checks for
 * process errors and calls this->printResults().
 */
void PrimeSieveGUI::processFinished(int exitCode,
    QProcess::ExitStatus exitStatus) {
  // the process did not exit normally, i.e. threw and exception
  if (exitCode != 0) {
    // Qt uses '/' internally, even for Windows
    QString path = QCoreApplication::applicationDirPath() + "/" + APPLICATION_NAME + "_error.txt";
    QFile error_log(path);
    if (error_log.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text)) {
      QTextStream out(&error_log);
      out << primeSieveProcess_->readAllStandardError();
      error_log.close();
    }
    this->cleanUp();
    QMessageBox::critical(this, APPLICATION_NAME,
        "The PrimeSieveProcess reported an error, sieving has been aborted. Please contact the developer.");
  }
  // the PrimeSieveProcess has been interrupted by a signal (SIGTERM,
  // SIGKILL, ...) or a segmentation fault
  else if (exitStatus == QProcess::CrashExit) {
    this->cleanUp();
    QMessageBox::critical(this, APPLICATION_NAME, "The PrimeSieveProcess crashed, sieving has been aborted.");
  }
  // the PrimeSieveProcess has finished correctly
  else {
    ui->progressBar->setValue(ui->progressBar->maximum());
    // print results if not canceled lately
    if (ui->cancelButton->isEnabled())
      this->printResults();
    this->cleanUp();
  }
}

/**
 * Print the sieving results.
 */
void PrimeSieveGUI::printResults() {
  if (!ui->textEdit->toPlainText().isEmpty())
    ui->textEdit->appendPlainText("");

  // hack to get the count results aligned using tabs
  QString maxSizeText;
  for (int i = 0; i < ParallelPrimeSieve::COUNTS_SIZE; i++) {
    if ((flags_ & (ParallelPrimeSieve::COUNT_PRIMES << i)) &&
        maxSizeText.size() < primeText_[i].size())
      maxSizeText = primeText_[i];
  }
  ui->textEdit->insertPlainText(maxSizeText + ": ");
  int maxWidth = ui->textEdit->cursorRect().left();
  ui->textEdit->moveCursor(QTextCursor::StartOfLine, QTextCursor::KeepAnchor);
  ui->textEdit->textCursor().removeSelectedText();
  ui->textEdit->setTabStopWidth(maxWidth);

  // print prime counts & time elapsed
  for (int i = 0; i < ParallelPrimeSieve::COUNTS_SIZE; i++) {
    if (flags_ & (ParallelPrimeSieve::COUNT_PRIMES << i))
      ui->textEdit->appendPlainText(primeText_[i] + ":\t" + QString::number(primeSieveProcess_->getCounts(i)));
  }
  if (flags_ & ParallelPrimeSieve::COUNT_KTUPLETS)
    ui->textEdit->appendPlainText("");
  QString time("Elapsed time:\t" + QString::number(primeSieveProcess_->getTimeElapsed(), 'f', 2) + " sec");
  ui->textEdit->appendPlainText(time);
}

/**
 * Cancel sieving.
 */
void PrimeSieveGUI::on_cancelButton_clicked() {
  ui->cancelButton->setDisabled(true);
  ui->progressBar->setValue(0);
  // too late to abort
  if ((flags_ & ParallelPrimeSieve::PRINT_FLAGS) && primeSieveProcess_->isFinished())
    return;
  this->cleanUp();
}

/**
 * Clean up after sieving is finished or canceled (abort the
 * PrimeSieveProcess if still running).
 */
void PrimeSieveGUI::cleanUp() {
  progressBarTimer_.stop();
  if (primeSieveProcess_ != 0)
    delete primeSieveProcess_;
  primeSieveProcess_ = 0;
  // invert buttons
  ui->cancelButton->setDisabled(true);
  ui->sieveButton->setEnabled(true);
  // force repainting widgets
  this->repaint();
}
<commit_msg>updated error message<commit_after>/*
 * PrimeSieveGUI.cpp -- This file is part of primesieve
 *
 * Copyright (C) 2011 Kim Walisch, <kim.walisch@gmail.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
 */

#include "PrimeSieveGUI.h"
#include "ui_PrimeSieveGUI.h"
#include "PrimeSieveProcess.h"
#include "../soe/ParallelPrimeSieve.h"
#include "../expr/ExpressionParser.h"

#include <QtGlobal>
#include <QCoreApplication>
#include <QByteArray>
#include <QTextStream>
#include <QFile>
#include <QSize>
#include <QMessageBox>
#include <QTextCursor>
#include <stdexcept>

PrimeSieveGUI::PrimeSieveGUI(QWidget *parent) :
  QMainWindow(parent), ui(new Ui::PrimeSieveGUI), validator_(0),
  primeSieveProcess_(0), saveAct_(0), quitAct_(0), aboutAct_(0),
  alignmentGroup_(0) {
  ui->setupUi(this);
  primeText_.push_back("Prime numbers");
  primeText_.push_back("Twin primes");
  primeText_.push_back("Prime triplets");
  primeText_.push_back("Prime quadruplets");
  primeText_.push_back("Prime quintuplets");
  primeText_.push_back("Prime sextuplets");
  primeText_.push_back("Prime septuplets");
  this->initGUI();
  this->initConnections();
}

PrimeSieveGUI::~PrimeSieveGUI() {
  this->cleanUp();
  delete validator_;
  delete saveAct_;
  delete quitAct_;
  delete aboutAct_;
  delete alignmentGroup_;
  for (; !countAct_.isEmpty(); countAct_.pop_back())
    delete countAct_.back();
  for (; !printAct_.isEmpty(); printAct_.pop_back())
    delete printAct_.back();
  // Qt code
  delete ui;
}

void PrimeSieveGUI::changeEvent(QEvent *e) {
  QMainWindow::changeEvent(e);
  switch (e->type()) {
  case QEvent::LanguageChange:
    ui->retranslateUi(this);
    break;
  default:
    break;
  }
}

void PrimeSieveGUI::initGUI() {
  this->setWindowTitle(APPLICATION_NAME + " " + APPLICATION_VERSION);
  this->createMenu(primeText_);

  // fill the sieveSizeComboBox with power of 2 values <= "8192 KB"
  for (int i = MINIMUM_SIEVE_SIZE; i <= MAXIMUM_SIEVE_SIZE; i *= 2)
    ui->sieveSizeComboBox->addItem(QString::number(i) + " KB");
  this->setTo(ui->sieveSizeComboBox, DEFAULT_SIEVE_SIZE);

  // fill the threadsComboBox with power of 2 values <= maxThreads_
  maxThreads_ = ParallelPrimeSieve::getMaxThreads();
  for (int i = 1; i < maxThreads_; i *= 2)
    ui->threadsComboBox->addItem(QString::number(i));
  ui->threadsComboBox->addItem(QString::number(maxThreads_));
  this->setTo(ui->threadsComboBox, "1");

  // set an ideal ComboBox width
  int width = ui->sieveSizeComboBox->minimumSizeHint().width();
  ui->sieveSizeComboBox->setFixedWidth(width);
  ui->threadsComboBox->setFixedWidth(width);

  // set a nice GUI size
  QSize size = this->sizeHint();
  size.setWidth(this->minimumSizeHint().width());
#if defined(Q_OS_WIN)
  size.setHeight(size.height() - size.height() / 10);
#endif
  this->resize(size);

  // limit input for arithmetic expressions
  QRegExp rx("[0-9\\+\\-\\*\\/\\%\\^\\(\\)\\e\\E]*");
  validator_ = new QRegExpValidator(rx, this);
  ui->lowerBoundLineEdit->setValidator(validator_);
  ui->upperBoundLineEdit->setValidator(validator_);
}

void PrimeSieveGUI::initConnections() {
  connect(&progressBarTimer_,     SIGNAL(timeout()),                    this, SLOT(advanceProgressBar()));
  connect(ui->lowerBoundLineEdit, SIGNAL(textChanged(const QString &)), this, SLOT(autoSetThreads()));
  connect(ui->upperBoundLineEdit, SIGNAL(textChanged(const QString &)), this, SLOT(autoSetThreads()));
  connect(ui->autoSetCheckBox,    SIGNAL(toggled(bool)),                this, SLOT(autoSetThreads()));
  connect(saveAct_,               SIGNAL(triggered()),                  this, SLOT(saveToFile()));
  connect(quitAct_,               SIGNAL(triggered()),                  qApp, SLOT(closeAllWindows()));
  connect(alignmentGroup_,        SIGNAL(triggered(QAction*)),          this, SLOT(printMenuClicked(QAction*)));
  connect(aboutAct_,              SIGNAL(triggered()),                  this, SLOT(showAboutDialog()));
}

/**
 * Get the sieve size in kilobytes from the sieveSizeComboBox.
 * @post sieveSize >= 1 && sieveSize <= 8192.
 */
int PrimeSieveGUI::getSieveSize() {
  QString sieveSize(ui->sieveSizeComboBox->currentText());
  // remove " KB"
  sieveSize.chop(3);
  return sieveSize.toInt();
}

/**
 * Get the number of threads from the threadsComboBox.
 */
int PrimeSieveGUI::getThreads() {
  return ui->threadsComboBox->currentText().toInt();
}

quint64 PrimeSieveGUI::getNumber(const QString& str) {
  if (str.isEmpty())
    throw std::invalid_argument("Missing number input.");

  ExpressionParser<quint64> parser;
  if (!parser.eval(str.toAscii().data()))
    throw std::invalid_argument(parser.getErrorMessage());

  int digits = str.count(QRegExp("[0-9]"));
  if (parser.getResult() >= UPPER_BOUND_LIMIT || (
      digits == str.size() && (
      digits >  UPPER_BOUND_STR.size() || (
      digits == UPPER_BOUND_STR.size() &&
      str    >= UPPER_BOUND_STR))))
    throw std::invalid_argument("Please use positive integers < (2^64-1)-(2^32-1)*10.");

  return parser.getResult();
}

void PrimeSieveGUI::setTo(QComboBox* comboBox, const QString& text) {
  comboBox->setCurrentIndex(comboBox->findText(text));
}

/**
 * If "Auto set" is enabled set an ideal number of threads for the
 * current lower bound, upper bound in the threadsComboBox.
 */
void PrimeSieveGUI::autoSetThreads() {
  if (ui->autoSetCheckBox->isEnabled() && ui->autoSetCheckBox->isChecked()) {
    try {
      quint64 lowerBound = this->getNumber(ui->lowerBoundLineEdit->text());
      quint64 upperBound = this->getNumber(ui->upperBoundLineEdit->text());
      ParallelPrimeSieve pps;
      pps.setStartNumber(lowerBound);
      pps.setStopNumber(upperBound);
      int idealNumThreads = pps.getNumThreads();
      if (idealNumThreads < maxThreads_) {
        // floor to the next power of 2 value
        int p = 1;
        for (; p <= idealNumThreads; p *= 2)
          ;
        idealNumThreads = p / 2;
      }
      this->setTo(ui->threadsComboBox, QString::number(idealNumThreads));
    } catch (...) {
      this->setTo(ui->threadsComboBox, "1");
    }
  }
}

/**
 * The user has chosen a custom number of threads, disable "Auto set".
 */
void PrimeSieveGUI::on_threadsComboBox_activated() {
  ui->autoSetCheckBox->setChecked(false);
}

/**
 * Start sieving primes.
 */
void PrimeSieveGUI::on_sieveButton_clicked() {
  // invert buttons, reset upon cleanUp()
  ui->sieveButton->setDisabled(true);
  ui->cancelButton->setEnabled(true);
  try {
    flags_ = this->getMenuSettings();
    if ((flags_ & (ParallelPrimeSieve::COUNT_FLAGS | ParallelPrimeSieve::PRINT_FLAGS)) == 0)
      throw std::invalid_argument("Nothing to do, no count or print options selected.");

    quint64 lowerBound = this->getNumber(ui->lowerBoundLineEdit->text());
    quint64 upperBound = this->getNumber(ui->upperBoundLineEdit->text());
    if (lowerBound > upperBound)
      throw std::invalid_argument("The lower bound must be <= upper bound.");

    // reset the GUI widgets
    ui->progressBar->setValue(ui->progressBar->minimum());
    ui->textEdit->clear();
    progressBarTimer_.start(25);

    // start a new process for sieving (avoids cancel
    // trouble with multiple threads)
    primeSieveProcess_ = new PrimeSieveProcess(this);
    if (flags_ & ParallelPrimeSieve::PRINT_FLAGS)
      connect(primeSieveProcess_, SIGNAL(readyReadStandardOutput()),
          this, SLOT(printProcessOutput()));
    connect(primeSieveProcess_, SIGNAL(finished(int, QProcess::ExitStatus)),
        this, SLOT(processFinished(int, QProcess::ExitStatus)));
    primeSieveProcess_->start(lowerBound, upperBound, this->getSieveSize(),
        flags_, this->getThreads());

  } catch (std::invalid_argument& ex) {
    this->cleanUp();
    QMessageBox::warning(this, APPLICATION_NAME, ex.what());
  } catch (std::exception& ex) {
    this->cleanUp();
    QMessageBox::critical(this, APPLICATION_NAME, ex.what());
  }
}

void PrimeSieveGUI::advanceProgressBar() {
  int permil = static_cast<int> (primeSieveProcess_->getStatus() * 10.0);
  ui->progressBar->setValue(permil);
}

/**
 * Redirects the standard output (prime numbers or prime k-tuplets) of
 * the primeSieveProcess_ to the TextEdit.
 */
void PrimeSieveGUI::printProcessOutput() {
  QByteArray buffer;
  buffer.reserve(PRINT_BUFFER_SIZE + 256);
  while (ui->cancelButton->isEnabled() && primeSieveProcess_->canReadLine()) {
    buffer.clear();
    while (primeSieveProcess_->canReadLine() && buffer.size() < PRINT_BUFFER_SIZE)
      buffer.append(primeSieveProcess_->readLine(256));
    // remove "\r\n" or '\n', '\r' at the back
    while (buffer.endsWith('\n') ||
           buffer.endsWith('\r'))
      buffer.chop(1);
    if (!buffer.isEmpty())
      ui->textEdit->appendPlainText(buffer);
/// Keep the GUI responsive.
/// @warning QApplication::processEvents() must not be used on
///          operating systems that use signal recursion (like Linux
///          X11) otherwise the stack will explode!
#if defined(Q_OS_WIN) || defined(Q_OS_MAC)
    QApplication::processEvents();
#else
    ui->textEdit->repaint();
#endif
  }
}

/**
 * Is executed when the primeSieveProcess_ finishes, checks for
 * process errors and calls this->printResults().
 */
void PrimeSieveGUI::processFinished(int exitCode,
    QProcess::ExitStatus exitStatus) {
  // the process did not exit normally, i.e. threw and exception
  if (exitCode != 0) {
    // Qt uses '/' internally, even for Windows
    QString path = QCoreApplication::applicationDirPath() + "/" + APPLICATION_NAME + "_error.txt";
    QFile error_log(path);
    if (error_log.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text)) {
      QTextStream out(&error_log);
      out << primeSieveProcess_->readAllStandardError();
      error_log.close();
    }
    this->cleanUp();
    QMessageBox::critical(this, APPLICATION_NAME,
        "The PrimeSieveProcess reported an error (see primesieve_error.txt), sieving has been aborted.");
  }
  // the PrimeSieveProcess has been interrupted by a signal (SIGTERM,
  // SIGKILL, ...) or a segmentation fault
  else if (exitStatus == QProcess::CrashExit) {
    this->cleanUp();
    QMessageBox::critical(this, APPLICATION_NAME, "The PrimeSieveProcess crashed, sieving has been aborted.");
  }
  // the PrimeSieveProcess has finished correctly
  else {
    ui->progressBar->setValue(ui->progressBar->maximum());
    // print results if not canceled lately
    if (ui->cancelButton->isEnabled())
      this->printResults();
    this->cleanUp();
  }
}

/**
 * Print the sieving results.
 */
void PrimeSieveGUI::printResults() {
  if (!ui->textEdit->toPlainText().isEmpty())
    ui->textEdit->appendPlainText("");

  // hack to get the count results aligned using tabs
  QString maxSizeText;
  for (int i = 0; i < ParallelPrimeSieve::COUNTS_SIZE; i++) {
    if ((flags_ & (ParallelPrimeSieve::COUNT_PRIMES << i)) &&
        maxSizeText.size() < primeText_[i].size())
      maxSizeText = primeText_[i];
  }
  ui->textEdit->insertPlainText(maxSizeText + ": ");
  int maxWidth = ui->textEdit->cursorRect().left();
  ui->textEdit->moveCursor(QTextCursor::StartOfLine, QTextCursor::KeepAnchor);
  ui->textEdit->textCursor().removeSelectedText();
  ui->textEdit->setTabStopWidth(maxWidth);

  // print prime counts & time elapsed
  for (int i = 0; i < ParallelPrimeSieve::COUNTS_SIZE; i++) {
    if (flags_ & (ParallelPrimeSieve::COUNT_PRIMES << i))
      ui->textEdit->appendPlainText(primeText_[i] + ":\t" + QString::number(primeSieveProcess_->getCounts(i)));
  }
  if (flags_ & ParallelPrimeSieve::COUNT_KTUPLETS)
    ui->textEdit->appendPlainText("");
  QString time("Elapsed time:\t" + QString::number(primeSieveProcess_->getTimeElapsed(), 'f', 2) + " sec");
  ui->textEdit->appendPlainText(time);
}

/**
 * Cancel sieving.
 */
void PrimeSieveGUI::on_cancelButton_clicked() {
  ui->cancelButton->setDisabled(true);
  ui->progressBar->setValue(0);
  // too late to abort
  if ((flags_ & ParallelPrimeSieve::PRINT_FLAGS) && primeSieveProcess_->isFinished())
    return;
  this->cleanUp();
}

/**
 * Clean up after sieving is finished or canceled (abort the
 * PrimeSieveProcess if still running).
 */
void PrimeSieveGUI::cleanUp() {
  progressBarTimer_.stop();
  if (primeSieveProcess_ != 0)
    delete primeSieveProcess_;
  primeSieveProcess_ = 0;
  // invert buttons
  ui->cancelButton->setDisabled(true);
  ui->sieveButton->setEnabled(true);
  // force repainting widgets
  this->repaint();
}
<|endoftext|>


<commit_before>#include "ioHandler.h"
#include <exception>
#include <cerrno>

void writer_helper(ReadBase *r, std::shared_ptr<OutputWriter> pe, std::shared_ptr<OutputWriter> se, bool stranded, bool no_orphans ) { //class writer
    PairedEndRead *per = dynamic_cast<PairedEndRead*>(r);
    if (per) {
        Read &one = per->non_const_read_one();
        Read &two = per->non_const_read_two();

        if (!one.getDiscard() && !two.getDiscard()) {
            pe->write(*per);
        } else if (!one.getDiscard() && !no_orphans) { // Will never be RC
            se->write_read(one, false);
        } else if (!two.getDiscard() && !no_orphans) { // if stranded RC
            se->write_read((per->get_read_two()), stranded);
        } else {

        }
    } else {
        SingleEndRead *ser = dynamic_cast<SingleEndRead*>(r);
        if (!ser) {
            throw std::runtime_error("Unknown read found");
        }
        if (! (ser->non_const_read_one()).getDiscard() ) {
            se->write(*ser);
        } else {

        }
    }
}

void skip_lr(std::istream *input) {
    while(input and input->good() and (input->peek() == '\n' || input->peek() == '\r')) {
        input->get();
    }
}

void  __attribute__ ((noreturn)) throw_error(const std::string& filename) {
    throw std::runtime_error(filename + ": " +  std::strerror( errno ));
}

/*
takes a delimited string and converts to fasta format for reading in
*/
std::string string2fasta(std::string seqstring, const char delim) {
  std::string newfa;
  int index=1;
  std::stringstream ss( seqstring );

  while( ss.good() )
  {
      std::string substr;
      getline( ss, substr, delim );
      newfa.append(">seq");
      newfa.append( std::to_string(index) );
      newfa.append( "\n" );
      newfa.append( substr );
      newfa.append( "\n" );
      index++;
  }
  return(newfa);
}

int check_open_r(const std::string& filename) {
    FILE* f = NULL;

    bf::path p(filename);
    if (!bf::exists(p)) {
        throw std::runtime_error("File " + filename + " was not found.");
    }

    if (p.extension() == ".gz") {
        f = popen(("gunzip -c '" + filename + "'").c_str(), "r");
    } else {
        f = fopen(filename.c_str(), "r");
    }

    if (!f) {
        throw_error(filename);
    }
    return fileno(f);
}

int check_exists(const std::string& filename, bool force, bool gzip, bool std_out) {
    FILE* f = NULL;

    if (std_out) {
        return fileno(stdout);
    }
    std::string fname = gzip ? filename + ".gz" : filename ;

    bf::path p(fname);

    if (force || !bf::exists(p)) {
        if (gzip) {
            f = popen(("gzip > '" + fname + "'").c_str(), "w");
        } else {
            f = fopen(fname.c_str(), "w");
        }
        if (!f) {
            throw_error(fname);
        }
        return fileno(f);
    } else {
        throw std::runtime_error("File " + fname + " all ready exists. Please use -F or delete it\n");
    }
}

Read InputFastq::load_read(std::istream *input) {
    while(std::getline(*input, id) && id.size() < 1) {
    }
    if (id.size() < 1) {
        throw std::runtime_error("invalid id line empty");
    }
    if (id[0] != '@') {
        throw std::runtime_error("id line did not begin with @");
    }
    std::getline(*input, seq);
    if (seq.size() < 1) {
        throw std::runtime_error("invalid seq line empty");
    }
    std::getline(*input, id2);
    if (id2.size() < 1) {
        throw std::runtime_error("invalid id2 line empty");
    }
    if (id2[0] != '+') {
        throw std::runtime_error("invalid id2 line did not begin with +");
    }
    std::getline(*input, qual);
    if (qual.size() != seq.size()) {
        throw std::runtime_error("qual string not the same length as sequence");
    }

    // ignore extra lines at end of file
    while(input->good() and (input->peek() == '\n' || input->peek() == '\r')) {
        input->get();
    }
    return Read(seq, qual, id.substr(1));
}

Read InputFasta::load_read(std::istream *input) {
    while(std::getline(*input, id) && id.size() < 1) {
    }
    if (id.size() < 1) {
        throw std::runtime_error("invalid id - line empty");
    }
    if (id[0] != '>') {
        throw std::runtime_error("id line did not begin with >");
    }
    seq = "";
    while (std::getline(*input, tmpSeq)) {
        seq += tmpSeq;
        if (input->peek() == '>') {
            break;
        }
    }
    if (seq.size() < 1) {
        throw std::runtime_error("no sequence");
    }
    while(input->good() and (input->peek() == '\n' || input->peek() == '\r')) {
        input->get();
    }
    return Read(seq, "", id.substr(1));

}

//Overrides load_read for tab delimited reads
std::vector<Read> TabReadImpl::load_read(std::istream *input) {

    std::vector <Read> reads(1);
    while(std::getline(*input, tabLine) && tabLine.size() < 1) {
    }

    std::vector <std::string> parsedRead;
    boost::split(parsedRead, tabLine, boost::is_any_of("\t"));

    if (parsedRead.size() != 3 && parsedRead.size() != 5 && parsedRead.size() != 6) {
        throw std::runtime_error("There are not either 3 (SE), 5 (PE, itab5), or 6 (PE, itab6) elements within a tab delimited file line");
    }

    if (parsedRead[1].size() != parsedRead[2].size()) {
        throw std::runtime_error("sequence and qualities are not the same length 1");
    }

    reads[0] = Read(parsedRead[1], parsedRead[2], parsedRead[0]);

    if (parsedRead.size() == 5) {

        if (parsedRead[3].size() != parsedRead[4].size()) {
            throw std::runtime_error("sequence and qualities are not the same length 2");
        }

        reads.push_back(Read(parsedRead[3], parsedRead[4], parsedRead[0]));
    }

    if (parsedRead.size() == 6) {

        if (parsedRead[4].size() != parsedRead[5].size()) {
            throw std::runtime_error("sequence and qualities are not the same length 2");
        }

        reads.push_back(Read(parsedRead[4], parsedRead[5], parsedRead[3]));
    }

    // ignore extra lines at end of file
    while(input->good() and (input->peek() == '\n' || input->peek() == '\r')) {
        input->get();
    }

    return reads;
}

template <>
InputReader<SingleEndRead, SingleEndReadFastqImpl>::value_type InputReader<SingleEndRead, SingleEndReadFastqImpl>::next() {
    return InputReader<SingleEndRead, SingleEndReadFastqImpl>::value_type(new SingleEndRead(load_read(input)));
}

template <>
bool InputReader<SingleEndRead, SingleEndReadFastqImpl>::has_next() {
    // ignore extra lines at end of file
    if (!(input and input->good()) and !finput.empty()){
        fs.open(check_open_r(finput.back()), bi::close_handle);
        input = &fs;
        finput.pop_back();
    }
    skip_lr(input);
    return (input and input->good());
};

template<>
InputReader<SingleEndRead, FastaReadImpl>::value_type InputReader<SingleEndRead, FastaReadImpl>::next() {
    return InputReader<SingleEndRead, FastaReadImpl>::value_type(new SingleEndRead(load_read(input)));
}

template <>
bool InputReader<SingleEndRead, FastaReadImpl>::has_next() {
    // ignore extra lines at end of file
    skip_lr(input);
    return (input and input->good());
};

template <>
InputReader<PairedEndRead, PairedEndReadFastqImpl>::value_type InputReader<PairedEndRead, PairedEndReadFastqImpl>::next() {
    Read r1 = load_read(in1);
    Read r2 = load_read(in2);
    return InputReader<PairedEndRead, PairedEndReadFastqImpl>::value_type(new PairedEndRead(r1, r2));
}

template <>
bool InputReader<PairedEndRead, PairedEndReadFastqImpl>::has_next() {
    // ignore extra lines at end of file
    if (!(in1 and in1->good() and in2 and in2->good()) and !fin1.empty()) {
        fs1.open(check_open_r(fin1.back()), bi::never_close_handle);
        fs2.open(check_open_r(fin2.back()), bi::never_close_handle);
        in1=&fs1;
        in2=&fs2;
        fin1.pop_back();
        fin2.pop_back();
    }
    skip_lr(in1);
    skip_lr(in2);
    return (in1 and in1->good() and in2 and in2->good());
};

template<>
InputReader<PairedEndRead, InterReadImpl>::value_type InputReader<PairedEndRead, InterReadImpl>::next() {
    Read r1 = load_read(in1);
    Read r2;
    try {
        r2 = load_read(in1);
    } catch (const std::exception&) {
        throw std::runtime_error("odd number of sequences in interleaved file");
    }
    return InputReader<PairedEndRead, InterReadImpl>::value_type(new PairedEndRead(r1, r2));
}

template<>
bool InputReader<PairedEndRead, InterReadImpl>::has_next() {
    if (!(in1 and in1->good()) and !fin.empty()){
        inter.open(check_open_r(fin.back()), bi::close_handle);
        in1 = &inter;
        fin.pop_back();
    }
    skip_lr(in1);
    return(in1 && in1->good());
}

template <>
InputReader<ReadBase, TabReadImpl>::value_type InputReader<ReadBase, TabReadImpl>::next() {
    std::vector<Read> rs = load_read(in1);
    if (rs.size() == 1) {
        return InputReader<SingleEndRead, TabReadImpl>::value_type(new SingleEndRead(rs[0]));
    }
    return InputReader<PairedEndRead, TabReadImpl>::value_type(new PairedEndRead(rs[0], rs[1]));
}

template <>
bool InputReader<ReadBase, TabReadImpl>::has_next() {
    // ignore extra lines at end of file
    if (!(in1 and in1->good()) and !fin.empty()){
        tabin.open(check_open_r(fin.back()), bi::close_handle);
        in1 = &tabin;
        fin.pop_back();
    }
    skip_lr(in1);
    return (in1 and in1->good());
}
<commit_msg>added include that seems to be necessary for older versions of gcc<commit_after>#include "ioHandler.h"
#include <exception>
#include <cerrno>
#include <sstream>

void writer_helper(ReadBase *r, std::shared_ptr<OutputWriter> pe, std::shared_ptr<OutputWriter> se, bool stranded, bool no_orphans ) { //class writer
    PairedEndRead *per = dynamic_cast<PairedEndRead*>(r);
    if (per) {
        Read &one = per->non_const_read_one();
        Read &two = per->non_const_read_two();

        if (!one.getDiscard() && !two.getDiscard()) {
            pe->write(*per);
        } else if (!one.getDiscard() && !no_orphans) { // Will never be RC
            se->write_read(one, false);
        } else if (!two.getDiscard() && !no_orphans) { // if stranded RC
            se->write_read((per->get_read_two()), stranded);
        } else {

        }
    } else {
        SingleEndRead *ser = dynamic_cast<SingleEndRead*>(r);
        if (!ser) {
            throw std::runtime_error("Unknown read found");
        }
        if (! (ser->non_const_read_one()).getDiscard() ) {
            se->write(*ser);
        } else {

        }
    }
}

void skip_lr(std::istream *input) {
    while(input and input->good() and (input->peek() == '\n' || input->peek() == '\r')) {
        input->get();
    }
}

void  __attribute__ ((noreturn)) throw_error(const std::string& filename) {
    throw std::runtime_error(filename + ": " +  std::strerror( errno ));
}

/*
takes a delimited string and converts to fasta format for reading in
*/
std::string string2fasta(std::string seqstring, const char delim) {
  std::string newfa;
  int index=1;
  std::stringstream ss( seqstring );

  while( ss.good() )
  {
      std::string substr;
      getline( ss, substr, delim );
      newfa.append(">seq");
      newfa.append( std::to_string(index) );
      newfa.append( "\n" );
      newfa.append( substr );
      newfa.append( "\n" );
      index++;
  }
  return(newfa);
}

int check_open_r(const std::string& filename) {
    FILE* f = NULL;

    bf::path p(filename);
    if (!bf::exists(p)) {
        throw std::runtime_error("File " + filename + " was not found.");
    }

    if (p.extension() == ".gz") {
        f = popen(("gunzip -c '" + filename + "'").c_str(), "r");
    } else {
        f = fopen(filename.c_str(), "r");
    }

    if (!f) {
        throw_error(filename);
    }
    return fileno(f);
}

int check_exists(const std::string& filename, bool force, bool gzip, bool std_out) {
    FILE* f = NULL;

    if (std_out) {
        return fileno(stdout);
    }
    std::string fname = gzip ? filename + ".gz" : filename ;

    bf::path p(fname);

    if (force || !bf::exists(p)) {
        if (gzip) {
            f = popen(("gzip > '" + fname + "'").c_str(), "w");
        } else {
            f = fopen(fname.c_str(), "w");
        }
        if (!f) {
            throw_error(fname);
        }
        return fileno(f);
    } else {
        throw std::runtime_error("File " + fname + " all ready exists. Please use -F or delete it\n");
    }
}

Read InputFastq::load_read(std::istream *input) {
    while(std::getline(*input, id) && id.size() < 1) {
    }
    if (id.size() < 1) {
        throw std::runtime_error("invalid id line empty");
    }
    if (id[0] != '@') {
        throw std::runtime_error("id line did not begin with @");
    }
    std::getline(*input, seq);
    if (seq.size() < 1) {
        throw std::runtime_error("invalid seq line empty");
    }
    std::getline(*input, id2);
    if (id2.size() < 1) {
        throw std::runtime_error("invalid id2 line empty");
    }
    if (id2[0] != '+') {
        throw std::runtime_error("invalid id2 line did not begin with +");
    }
    std::getline(*input, qual);
    if (qual.size() != seq.size()) {
        throw std::runtime_error("qual string not the same length as sequence");
    }

    // ignore extra lines at end of file
    while(input->good() and (input->peek() == '\n' || input->peek() == '\r')) {
        input->get();
    }
    return Read(seq, qual, id.substr(1));
}

Read InputFasta::load_read(std::istream *input) {
    while(std::getline(*input, id) && id.size() < 1) {
    }
    if (id.size() < 1) {
        throw std::runtime_error("invalid id - line empty");
    }
    if (id[0] != '>') {
        throw std::runtime_error("id line did not begin with >");
    }
    seq = "";
    while (std::getline(*input, tmpSeq)) {
        seq += tmpSeq;
        if (input->peek() == '>') {
            break;
        }
    }
    if (seq.size() < 1) {
        throw std::runtime_error("no sequence");
    }
    while(input->good() and (input->peek() == '\n' || input->peek() == '\r')) {
        input->get();
    }
    return Read(seq, "", id.substr(1));

}

//Overrides load_read for tab delimited reads
std::vector<Read> TabReadImpl::load_read(std::istream *input) {

    std::vector <Read> reads(1);
    while(std::getline(*input, tabLine) && tabLine.size() < 1) {
    }

    std::vector <std::string> parsedRead;
    boost::split(parsedRead, tabLine, boost::is_any_of("\t"));

    if (parsedRead.size() != 3 && parsedRead.size() != 5 && parsedRead.size() != 6) {
        throw std::runtime_error("There are not either 3 (SE), 5 (PE, itab5), or 6 (PE, itab6) elements within a tab delimited file line");
    }

    if (parsedRead[1].size() != parsedRead[2].size()) {
        throw std::runtime_error("sequence and qualities are not the same length 1");
    }

    reads[0] = Read(parsedRead[1], parsedRead[2], parsedRead[0]);

    if (parsedRead.size() == 5) {

        if (parsedRead[3].size() != parsedRead[4].size()) {
            throw std::runtime_error("sequence and qualities are not the same length 2");
        }

        reads.push_back(Read(parsedRead[3], parsedRead[4], parsedRead[0]));
    }

    if (parsedRead.size() == 6) {

        if (parsedRead[4].size() != parsedRead[5].size()) {
            throw std::runtime_error("sequence and qualities are not the same length 2");
        }

        reads.push_back(Read(parsedRead[4], parsedRead[5], parsedRead[3]));
    }

    // ignore extra lines at end of file
    while(input->good() and (input->peek() == '\n' || input->peek() == '\r')) {
        input->get();
    }

    return reads;
}

template <>
InputReader<SingleEndRead, SingleEndReadFastqImpl>::value_type InputReader<SingleEndRead, SingleEndReadFastqImpl>::next() {
    return InputReader<SingleEndRead, SingleEndReadFastqImpl>::value_type(new SingleEndRead(load_read(input)));
}

template <>
bool InputReader<SingleEndRead, SingleEndReadFastqImpl>::has_next() {
    // ignore extra lines at end of file
    if (!(input and input->good()) and !finput.empty()){
        fs.open(check_open_r(finput.back()), bi::close_handle);
        input = &fs;
        finput.pop_back();
    }
    skip_lr(input);
    return (input and input->good());
};

template<>
InputReader<SingleEndRead, FastaReadImpl>::value_type InputReader<SingleEndRead, FastaReadImpl>::next() {
    return InputReader<SingleEndRead, FastaReadImpl>::value_type(new SingleEndRead(load_read(input)));
}

template <>
bool InputReader<SingleEndRead, FastaReadImpl>::has_next() {
    // ignore extra lines at end of file
    skip_lr(input);
    return (input and input->good());
};

template <>
InputReader<PairedEndRead, PairedEndReadFastqImpl>::value_type InputReader<PairedEndRead, PairedEndReadFastqImpl>::next() {
    Read r1 = load_read(in1);
    Read r2 = load_read(in2);
    return InputReader<PairedEndRead, PairedEndReadFastqImpl>::value_type(new PairedEndRead(r1, r2));
}

template <>
bool InputReader<PairedEndRead, PairedEndReadFastqImpl>::has_next() {
    // ignore extra lines at end of file
    if (!(in1 and in1->good() and in2 and in2->good()) and !fin1.empty()) {
        fs1.open(check_open_r(fin1.back()), bi::never_close_handle);
        fs2.open(check_open_r(fin2.back()), bi::never_close_handle);
        in1=&fs1;
        in2=&fs2;
        fin1.pop_back();
        fin2.pop_back();
    }
    skip_lr(in1);
    skip_lr(in2);
    return (in1 and in1->good() and in2 and in2->good());
};

template<>
InputReader<PairedEndRead, InterReadImpl>::value_type InputReader<PairedEndRead, InterReadImpl>::next() {
    Read r1 = load_read(in1);
    Read r2;
    try {
        r2 = load_read(in1);
    } catch (const std::exception&) {
        throw std::runtime_error("odd number of sequences in interleaved file");
    }
    return InputReader<PairedEndRead, InterReadImpl>::value_type(new PairedEndRead(r1, r2));
}

template<>
bool InputReader<PairedEndRead, InterReadImpl>::has_next() {
    if (!(in1 and in1->good()) and !fin.empty()){
        inter.open(check_open_r(fin.back()), bi::close_handle);
        in1 = &inter;
        fin.pop_back();
    }
    skip_lr(in1);
    return(in1 && in1->good());
}

template <>
InputReader<ReadBase, TabReadImpl>::value_type InputReader<ReadBase, TabReadImpl>::next() {
    std::vector<Read> rs = load_read(in1);
    if (rs.size() == 1) {
        return InputReader<SingleEndRead, TabReadImpl>::value_type(new SingleEndRead(rs[0]));
    }
    return InputReader<PairedEndRead, TabReadImpl>::value_type(new PairedEndRead(rs[0], rs[1]));
}

template <>
bool InputReader<ReadBase, TabReadImpl>::has_next() {
    // ignore extra lines at end of file
    if (!(in1 and in1->good()) and !fin.empty()){
        tabin.open(check_open_r(fin.back()), bi::close_handle);
        in1 = &tabin;
        fin.pop_back();
    }
    skip_lr(in1);
    return (in1 and in1->good());
}
<|endoftext|>


<commit_before><commit_msg>DOMUI: Don't call SetString for fields that doesn't exist in the Password Manager.<commit_after><|endoftext|>


<commit_before>// For conditions of distribution and use, see copyright notice in license.txt
#include "StableHeaders.h"

#include "ZeroCode.h"

namespace ProtocolUtilities
{

    size_t CountConsecutiveZeroes(const uint8_t *data, size_t i, size_t numBytes)
    {
        size_t count = 0;
        while(i < numBytes && data[i] == 0)
        {
            ++count;
            ++i;
        }
        return count;
    }

    size_t CountZeroEncodedLength(const uint8_t *data, size_t numBytes)
    {
        size_t length = 0;

        size_t i = 0;
        while(i < numBytes)
        {
            if (data[i] == 0) // Hit a zero?
            {
                size_t numZeroes = CountConsecutiveZeroes(data, i, numBytes);
                length += 1 + numZeroes;
                i += numZeroes;
            }
            else
            {
                ++length;
                ++i;
            }
        }
        return length;
    }

    size_t CountZeroDecodedLength(const uint8_t *data, size_t numBytes)
    {
        size_t length = 0;

        size_t i = 0;
        while(i < numBytes)
        {
            // If we encounter a zero, the next byte in the stream tells us how many times we duplicate that zero.
            if (data[i] == 0)
            {
                ++i;
                if (i >= numBytes) // Oops! We received a stream where the last byte was zero. We should have had a length byte after this.. Malformed packet!
                    return 0; // return 0 instead of length to signal that this packet is malformed.

                size_t numZeroes = data[i++];

                if (numZeroes == 0) // A run of zero zeroes? The packet is then malformed.
                    return 0; // \todo Have heard of rumors that a sequence '00 00 AA BB' would signal a larger block of zeroes, e.g. using a u16 as the length counter.
                              //       libopenmetaverse's code doesn't do this however, so we conclude this case to result in a corrupted stream.

                length += numZeroes;
            }
            else // A normal non-zero byte.
            {
                ++length;
                ++i;
            }
        }
        return length;
    }

    bool ZeroDecode(uint8_t *dstData, size_t dstBytes, const uint8_t *srcData, size_t srcBytes)
    {
        size_t dst = 0;
        size_t src = 0;

        while(src < srcBytes)
        {
            if (srcData[src] == 0)
            {
                ++src;
                if (src >= srcBytes) // Malformed zero-encoded packet found! (Ends in a zero without run-length!
                    return false;

                size_t numZeroes = srcData[src++];
                for(size_t i = 0; i < numZeroes; ++i)
                {
                    if (dst >= dstBytes)
                        return false; // Whoops! Caller didn't provide a buffer big enough!

                    dstData[dst++] = 0;
                }
            }
            else
            {
                if (dst >= dstBytes)
                    return false; // Whoops! Caller didn't provide a buffer big enough!

                dstData[dst++] = srcData[src++];
            }
        }
        return true;
    }

    bool ZeroEncode(uint8_t *dstData, size_t dstBytes, const uint8_t *srcData, size_t srcBytes)
    {
        size_t dst = 0;
        size_t src = 0;

        while(src < srcBytes)
        {
            if (srcData[src] == 0)
            {
                size_t numZeroes = CountConsecutiveZeroes(srcData, src, srcBytes);
                src += numZeroes;

                ///\bug Fails on a run of 256 or more zeroes.

                ///\todo Warning log out.
                if (dst >= dstBytes)
                    return false; // Whoops! Caller didn't provide a buffer big enough!
                dstData[dst++] = 0;
                ///\todo Warning log out.
                if (dst >= dstBytes)
                    return false; // Whoops! Caller didn't provide a buffer big enough!
                dstData[dst++] = numZeroes;
            }
            else
            {
                ///\todo Warning log out.
                if (dst >= dstBytes)
                    return false; // Whoops! Caller didn't provide a buffer big enough!
                dstData[dst++] = srcData[src++];
            }
        }

        return true;
    }

}<commit_msg>Clean couple todo's: add warning log prints for ZeroCode.cpp.<commit_after>// For conditions of distribution and use, see copyright notice in license.txt

#include "StableHeaders.h"

#include "ZeroCode.h"

#include "LoggingFunctions.h"

DEFINE_POCO_LOGGING_FUNCTIONS("ZeroCode")

namespace ProtocolUtilities
{

    size_t CountConsecutiveZeroes(const uint8_t *data, size_t i, size_t numBytes)
    {
        size_t count = 0;
        while(i < numBytes && data[i] == 0)
        {
            ++count;
            ++i;
        }
        return count;
    }

    size_t CountZeroEncodedLength(const uint8_t *data, size_t numBytes)
    {
        size_t length = 0;

        size_t i = 0;
        while(i < numBytes)
        {
            if (data[i] == 0) // Hit a zero?
            {
                size_t numZeroes = CountConsecutiveZeroes(data, i, numBytes);
                length += 1 + numZeroes;
                i += numZeroes;
            }
            else
            {
                ++length;
                ++i;
            }
        }
        return length;
    }

    size_t CountZeroDecodedLength(const uint8_t *data, size_t numBytes)
    {
        size_t length = 0;

        size_t i = 0;
        while(i < numBytes)
        {
            // If we encounter a zero, the next byte in the stream tells us how many times we duplicate that zero.
            if (data[i] == 0)
            {
                ++i;
                if (i >= numBytes)
                {
                    LogWarning("Oops! We received a stream where the last byte was zero. We should have had a length byte after this.. Malformed packet!");
                    return 0; // return 0 instead of length to signal that this packet is malformed.
                }

                size_t numZeroes = data[i++];
                if (numZeroes == 0) // A run of zero zeroes? The packet is then malformed.
                    return 0; // \todo Have heard of rumors that a sequence '00 00 AA BB' would signal a larger block of zeroes, e.g. using a u16 as the length counter.
                              //       libopenmetaverse's code doesn't do this however, so we conclude this case to result in a corrupted stream.
                length += numZeroes;
            }
            else // A normal non-zero byte.
            {
                ++length;
                ++i;
            }
        }
        return length;
    }

    bool ZeroDecode(uint8_t *dstData, size_t dstBytes, const uint8_t *srcData, size_t srcBytes)
    {
        size_t dst = 0;
        size_t src = 0;

        while(src < srcBytes)
        {
            if (srcData[src] == 0)
            {
                ++src;
                if (src >= srcBytes)
                {
                    LogWarning("Malformed zero-encoded packet found! (Ends in a zero without run-length!");
                    return false;
                }

                size_t numZeroes = srcData[src++];
                for(size_t i = 0; i < numZeroes; ++i)
                {
                    if (dst >= dstBytes)
                    {
                        LogWarning("Whoops! Caller didn't provide a buffer big enough!");
                        return false;
                    }

                    dstData[dst++] = 0;
                }
            }
            else
            {
                if (dst >= dstBytes)
                {
                    LogWarning("Whoops! Caller didn't provide a buffer big enough!");
                    return false;
                }

                dstData[dst++] = srcData[src++];
            }
        }

        return true;
    }

    bool ZeroEncode(uint8_t *dstData, size_t dstBytes, const uint8_t *srcData, size_t srcBytes)
    {
        size_t dst = 0;
        size_t src = 0;
        while(src < srcBytes)
        {
            if (srcData[src] == 0)
            {
                size_t numZeroes = CountConsecutiveZeroes(srcData, src, srcBytes);
                src += numZeroes;

                ///\bug Fails on a run of 256 or more zeroes.
                if (dst >= dstBytes)
                {
                    LogWarning("Whoops! Caller didn't provide a buffer big enough!");
                    return false;
                }
                dstData[dst++] = 0;
                if (dst >= dstBytes)
                {
                    LogWarning("Whoops! Caller didn't provide a buffer big enough!");
                    return false;
                }
                dstData[dst++] = numZeroes;
            }
            else
            {
                if (dst >= dstBytes)
                {
                    LogWarning("Whoops! Caller didn't provide a buffer big enough!");
                    return false;
                }
                dstData[dst++] = srcData[src++];
            }
        }

        return true;
    }
}
<|endoftext|>


<commit_before>/*************** <auto-copyright.pl BEGIN do not edit this line> **************
 *
 * VR Juggler is (C) Copyright 1998-2007 by Iowa State University
 *
 * Original Authors:
 *   Allen Bierbaum, Christopher Just,
 *   Patrick Hartling, Kevin Meinert,
 *   Carolina Cruz-Neira, Albert Baker
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 *
 *************** <auto-copyright.pl END do not edit this line> ***************/

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

#include <vpr/vpr.h>

#include <drivers/noDNA/X-IST/X-ISTStandalone.h>

#ifndef GENERIC_READ
#  define GENERIC_READ 0
#endif
#ifndef GENERIC_WRITE
#  define GENERIC_WRITE 0
#endif
#ifndef OPEN_EXISTING
#  define OPEN_EXISTING 0
#endif

#if ! defined(VPR_OS_Windows)
#  define PURGE_TXCLEAR 0x0004
#  define PURGE_RXCLEAR 0x0008
#endif

///////////////////////////////////////////////////////////
// Public Methods
///////////////////////////////////////////////////////////

// Constructor
X_ISTStandalone::X_ISTStandalone()
   : mComm(NULL)
{
}

// Destructor
X_ISTStandalone::~X_ISTStandalone()
{
   closeGlove();
}

// Connect to the X-IST hardware
bool X_ISTStandalone::connectToHardware(const int gloveNumber)
{
   int num_devs;
   FT_STATUS ftstatus = FT_ListDevices(&num_devs, NULL, FT_LIST_NUMBER_ONLY);

   if ( ftstatus != FT_OK )
   {
      return false;
   }

   if ( gloveNumber >= num_devs )
   {
      return false;
   }

   char str_serial[256];

   ftstatus = FT_ListDevices((char*) gloveNumber, str_serial,
                             FT_LIST_BY_INDEX | FT_OPEN_BY_SERIAL_NUMBER);

   if ( ftstatus != FT_OK )
   {
      return false;
   }

   mComm = FT_W32_CreateFile(str_serial, GENERIC_READ|GENERIC_WRITE, 0, 0,
                             OPEN_EXISTING, FT_OPEN_BY_SERIAL_NUMBER, 0);

#if defined(VPR_OS_Windows)
   if ( mComm == (void*) INVALID_HANDLE_VALUE )
#else
   if ( mComm == (void*) NULL )
#endif
   {
      closeGlove();
      return false;
   }

   FTTIMEOUTS ctmoNew = {0};
   FTDCB dcbUSB;

   FT_W32_GetCommTimeouts(mComm, &mCtmoOld);
   ctmoNew.ReadIntervalTimeout = 50;
   ctmoNew.ReadTotalTimeoutConstant = 200;
   ctmoNew.ReadTotalTimeoutMultiplier = 0;
   ctmoNew.WriteTotalTimeoutMultiplier = 0;
   ctmoNew.WriteTotalTimeoutConstant = 0;
   FT_W32_SetCommTimeouts(mComm, &ctmoNew);
   dcbUSB.DCBlength = sizeof(dcbUSB);
   FT_W32_GetCommState(mComm, &dcbUSB);
   dcbUSB.BaudRate = 1000000;
   dcbUSB.fOutxCtsFlow = false;
   dcbUSB.fRtsControl = 0;
   dcbUSB.fAbortOnError = false;
   FT_W32_SetCommState(mComm, &dcbUSB);
   FT_W32_PurgeComm(mComm, PURGE_TXCLEAR | PURGE_RXCLEAR);

   char buffer[256];
   char name[256];

// Get firmware version
   buffer[0] = 0x11;
   write(buffer, 1);
   memset(buffer, 0, sizeof(buffer));
   read(buffer, 40);
   FT_W32_PurgeComm(mComm, PURGE_TXCLEAR | PURGE_RXCLEAR);
   mFirmwareVersion = WORD (((buffer[0] - 48) * 100) + ((buffer[2] - 48) * 10) + (buffer[4] - 48));
//   vprDEBUG(gadgetDBG_INPUT_MGR, vprDBG_CONFIG_LVL)
//      << "[X-IST] firmware version : " << mFirmwareVersion << std::endl
//      << vprDEBUG_FLUSH;

// Get hardware version
   buffer[0] = 0x12;
   write(buffer, 1);
   memset(buffer, 0, sizeof(buffer));
   read(buffer, 40);
   FT_W32_PurgeComm(mComm, PURGE_TXCLEAR | PURGE_RXCLEAR);
   sprintf(name, (char*)buffer);
//   vprDEBUG(gadgetDBG_INPUT_MGR, vprDBG_CONFIG_LVL)
//      << "[X-IST] hardware version : " << name << std::endl
//      << vprDEBUG_FLUSH;

// Get product id
   buffer[0] = 0x13;
   write(buffer, 1);
   memset(buffer, 0, sizeof(buffer));
   read(buffer, 40);
   FT_W32_PurgeComm(mComm, PURGE_TXCLEAR | PURGE_RXCLEAR);
   sprintf(name,(char*)buffer);
//   vprDEBUG(gadgetDBG_INPUT_MGR, vprDBG_CONFIG_LVL)
//      << "[X-IST] product id : " << name << std::endl << vprDEBUG_FLUSH;

   return true;
}

bool X_ISTStandalone::readRecordsFromHardware(WORD values[24])
{
   unsigned char buffer[256];

// Get all channels
   buffer[0] = 0x35;
   if ( ! write((char*) buffer, 1) )
   {
      return false;
   }
   if ( ! read((char*) buffer, (mFirmwareVersion < 27 ? 31 : 38)) )
   {
      return false;
   }

   FT_W32_PurgeComm(mComm, PURGE_TXCLEAR | PURGE_RXCLEAR);

   values[0] = WORD (buffer[0] + (short (buffer[1] / 16) * 256));
   values[1] = WORD (buffer[2] + (short (buffer[1] % 16) * 256));
   values[2] = WORD (buffer[3] + (short (buffer[4] / 16) * 256));
   values[3] = WORD (buffer[5] + (short (buffer[4] % 16) * 256));
   values[4] = WORD (buffer[6] + (short (buffer[7] / 16) * 256));
   values[5] = WORD (buffer[8] + (short (buffer[7] % 16) * 256));
   values[6] = WORD (buffer[9] + (short (buffer[10] / 16) * 256));
   values[7] = WORD (buffer[11] + (short (buffer[10] % 16) * 256));
   values[8] = WORD (buffer[12] + (short (buffer[13] / 16) * 256));
   values[9] = WORD (buffer[14] + (short (buffer[13] % 16) * 256));
   values[10] = WORD (buffer[15] + (short (buffer[16] / 16) * 256));
   values[11] = WORD (buffer[17] + (short (buffer[16] % 16) * 256));
   values[12] = WORD (buffer[18] + (short (buffer[19] / 16) * 256));
   values[13] = WORD (buffer[20] + (short (buffer[19] % 16) * 256));
   values[14] = WORD (buffer[21] + (short (buffer[22] / 16) * 256));
   values[15] = WORD (buffer[23] + (short (buffer[22] % 16) * 256));
   values[16] = WORD (buffer[24] + (short (buffer[25] / 16) * 256));
   values[17] = WORD (buffer[26] + (short (buffer[25] % 16) * 256));
   values[18] = WORD (buffer[27] + (short (buffer[28] / 16) * 256));
   values[19] = WORD (buffer[29] + (short (buffer[28] % 16) * 256));

   if ( mFirmwareVersion > 26 )
   {
      values[20] = WORD (buffer[30] + (short (buffer[31] / 16) * 256));
      values[21] = WORD (buffer[32] + (short (buffer[31] % 16) * 256));
      values[22] = WORD (buffer[33] + (short (buffer[34] / 16) * 256));
      values[23] = WORD (buffer[35] + (short (buffer[34] % 16) * 256));
   }

   return true;
}

void X_ISTStandalone::closeGlove()
{
   if ( mComm != NULL )
   {
      FT_W32_SetCommTimeouts(mComm, &mCtmoOld);
      FT_W32_CloseHandle(mComm);
   }

   mComm = NULL;
}

bool X_ISTStandalone::read(char* buffer, const unsigned long int size)
{
   DWORD dwBytesRead;
   FT_W32_ReadFile(mComm, buffer, size, &dwBytesRead, NULL);
   return (size == dwBytesRead);
}

bool X_ISTStandalone::write(char *buffer, const unsigned long int size)
{
   DWORD dwBytesWrite;
   FT_W32_WriteFile(mComm, buffer, size, &dwBytesWrite, NULL);
   return (size == dwBytesWrite);
}
<commit_msg>Silence API deprecation warnings from Visual C++ 8.0.<commit_after>/*************** <auto-copyright.pl BEGIN do not edit this line> **************
 *
 * VR Juggler is (C) Copyright 1998-2007 by Iowa State University
 *
 * Original Authors:
 *   Allen Bierbaum, Christopher Just,
 *   Patrick Hartling, Kevin Meinert,
 *   Carolina Cruz-Neira, Albert Baker
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 *
 *************** <auto-copyright.pl END do not edit this line> ***************/

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

#include <vpr/vpr.h>

#include <drivers/noDNA/X-IST/X-ISTStandalone.h>

#ifndef GENERIC_READ
#  define GENERIC_READ 0
#endif
#ifndef GENERIC_WRITE
#  define GENERIC_WRITE 0
#endif
#ifndef OPEN_EXISTING
#  define OPEN_EXISTING 0
#endif

#if ! defined(VPR_OS_Windows)
#  define PURGE_TXCLEAR 0x0004
#  define PURGE_RXCLEAR 0x0008
#endif

///////////////////////////////////////////////////////////
// Public Methods
///////////////////////////////////////////////////////////

// Constructor
X_ISTStandalone::X_ISTStandalone()
   : mComm(NULL)
{
}

// Destructor
X_ISTStandalone::~X_ISTStandalone()
{
   closeGlove();
}

// Connect to the X-IST hardware
bool X_ISTStandalone::connectToHardware(const int gloveNumber)
{
   int num_devs;
   FT_STATUS ftstatus = FT_ListDevices(&num_devs, NULL, FT_LIST_NUMBER_ONLY);

   if ( ftstatus != FT_OK )
   {
      return false;
   }

   if ( gloveNumber >= num_devs )
   {
      return false;
   }

   char str_serial[256];

   ftstatus = FT_ListDevices((char*) gloveNumber, str_serial,
                             FT_LIST_BY_INDEX | FT_OPEN_BY_SERIAL_NUMBER);

   if ( ftstatus != FT_OK )
   {
      return false;
   }

   mComm = FT_W32_CreateFile(str_serial, GENERIC_READ|GENERIC_WRITE, 0, 0,
                             OPEN_EXISTING, FT_OPEN_BY_SERIAL_NUMBER, 0);

#if defined(VPR_OS_Windows)
   if ( mComm == (void*) INVALID_HANDLE_VALUE )
#else
   if ( mComm == (void*) NULL )
#endif
   {
      closeGlove();
      return false;
   }

   FTTIMEOUTS ctmoNew = {0};
   FTDCB dcbUSB;

   FT_W32_GetCommTimeouts(mComm, &mCtmoOld);
   ctmoNew.ReadIntervalTimeout = 50;
   ctmoNew.ReadTotalTimeoutConstant = 200;
   ctmoNew.ReadTotalTimeoutMultiplier = 0;
   ctmoNew.WriteTotalTimeoutMultiplier = 0;
   ctmoNew.WriteTotalTimeoutConstant = 0;
   FT_W32_SetCommTimeouts(mComm, &ctmoNew);
   dcbUSB.DCBlength = sizeof(dcbUSB);
   FT_W32_GetCommState(mComm, &dcbUSB);
   dcbUSB.BaudRate = 1000000;
   dcbUSB.fOutxCtsFlow = false;
   dcbUSB.fRtsControl = 0;
   dcbUSB.fAbortOnError = false;
   FT_W32_SetCommState(mComm, &dcbUSB);
   FT_W32_PurgeComm(mComm, PURGE_TXCLEAR | PURGE_RXCLEAR);

   char buffer[256];

// Get firmware version
   buffer[0] = 0x11;
   write(buffer, 1);
   memset(buffer, 0, sizeof(buffer));
   read(buffer, 40);
   FT_W32_PurgeComm(mComm, PURGE_TXCLEAR | PURGE_RXCLEAR);
   mFirmwareVersion = WORD (((buffer[0] - 48) * 100) + ((buffer[2] - 48) * 10) + (buffer[4] - 48));
//   vprDEBUG(gadgetDBG_INPUT_MGR, vprDBG_CONFIG_LVL)
//      << "[X-IST] firmware version : " << mFirmwareVersion << std::endl
//      << vprDEBUG_FLUSH;

// Get hardware version
   buffer[0] = 0x12;
   write(buffer, 1);
   memset(buffer, 0, sizeof(buffer));
   read(buffer, 40);
   FT_W32_PurgeComm(mComm, PURGE_TXCLEAR | PURGE_RXCLEAR);
//   vprDEBUG(gadgetDBG_INPUT_MGR, vprDBG_CONFIG_LVL)
//      << "[X-IST] hardware version : " << buffer << std::endl
//      << vprDEBUG_FLUSH;

// Get product id
   buffer[0] = 0x13;
   write(buffer, 1);
   memset(buffer, 0, sizeof(buffer));
   read(buffer, 40);
   FT_W32_PurgeComm(mComm, PURGE_TXCLEAR | PURGE_RXCLEAR);
//   vprDEBUG(gadgetDBG_INPUT_MGR, vprDBG_CONFIG_LVL)
//      << "[X-IST] product id : " << buffer << std::endl << vprDEBUG_FLUSH;

   return true;
}

bool X_ISTStandalone::readRecordsFromHardware(WORD values[24])
{
   unsigned char buffer[256];

// Get all channels
   buffer[0] = 0x35;
   if ( ! write((char*) buffer, 1) )
   {
      return false;
   }
   if ( ! read((char*) buffer, (mFirmwareVersion < 27 ? 31 : 38)) )
   {
      return false;
   }

   FT_W32_PurgeComm(mComm, PURGE_TXCLEAR | PURGE_RXCLEAR);

   values[0] = WORD (buffer[0] + (short (buffer[1] / 16) * 256));
   values[1] = WORD (buffer[2] + (short (buffer[1] % 16) * 256));
   values[2] = WORD (buffer[3] + (short (buffer[4] / 16) * 256));
   values[3] = WORD (buffer[5] + (short (buffer[4] % 16) * 256));
   values[4] = WORD (buffer[6] + (short (buffer[7] / 16) * 256));
   values[5] = WORD (buffer[8] + (short (buffer[7] % 16) * 256));
   values[6] = WORD (buffer[9] + (short (buffer[10] / 16) * 256));
   values[7] = WORD (buffer[11] + (short (buffer[10] % 16) * 256));
   values[8] = WORD (buffer[12] + (short (buffer[13] / 16) * 256));
   values[9] = WORD (buffer[14] + (short (buffer[13] % 16) * 256));
   values[10] = WORD (buffer[15] + (short (buffer[16] / 16) * 256));
   values[11] = WORD (buffer[17] + (short (buffer[16] % 16) * 256));
   values[12] = WORD (buffer[18] + (short (buffer[19] / 16) * 256));
   values[13] = WORD (buffer[20] + (short (buffer[19] % 16) * 256));
   values[14] = WORD (buffer[21] + (short (buffer[22] / 16) * 256));
   values[15] = WORD (buffer[23] + (short (buffer[22] % 16) * 256));
   values[16] = WORD (buffer[24] + (short (buffer[25] / 16) * 256));
   values[17] = WORD (buffer[26] + (short (buffer[25] % 16) * 256));
   values[18] = WORD (buffer[27] + (short (buffer[28] / 16) * 256));
   values[19] = WORD (buffer[29] + (short (buffer[28] % 16) * 256));

   if ( mFirmwareVersion > 26 )
   {
      values[20] = WORD (buffer[30] + (short (buffer[31] / 16) * 256));
      values[21] = WORD (buffer[32] + (short (buffer[31] % 16) * 256));
      values[22] = WORD (buffer[33] + (short (buffer[34] / 16) * 256));
      values[23] = WORD (buffer[35] + (short (buffer[34] % 16) * 256));
   }

   return true;
}

void X_ISTStandalone::closeGlove()
{
   if ( mComm != NULL )
   {
      FT_W32_SetCommTimeouts(mComm, &mCtmoOld);
      FT_W32_CloseHandle(mComm);
   }

   mComm = NULL;
}

bool X_ISTStandalone::read(char* buffer, const unsigned long int size)
{
   DWORD dwBytesRead;
   FT_W32_ReadFile(mComm, buffer, size, &dwBytesRead, NULL);
   return (size == dwBytesRead);
}

bool X_ISTStandalone::write(char *buffer, const unsigned long int size)
{
   DWORD dwBytesWrite;
   FT_W32_WriteFile(mComm, buffer, size, &dwBytesWrite, NULL);
   return (size == dwBytesWrite);
}
<|endoftext|>


<commit_before>#include <realm.hpp>
#include <iostream>

using namespace realm;

bool get_table_ndx(size_t& ndx)
{
    std::cout << "Table ndx? ";
    std::string inp;
    getline(std::cin, inp);
    const char* buf = inp.c_str();
    char* endp;
    ndx = strtol(buf, &endp, 0);
    return *endp == '\0';
}

bool get_range(size_t size, size_t& begin, size_t& end)
{
    std::cout << "Size " << size << ". Range? ";
    std::string inp;
    getline(std::cin, inp);
    if (inp.size() == 0) {
        begin = 0;
        end = size;
        return true;
    }
    const char* buf = inp.c_str();
    char* endp;
    begin = strtol(buf, &endp, 0);
    if (*endp == '\0') {
        end = begin + 1;
        return begin < size;
    }
    if (*endp == '-') {
        ++endp;
        if (*endp != '\0')
            end = strtol(endp, &endp, 0);
        else
            end = size;
        if (*endp == '\0') {
            return begin < end && end <= size;
        }
    }
    return false;
}

void print_objects(ConstTableRef table, size_t begin, size_t end)
{
    printf("                 Object key");
    auto col_keys = table->get_column_keys();
    for (auto col : col_keys) {
        printf("%21s", table->get_column_name(col).data());
    }
    printf("\n");
    for (size_t row = begin; row < end; row++) {
        printf("%5zu ", row);
        ConstObj obj = table->get_object(row);
        printf(" %20zx", obj.get_key().value);
        for (auto col : col_keys) {
            switch (table->get_column_type(col)) {
                case type_Int:
                    printf(" %20ld", obj.get<Int>(col));
                    break;
                case type_Bool:
                    printf(" %20s", obj.get<Bool>(col) ? "true" : "false");
                    break;
                case type_Float:
                    break;
                case type_Double:
                    break;
                case type_String: {
                    auto str = obj.get<String>(col);
                    auto sz = str.size();
                    if (sz > 200) {
                        printf("  String sz: %8zu", sz);
                    }
                    else {
                        printf(" %20s", str.data());
                    }
                    break;
                }
                case type_Timestamp:
                    printf(" %20ld", obj.get<Timestamp>(col).get_seconds());
                    break;
                default:
                    printf(" ********************");
                    break;
            }
        }
        printf("\n");
    }
}

int main(int argc, char const* argv[])
{
    if (argc > 1) {
        Group g(argv[1]);
        auto table_keys = g.get_table_keys();
        for (size_t i = 0; i < table_keys.size(); i++) {
            std::cout << i << ". " << g.get_table_name(table_keys[i]) << " ";
        }
        std::cout << std::endl;
        size_t table_ndx;
        while (get_table_ndx(table_ndx)) {
            auto table = g.get_table(table_keys[table_ndx]);
            auto sz = table->size();
            size_t begin;
            size_t end;
            while (get_range(sz, begin, end)) {
                print_objects(table, begin, end);
            }
        }
    }
    return 0;
}
<commit_msg>Support more column types in realm-browser<commit_after>#include <realm.hpp>
#include <iostream>
#include <ctime>

using namespace realm;

bool get_table_ndx(size_t& ndx)
{
    std::cout << "Table ndx? ";
    std::string inp;
    getline(std::cin, inp);
    const char* buf = inp.c_str();
    char* endp;
    ndx = strtol(buf, &endp, 0);
    return *endp == '\0';
}

bool get_range(size_t size, size_t& begin, size_t& end)
{
    std::cout << "Size " << size << ". Range? ";
    std::string inp;
    getline(std::cin, inp);
    if (inp.size() == 0) {
        begin = 0;
        end = size;
        return true;
    }
    const char* buf = inp.c_str();
    char* endp;
    begin = strtol(buf, &endp, 0);
    if (*endp == '\0') {
        end = begin + 1;
        return begin < size;
    }
    if (*endp == '-') {
        ++endp;
        if (*endp != '\0')
            end = strtol(endp, &endp, 0);
        else
            end = size;
        if (*endp == '\0') {
            return begin < end && end <= size;
        }
    }
    return false;
}

void print_objects(ConstTableRef table, size_t begin, size_t end)
{
    printf("                 Object key");
    auto col_keys = table->get_column_keys();
    for (auto col : col_keys) {
        printf("%21s", table->get_column_name(col).data());
    }
    printf("\n");
    for (size_t row = begin; row < end; row++) {
        printf("%5zu ", row);
        ConstObj obj = table->get_object(row);
        printf(" %20zx", obj.get_key().value);
        for (auto col : col_keys) {
            auto col_type = table->get_column_type(col);
            if (table->get_column_attr(col).test(col_attr_Nullable) && obj.is_null(col)) {
                printf("               <null>");
                continue;
            }
            if (table->get_column_attr(col).test(col_attr_List) && col_type != type_LinkList) {
                printf("               <list>");
                continue;
            }
            switch (col_type) {
                case type_Int:
                    printf(" %20ld", obj.get<Int>(col));
                    break;
                case type_Bool:
                    printf(" %20s", obj.get<Bool>(col) ? "true" : "false");
                    break;
                case type_Float:
                    printf(" %20f", obj.get<Float>(col));
                    break;
                case type_Double:
                    printf(" %20f", obj.get<Double>(col));
                    break;
                case type_String: {
                    std::string str = obj.get<String>(col);
                    if (str.size() == 0) {
                        str = "<empty>";
                    }
                    if (str.size() > 20) {
                        str = str.substr(0, 17) + "...";
                    }
                    printf(" %20s", str.c_str());
                    break;
                }
                case type_Binary: {
                    auto bin = obj.get<Binary>(col);
                    printf("   bin size: %8zu", bin.size());
                    break;
                }
                case type_Timestamp: {
                    auto value = obj.get<Timestamp>(col);
                    auto seconds = value.get_seconds();
                    auto tm = gmtime(&seconds);
                    printf("  %4d-%02d-%02d %02d:%02d:%02d", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
                           tm->tm_hour, tm->tm_min, tm->tm_sec);
                    break;
                }
                case type_Link: {
                    printf("      -> %12zx", obj.get<ObjKey>(col).value);
                    break;
                }
                case type_LinkList: {
                    std::stringstream links;
                    links << "[" << std::hex;
                    auto lv = obj.get_linklist(col);
                    auto sz = lv.size();
                    if (sz > 0) {
                        links << lv.get(0).value;
                        for (size_t i = 1; i < sz; i++) {
                            links << "," << lv.get(i).value;
                        }
                    }
                    links << "]" << std::dec;
                    std::string str = links.str();
                    if (str.size() > 20) {
                        str = str.substr(0, 17) + "...";
                    }

                    printf(" %20s", str.c_str());
                    break;
                }
                default:
                    printf(" ********************");
                    break;
            }
        }
        printf("\n");
    }
}

int main(int argc, char const* argv[])
{
    if (argc > 1) {
        Group g(argv[1]);
        auto table_keys = g.get_table_keys();
        for (size_t i = 0; i < table_keys.size(); i++) {
            std::cout << i << ". " << g.get_table_name(table_keys[i]) << " ";
        }
        std::cout << std::endl;
        size_t table_ndx;
        while (get_table_ndx(table_ndx)) {
            auto table = g.get_table(table_keys[table_ndx]);
            auto sz = table->size();
            size_t begin;
            size_t end;
            while (get_range(sz, begin, end)) {
                print_objects(table, begin, end);
            }
        }
    }
    return 0;
}
<|endoftext|>


<commit_before>#include "LayeredWindowInfo.h"

namespace ViWm {
namespace Renderer
{
    LayeredWindowInfo::LayeredWindowInfo( int x, int y, UINT width, UINT height)
        : m_sourcePosition()
        , m_windowPosition()
        , m_blend()
        , m_info()
    {
        m_size.cx = width;
        m_size.cy = height;

        m_sourcePosition.x = 0;
        m_sourcePosition.y = 0;

        m_windowPosition.x = x;
        m_windowPosition.y = y;

        m_blend.BlendOp = AC_SRC_OVER;
        m_blend.BlendFlags = 0;
        m_blend.SourceConstantAlpha = 255;
        m_blend.AlphaFormat = AC_SRC_ALPHA;

        m_info.cbSize = sizeof(UPDATELAYEREDWINDOWINFO);
        m_info.pptSrc = &m_sourcePosition;
        m_info.pptDst = &m_windowPosition;
        m_info.psize = &m_size;
        m_info.pblend = &m_blend;
        m_info.dwFlags = ULW_ALPHA;
    }

    void LayeredWindowInfo::Update( HWND window, HDC source)
    {
        m_info.hdcSrc = source;
        BOOL rez = UpdateLayeredWindowIndirect(window, &m_info);

        if (rez == 0)
            throw;
    }
}}
<commit_msg>Changed UpdateLayered... to use the version available on Windows XP<commit_after>#include "LayeredWindowInfo.h"

namespace ViWm {
namespace Renderer
{
    LayeredWindowInfo::LayeredWindowInfo( int x, int y, UINT width, UINT height)
        : m_sourcePosition()
        , m_windowPosition()
        , m_blend()
        , m_info()
    {
        m_size.cx = width;
        m_size.cy = height;

        m_sourcePosition.x = 0;
        m_sourcePosition.y = 0;

        m_windowPosition.x = x;
        m_windowPosition.y = y;

        m_blend.BlendOp = AC_SRC_OVER;
        m_blend.BlendFlags = 0;
        m_blend.SourceConstantAlpha = 255;
        m_blend.AlphaFormat = AC_SRC_ALPHA;

        m_info.cbSize = sizeof(UPDATELAYEREDWINDOWINFO);
        m_info.pptSrc = &m_sourcePosition;
        m_info.pptDst = &m_windowPosition;
        m_info.psize = &m_size;
        m_info.pblend = &m_blend;
        m_info.dwFlags = ULW_ALPHA;
    }

    void LayeredWindowInfo::Update( HWND window, HDC source)
    {
        m_info.hdcSrc = source;
        BOOL rez = UpdateLayeredWindow( window
                                      , NULL
                                      , &m_windowPosition
                                      , &m_size
                                      , source
                                      , &m_sourcePosition
                                      , 0
                                      , &m_blend
                                      , ULW_ALPHA );

        if (rez == 0)
            throw;
    }
}}
<|endoftext|>