<commit_before>/*
 * Copyright (c) 2013, Red Hat.
 * Copyright (c) 2007-2009, Aconex.  All Rights Reserved.
 *
 * 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 2 of the License, or (at your
 * option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 */
#include "openviewdialog.h"
#include <QtGui/QCompleter>
#include <QtGui/QFileDialog>
#include <QtGui/QMessageBox>
#include "main.h"
#include "hostdialog.h"

OpenViewDialog::OpenViewDialog(QWidget *parent) : QDialog(parent)
{
    setupUi(this);
    my.dirModel = new QDirModel;
    my.dirModel->setIconProvider(fileIconProvider);
    dirListView->setModel(my.dirModel);

    my.completer = new QCompleter;
    my.completer->setModel(my.dirModel);
    fileNameLineEdit->setCompleter(my.completer);

    connect(dirListView->selectionModel(),
	SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
	this, SLOT(dirListView_selectionChanged()));

    QDir dir;
    QChar sep(__pmPathSeparator());
    QString sys = my.systemDir = pmGetConfig("PCP_VAR_DIR");
    my.systemDir.append(sep);
    my.systemDir.append("config");
    my.systemDir.append(sep);
    my.systemDir.append("kmchart");
    if (dir.exists(my.systemDir))
	pathComboBox->addItem(fileIconProvider->icon(QFileIconProvider::Folder),
			  my.systemDir);
    my.systemDir = sys;
    my.systemDir.append(sep);
    my.systemDir.append("config");
    my.systemDir.append(sep);
    my.systemDir.append("pmchart");
    if (dir.exists(my.systemDir))
	pathComboBox->addItem(fileIconProvider->icon(QFileIconProvider::Folder),
			  my.systemDir);

    QString home = my.userDir = QDir::toNativeSeparators(QDir::homePath());
    my.userDir.append(sep);
    my.userDir.append(".pcp");
    my.userDir.append(sep);
    my.userDir.append("kmchart");
    if (dir.exists(my.userDir))
	pathComboBox->addItem(fileIconProvider->icon(QFileIconProvider::Folder),
			  my.userDir);
    my.userDir = home;
    my.userDir.append(sep);
    my.userDir.append(".pcp");
    my.userDir.append(sep);
    my.userDir.append("pmchart");
    if (dir.exists(my.userDir))
	pathComboBox->addItem(fileIconProvider->icon(QFileIconProvider::Folder),
			  my.userDir);

    pathComboBox->addItem(fileIconProvider->icon(QFileIconProvider::Folder),
			  home);
}

OpenViewDialog::~OpenViewDialog()
{
    delete my.completer;
    delete my.dirModel;
}

void OpenViewDialog::reset()
{
    if ((my.archiveSource = pmchart->isArchiveTab())) {
	sourceLabel->setText(tr("Archive:"));
	sourcePushButton->setIcon(QIcon(":/images/archive.png"));
    } else {
	sourceLabel->setText(tr("Host:"));
	sourcePushButton->setIcon(QIcon(":/images/computer.png"));
    }
    setupComboBoxes(my.archiveSource);
    setPath(my.systemDir);
}

void OpenViewDialog::setPathUi(const QString &path)
{
    if (path.isEmpty())
	return;

    int index = pathComboBox->findText(path);
    if (index == -1) {
	pathComboBox->addItem(fileIconProvider->icon(QFileIconProvider::Folder),
				path);
	index = pathComboBox->count() - 1;
    }
    pathComboBox->setCurrentIndex(index);
    dirListView->selectionModel()->clear();

    userToolButton->setChecked(path == my.userDir);
    systemToolButton->setChecked(path == my.systemDir);

    fileNameLineEdit->setModified(false);
    fileNameLineEdit->clear();
}

void OpenViewDialog::setPath(const QModelIndex &index)
{
    console->post("OpenViewDialog::setPath QModelIndex path=%s",
			(const char *)my.dirModel->filePath(index).toAscii());
    my.dirIndex = index;
    my.dirModel->refresh(index);
    dirListView->setRootIndex(index);
    setPathUi(my.dirModel->filePath(index));
}

void OpenViewDialog::setPath(const QString &path)
{
    console->post("OpenViewDialog::setPath QString path=%s",
			(const char *)path.toAscii());
    my.dirIndex = my.dirModel->index(path);
    my.dirModel->refresh(my.dirIndex);
    dirListView->setRootIndex(my.dirIndex);
    setPathUi(path);
}

void OpenViewDialog::pathComboBox_currentIndexChanged(QString path)
{
    console->post("OpenViewDialog::pathComboBox_currentIndexChanged");
    setPath(path);
}

void OpenViewDialog::parentToolButton_clicked()
{
    console->post("OpenViewDialog::parentToolButton_clicked");
    setPath(my.dirModel->parent(my.dirIndex));
}

void OpenViewDialog::userToolButton_clicked(bool enabled)
{
    if (enabled) {
	QDir dir;
	if (!dir.exists(my.userDir))
	    dir.mkpath(my.userDir);
	setPath(my.userDir);
    }
}

void OpenViewDialog::systemToolButton_clicked(bool enabled)
{
    if (enabled)
	setPath(my.systemDir);
}

void OpenViewDialog::dirListView_selectionChanged()
{
    QItemSelectionModel *selections = dirListView->selectionModel();
    QModelIndexList selectedIndexes = selections->selectedIndexes();

    console->post("OpenViewDialog::dirListView_clicked");

    my.completer->setCompletionPrefix(my.dirModel->filePath(my.dirIndex));
    if (selectedIndexes.count() != 1)
	fileNameLineEdit->setText("");
    else
	fileNameLineEdit->setText(my.dirModel->fileName(selectedIndexes.at(0)));
}

void OpenViewDialog::dirListView_activated(const QModelIndex &index)
{
    QFileInfo fi = my.dirModel->fileInfo(index);

    console->post("OpenViewDialog::dirListView_activated");

    if (fi.isDir())
	setPath(index);
    else if (fi.isFile()) {
	QStringList files;
	files << fi.absoluteFilePath();
	if (openViewFiles(files) == true)
	    done(0);
    }
}

int OpenViewDialog::setupArchiveComboBoxes()
{
    QIcon archiveIcon = fileIconProvider->icon(QedFileIconProvider::Archive);
    int index = 0;

    for (unsigned int i = 0; i < archiveGroup->numContexts(); i++) {
	QmcSource source = archiveGroup->context(i)->source();
	sourceComboBox->insertItem(i, archiveIcon, source.source());
	if (i == archiveGroup->contextIndex())
	    index = i;
    }
    return index;
}

int OpenViewDialog::setupLiveComboBoxes()
{
    QIcon containerIcon = fileIconProvider->icon(QedFileIconProvider::Container);
    QIcon hostIcon = fileIconProvider->icon(QFileIconProvider::Computer);
    int index = 0;

    for (unsigned int i = 0; i < liveGroup->numContexts(); i++) {
	QmcSource source = liveGroup->context(i)->source();
	QIcon icon = source.isContainer() ? containerIcon : hostIcon;

	sourceComboBox->insertItem(i, icon, source.hostLabel());
	if (i == liveGroup->contextIndex())
	    index = i;
    }
    return index;
}

void OpenViewDialog::setupComboBoxes(bool arch)
{
    // We block signals on the target combo boxes so that we don't
    // send spurious signals out about their lists being changed.
    // If we did that, we would keep changing the current context.
    sourceComboBox->blockSignals(true);
    sourceComboBox->clear();
    int index = arch ? setupArchiveComboBoxes() : setupLiveComboBoxes();
    sourceComboBox->setCurrentIndex(index);
    sourceComboBox->blockSignals(false);
}

void OpenViewDialog::archiveAdd()
{
    QFileDialog *af = new QFileDialog(this);
    QStringList al;
    int sts;

    af->setFileMode(QFileDialog::ExistingFiles);
    af->setAcceptMode(QFileDialog::AcceptOpen);
    af->setWindowTitle(tr("Add Archive"));
    af->setIconProvider(fileIconProvider);
    af->setDirectory(QDir::toNativeSeparators(QDir::homePath()));

    if (af->exec() == QDialog::Accepted)
	al = af->selectedFiles();
    for (QStringList::Iterator it = al.begin(); it != al.end(); ++it) {
	QString archive = *it;
	if ((sts = archiveGroup->use(PM_CONTEXT_ARCHIVE, archive)) < 0) {
	    archive.prepend(tr("Cannot open PCP archive: "));
	    archive.append(tr("\n"));
	    archive.append(tr(pmErrStr(sts)));
	    QMessageBox::warning(this, pmProgname, archive,
		    QMessageBox::Ok|QMessageBox::Default|QMessageBox::Escape,
		    QMessageBox::NoButton, QMessageBox::NoButton);
	} else {
	    setupComboBoxes(true);
	    archiveGroup->updateBounds();
	    QmcSource source = archiveGroup->context()->source();
	    pmtime->addArchive(source.start(), source.end(),
				source.timezone(), source.host(), false);
	}
    }
    delete af;
}

void OpenViewDialog::hostAdd()
{
    HostDialog *host = new HostDialog(this);

    if (host->exec() == QDialog::Accepted) {
	QString hostspec = host->getHostSpecification();
	int sts, flags = host->getContextFlags();

	if (hostspec == QString::null || hostspec.length() == 0) {
	    hostspec.append(tr("Hostname not specified\n"));
	    QMessageBox::warning(this, pmProgname, hostspec,
		    QMessageBox::Ok|QMessageBox::Default|QMessageBox::Escape,
		    Qt::NoButton, Qt::NoButton);
	} else if ((sts = liveGroup->use(PM_CONTEXT_HOST, hostspec, flags)) < 0) {
	    hostspec.prepend(tr("Cannot connect to host: "));
	    hostspec.append(tr("\n"));
	    hostspec.append(tr(pmErrStr(sts)));
	    QMessageBox::warning(this, pmProgname, hostspec,
		    QMessageBox::Ok|QMessageBox::Default|QMessageBox::Escape,
		    Qt::NoButton, Qt::NoButton);
	} else {
	    console->post(PmChart::DebugUi,
			"OpenViewDialog::newHost: %s (flags=0x%x)",
			(const char *)hostspec.toAscii(), flags);
	    setupComboBoxes(false);
	}
    }
    delete host;
}

void OpenViewDialog::sourcePushButton_clicked()
{
    if (my.archiveSource)
	archiveAdd();
    else
	hostAdd();
}

void OpenViewDialog::sourceComboBox_currentIndexChanged(int index)
{
    console->post("OpenViewDialog::sourceComboBox_currentIndexChanged %d", index);
    if (my.archiveSource == false)
	liveGroup->use((unsigned int)index);
    else
	archiveGroup->use((unsigned int)index);
}

bool OpenViewDialog::useLiveContext(int index)
{
    QmcSource source = liveGroup->context(index)->source();
    char *sourceName = source.sourceAscii();
    bool result = true;
    int sts;

    if ((sts = liveGroup->use(PM_CONTEXT_HOST, source.source())) < 0) {
	QString msg;
	msg.sprintf("Failed to connect to pmcd on \"%s\".\n%s.\n\n",
		    sourceName, pmErrStr(sts));
	QMessageBox::warning(NULL, pmProgname, msg,
		QMessageBox::Ok | QMessageBox::Default | QMessageBox::Escape,
		QMessageBox::NoButton, QMessageBox::NoButton);
	result = false;
    }
    free(sourceName);
    return result;
}

bool OpenViewDialog::useArchiveContext(int index)
{
    QmcSource source = archiveGroup->context(index)->source();
    char *sourceName = source.sourceAscii();
    bool result = true;
    int sts;

    if ((sts = archiveGroup->use(PM_CONTEXT_ARCHIVE, source.source())) < 0) {
	QString msg;
	msg.sprintf("Failed to open archive \"%s\".\n%s.\n\n",
		    sourceName, pmErrStr(sts));
	QMessageBox::warning(NULL, pmProgname, msg,
		QMessageBox::Ok | QMessageBox::Default | QMessageBox::Escape,
		QMessageBox::NoButton, QMessageBox::NoButton);
	result = false;
    }
    free(sourceName);
    return result;
}

bool OpenViewDialog::useComboBoxContext(bool arch)
{
    if (arch == false)
	return useLiveContext(sourceComboBox->currentIndex());
    else
	return useArchiveContext(sourceComboBox->currentIndex());
}

bool OpenViewDialog::openViewFiles(const QStringList &fl)
{
    QString msg;
    bool result = true;

    if (pmchart->isArchiveTab() != my.archiveSource) {
	if (pmchart->isArchiveTab())
	    msg = tr("Cannot open Host View(s) in an Archive Tab\n");
	else
	    msg = tr("Cannot open Archive View(s) in a Host Tab\n");
	QMessageBox::warning(this, pmProgname, msg,
	    QMessageBox::Ok|QMessageBox::Default|QMessageBox::Escape,
	    QMessageBox::NoButton, QMessageBox::NoButton);
	return false;
    }
    if (useComboBoxContext(my.archiveSource) == false)
	return false;
    QStringList files = fl;
    for (QStringList::Iterator it = files.begin(); it != files.end(); ++it)
	if (openView((const char *)(*it).toAscii()) == false)
	    result = false;
    pmchart->enableUi();
    return result;
}

void OpenViewDialog::openPushButton_clicked()
{
    QStringList files;
    QString msg;

    if (fileNameLineEdit->isModified()) {
	QString filename = fileNameLineEdit->text().trimmed();
	if (filename.isEmpty())
	    msg = tr("No View file(s) specified");
	else {
	    QFileInfo f(filename);
	    if (f.isDir()) {
		setPath(filename);
	    }
	    else if (f.exists()) {
		files << filename;
		if (openViewFiles(files) == true)
		    done(0);
	    }
	    else {
		msg = tr("No such View file exists:\n");
		msg.append(filename);
	    }
	}
    }
    else {
	QItemSelectionModel *selections = dirListView->selectionModel();
	QModelIndexList selectedIndexes = selections->selectedIndexes();

	if (selectedIndexes.count() == 0)
	    msg = tr("No View file(s) selected");
	else {
	    for (int i = 0; i < selectedIndexes.count(); i++) {
		QString filename = my.dirModel->filePath(selectedIndexes.at(i));
		QFileInfo f(filename);
		if (f.isDir())
		    continue;
		files << filename;
	    }
	    if (files.size() > 0)
		if (openViewFiles(files) == true)
		    done(0);
	}
    }

    if (msg.isEmpty() == false) {
	QMessageBox::warning(this, pmProgname, msg,
	    QMessageBox::Ok|QMessageBox::Default|QMessageBox::Escape,
	    QMessageBox::NoButton, QMessageBox::NoButton);
    }
}
<commit_msg>pmchart: fix SIGSEGV from opening a view when no archive available<commit_after>/*
 * Copyright (c) 2013, Red Hat.
 * Copyright (c) 2007-2009, Aconex.  All Rights Reserved.
 *
 * 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 2 of the License, or (at your
 * option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 */
#include "openviewdialog.h"
#include <QtGui/QCompleter>
#include <QtGui/QFileDialog>
#include <QtGui/QMessageBox>
#include "main.h"
#include "hostdialog.h"

OpenViewDialog::OpenViewDialog(QWidget *parent) : QDialog(parent)
{
    setupUi(this);
    my.dirModel = new QDirModel;
    my.dirModel->setIconProvider(fileIconProvider);
    dirListView->setModel(my.dirModel);

    my.completer = new QCompleter;
    my.completer->setModel(my.dirModel);
    fileNameLineEdit->setCompleter(my.completer);

    connect(dirListView->selectionModel(),
	SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
	this, SLOT(dirListView_selectionChanged()));

    QDir dir;
    QChar sep(__pmPathSeparator());
    QString sys = my.systemDir = pmGetConfig("PCP_VAR_DIR");
    my.systemDir.append(sep);
    my.systemDir.append("config");
    my.systemDir.append(sep);
    my.systemDir.append("kmchart");
    if (dir.exists(my.systemDir))
	pathComboBox->addItem(fileIconProvider->icon(QFileIconProvider::Folder),
			  my.systemDir);
    my.systemDir = sys;
    my.systemDir.append(sep);
    my.systemDir.append("config");
    my.systemDir.append(sep);
    my.systemDir.append("pmchart");
    if (dir.exists(my.systemDir))
	pathComboBox->addItem(fileIconProvider->icon(QFileIconProvider::Folder),
			  my.systemDir);

    QString home = my.userDir = QDir::toNativeSeparators(QDir::homePath());
    my.userDir.append(sep);
    my.userDir.append(".pcp");
    my.userDir.append(sep);
    my.userDir.append("kmchart");
    if (dir.exists(my.userDir))
	pathComboBox->addItem(fileIconProvider->icon(QFileIconProvider::Folder),
			  my.userDir);
    my.userDir = home;
    my.userDir.append(sep);
    my.userDir.append(".pcp");
    my.userDir.append(sep);
    my.userDir.append("pmchart");
    if (dir.exists(my.userDir))
	pathComboBox->addItem(fileIconProvider->icon(QFileIconProvider::Folder),
			  my.userDir);

    pathComboBox->addItem(fileIconProvider->icon(QFileIconProvider::Folder),
			  home);
}

OpenViewDialog::~OpenViewDialog()
{
    delete my.completer;
    delete my.dirModel;
}

void OpenViewDialog::reset()
{
    if ((my.archiveSource = pmchart->isArchiveTab())) {
	sourceLabel->setText(tr("Archive:"));
	sourcePushButton->setIcon(QIcon(":/images/archive.png"));
    } else {
	sourceLabel->setText(tr("Host:"));
	sourcePushButton->setIcon(QIcon(":/images/computer.png"));
    }
    setupComboBoxes(my.archiveSource);
    setPath(my.systemDir);
}

void OpenViewDialog::setPathUi(const QString &path)
{
    if (path.isEmpty())
	return;

    int index = pathComboBox->findText(path);
    if (index == -1) {
	pathComboBox->addItem(fileIconProvider->icon(QFileIconProvider::Folder),
				path);
	index = pathComboBox->count() - 1;
    }
    pathComboBox->setCurrentIndex(index);
    dirListView->selectionModel()->clear();

    userToolButton->setChecked(path == my.userDir);
    systemToolButton->setChecked(path == my.systemDir);

    fileNameLineEdit->setModified(false);
    fileNameLineEdit->clear();
}

void OpenViewDialog::setPath(const QModelIndex &index)
{
    console->post("OpenViewDialog::setPath QModelIndex path=%s",
			(const char *)my.dirModel->filePath(index).toAscii());
    my.dirIndex = index;
    my.dirModel->refresh(index);
    dirListView->setRootIndex(index);
    setPathUi(my.dirModel->filePath(index));
}

void OpenViewDialog::setPath(const QString &path)
{
    console->post("OpenViewDialog::setPath QString path=%s",
			(const char *)path.toAscii());
    my.dirIndex = my.dirModel->index(path);
    my.dirModel->refresh(my.dirIndex);
    dirListView->setRootIndex(my.dirIndex);
    setPathUi(path);
}

void OpenViewDialog::pathComboBox_currentIndexChanged(QString path)
{
    console->post("OpenViewDialog::pathComboBox_currentIndexChanged");
    setPath(path);
}

void OpenViewDialog::parentToolButton_clicked()
{
    console->post("OpenViewDialog::parentToolButton_clicked");
    setPath(my.dirModel->parent(my.dirIndex));
}

void OpenViewDialog::userToolButton_clicked(bool enabled)
{
    if (enabled) {
	QDir dir;
	if (!dir.exists(my.userDir))
	    dir.mkpath(my.userDir);
	setPath(my.userDir);
    }
}

void OpenViewDialog::systemToolButton_clicked(bool enabled)
{
    if (enabled)
	setPath(my.systemDir);
}

void OpenViewDialog::dirListView_selectionChanged()
{
    QItemSelectionModel *selections = dirListView->selectionModel();
    QModelIndexList selectedIndexes = selections->selectedIndexes();

    console->post("OpenViewDialog::dirListView_clicked");

    my.completer->setCompletionPrefix(my.dirModel->filePath(my.dirIndex));
    if (selectedIndexes.count() != 1)
	fileNameLineEdit->setText("");
    else
	fileNameLineEdit->setText(my.dirModel->fileName(selectedIndexes.at(0)));
}

void OpenViewDialog::dirListView_activated(const QModelIndex &index)
{
    QFileInfo fi = my.dirModel->fileInfo(index);

    console->post("OpenViewDialog::dirListView_activated");

    if (fi.isDir())
	setPath(index);
    else if (fi.isFile()) {
	QStringList files;
	files << fi.absoluteFilePath();
	if (openViewFiles(files) == true)
	    done(0);
    }
}

int OpenViewDialog::setupArchiveComboBoxes()
{
    QIcon archiveIcon = fileIconProvider->icon(QedFileIconProvider::Archive);
    int index = 0;

    for (unsigned int i = 0; i < archiveGroup->numContexts(); i++) {
	QmcSource source = archiveGroup->context(i)->source();
	sourceComboBox->insertItem(i, archiveIcon, source.source());
	if (i == archiveGroup->contextIndex())
	    index = i;
    }
    return index;
}

int OpenViewDialog::setupLiveComboBoxes()
{
    QIcon containerIcon = fileIconProvider->icon(QedFileIconProvider::Container);
    QIcon hostIcon = fileIconProvider->icon(QFileIconProvider::Computer);
    int index = 0;

    for (unsigned int i = 0; i < liveGroup->numContexts(); i++) {
	QmcSource source = liveGroup->context(i)->source();
	QIcon icon = source.isContainer() ? containerIcon : hostIcon;

	sourceComboBox->insertItem(i, icon, source.hostLabel());
	if (i == liveGroup->contextIndex())
	    index = i;
    }
    return index;
}

void OpenViewDialog::setupComboBoxes(bool arch)
{
    // We block signals on the target combo boxes so that we don't
    // send spurious signals out about their lists being changed.
    // If we did that, we would keep changing the current context.
    sourceComboBox->blockSignals(true);
    sourceComboBox->clear();
    int index = arch ? setupArchiveComboBoxes() : setupLiveComboBoxes();
    sourceComboBox->setCurrentIndex(index);
    sourceComboBox->blockSignals(false);
}

void OpenViewDialog::archiveAdd()
{
    QFileDialog *af = new QFileDialog(this);
    QStringList al;
    int sts;

    af->setFileMode(QFileDialog::ExistingFiles);
    af->setAcceptMode(QFileDialog::AcceptOpen);
    af->setWindowTitle(tr("Add Archive"));
    af->setIconProvider(fileIconProvider);
    af->setDirectory(QDir::toNativeSeparators(QDir::homePath()));

    if (af->exec() == QDialog::Accepted)
	al = af->selectedFiles();
    for (QStringList::Iterator it = al.begin(); it != al.end(); ++it) {
	QString archive = *it;
	if ((sts = archiveGroup->use(PM_CONTEXT_ARCHIVE, archive)) < 0) {
	    archive.prepend(tr("Cannot open PCP archive: "));
	    archive.append(tr("\n"));
	    archive.append(tr(pmErrStr(sts)));
	    QMessageBox::warning(this, pmProgname, archive,
		    QMessageBox::Ok|QMessageBox::Default|QMessageBox::Escape,
		    QMessageBox::NoButton, QMessageBox::NoButton);
	} else {
	    setupComboBoxes(true);
	    archiveGroup->updateBounds();
	    QmcSource source = archiveGroup->context()->source();
	    pmtime->addArchive(source.start(), source.end(),
				source.timezone(), source.host(), false);
	}
    }
    delete af;
}

void OpenViewDialog::hostAdd()
{
    HostDialog *host = new HostDialog(this);

    if (host->exec() == QDialog::Accepted) {
	QString hostspec = host->getHostSpecification();
	int sts, flags = host->getContextFlags();

	if (hostspec == QString::null || hostspec.length() == 0) {
	    hostspec.append(tr("Hostname not specified\n"));
	    QMessageBox::warning(this, pmProgname, hostspec,
		    QMessageBox::Ok|QMessageBox::Default|QMessageBox::Escape,
		    Qt::NoButton, Qt::NoButton);
	} else if ((sts = liveGroup->use(PM_CONTEXT_HOST, hostspec, flags)) < 0) {
	    hostspec.prepend(tr("Cannot connect to host: "));
	    hostspec.append(tr("\n"));
	    hostspec.append(tr(pmErrStr(sts)));
	    QMessageBox::warning(this, pmProgname, hostspec,
		    QMessageBox::Ok|QMessageBox::Default|QMessageBox::Escape,
		    Qt::NoButton, Qt::NoButton);
	} else {
	    console->post(PmChart::DebugUi,
			"OpenViewDialog::newHost: %s (flags=0x%x)",
			(const char *)hostspec.toAscii(), flags);
	    setupComboBoxes(false);
	}
    }
    delete host;
}

void OpenViewDialog::sourcePushButton_clicked()
{
    if (my.archiveSource)
	archiveAdd();
    else
	hostAdd();
}

void OpenViewDialog::sourceComboBox_currentIndexChanged(int index)
{
    console->post("OpenViewDialog::sourceComboBox_currentIndexChanged %d", index);
    if (my.archiveSource == false)
	liveGroup->use((unsigned int)index);
    else
	archiveGroup->use((unsigned int)index);
}

bool OpenViewDialog::useLiveContext(int index)
{
    if (liveGroup->numContexts() == 0) {
	QString msg("No host connections have been established yet\n");
	QMessageBox::warning(NULL, pmProgname, msg,
		QMessageBox::Ok | QMessageBox::Default | QMessageBox::Escape,
		QMessageBox::NoButton, QMessageBox::NoButton);
	return false;
    }

    Q_ASSERT(index <= liveGroup->numContexts());
    QmcSource source = liveGroup->context(index)->source();
    char *sourceName = source.sourceAscii();
    bool result = true;
    int sts;

    if ((sts = liveGroup->use(PM_CONTEXT_HOST, source.source())) < 0) {
	QString msg;
	msg.sprintf("Failed to connect to pmcd on \"%s\".\n%s.\n\n",
		    sourceName, pmErrStr(sts));
	QMessageBox::warning(NULL, pmProgname, msg,
		QMessageBox::Ok | QMessageBox::Default | QMessageBox::Escape,
		QMessageBox::NoButton, QMessageBox::NoButton);
	result = false;
    }
    free(sourceName);
    return result;
}

bool OpenViewDialog::useArchiveContext(int index)
{
    if (archiveGroup->numContexts() == 0) {
	QString msg("No PCP archives have been opened yet\n");
	QMessageBox::warning(NULL, pmProgname, msg,
		QMessageBox::Ok | QMessageBox::Default | QMessageBox::Escape,
		QMessageBox::NoButton, QMessageBox::NoButton);
	return false;
    }

    Q_ASSERT(index <= archiveGroup->numContexts());
    QmcSource source = archiveGroup->context(index)->source();
    char *sourceName = source.sourceAscii();
    bool result = true;
    int sts;

    if ((sts = archiveGroup->use(PM_CONTEXT_ARCHIVE, source.source())) < 0) {
	QString msg;
	msg.sprintf("Failed to open archive \"%s\".\n%s.\n\n",
		    sourceName, pmErrStr(sts));
	QMessageBox::warning(NULL, pmProgname, msg,
		QMessageBox::Ok | QMessageBox::Default | QMessageBox::Escape,
		QMessageBox::NoButton, QMessageBox::NoButton);
	result = false;
    }
    free(sourceName);
    return result;
}

bool OpenViewDialog::useComboBoxContext(bool arch)
{
    if (arch == false)
	return useLiveContext(sourceComboBox->currentIndex());
    else
	return useArchiveContext(sourceComboBox->currentIndex());
}

bool OpenViewDialog::openViewFiles(const QStringList &fl)
{
    QString msg;
    bool result = true;

    if (pmchart->isArchiveTab() != my.archiveSource) {
	if (pmchart->isArchiveTab())
	    msg = tr("Cannot open Host View(s) in an Archive Tab\n");
	else
	    msg = tr("Cannot open Archive View(s) in a Host Tab\n");
	QMessageBox::warning(this, pmProgname, msg,
	    QMessageBox::Ok|QMessageBox::Default|QMessageBox::Escape,
	    QMessageBox::NoButton, QMessageBox::NoButton);
	return false;
    }
    if (useComboBoxContext(my.archiveSource) == false)
	return false;
    QStringList files = fl;
    for (QStringList::Iterator it = files.begin(); it != files.end(); ++it)
	if (openView((const char *)(*it).toAscii()) == false)
	    result = false;
    pmchart->enableUi();
    return result;
}

void OpenViewDialog::openPushButton_clicked()
{
    QStringList files;
    QString msg;

    if (fileNameLineEdit->isModified()) {
	QString filename = fileNameLineEdit->text().trimmed();
	if (filename.isEmpty())
	    msg = tr("No View file(s) specified");
	else {
	    QFileInfo f(filename);
	    if (f.isDir()) {
		setPath(filename);
	    }
	    else if (f.exists()) {
		files << filename;
		if (openViewFiles(files) == true)
		    done(0);
	    }
	    else {
		msg = tr("No such View file exists:\n");
		msg.append(filename);
	    }
	}
    }
    else {
	QItemSelectionModel *selections = dirListView->selectionModel();
	QModelIndexList selectedIndexes = selections->selectedIndexes();

	if (selectedIndexes.count() == 0)
	    msg = tr("No View file(s) selected");
	else {
	    for (int i = 0; i < selectedIndexes.count(); i++) {
		QString filename = my.dirModel->filePath(selectedIndexes.at(i));
		QFileInfo f(filename);
		if (f.isDir())
		    continue;
		files << filename;
	    }
	    if (files.size() > 0)
		if (openViewFiles(files) == true)
		    done(0);
	}
    }

    if (msg.isEmpty() == false) {
	QMessageBox::warning(this, pmProgname, msg,
	    QMessageBox::Ok|QMessageBox::Default|QMessageBox::Escape,
	    QMessageBox::NoButton, QMessageBox::NoButton);
    }
}
<|endoftext|>


<commit_before>/**************************************************************************/
/**
**  ChildRInterface.cpp: This is the C++ source file for ChildRInterface, which
**    provides a generalized, OpenMI-style interface to the release
**    version of the CHILD
**    landscape evolution model.
**
**  For information regarding this program, please contact Greg Tucker at:
**
**     Cooperative Institute for Research in Environmental Sciences (CIRES)
**     and Department of Geological Sciences
**     University of Colorado
**     2200 Colorado Avenue, Campus Box 399
**     Boulder, CO 80309-0399
**
*/
/**************************************************************************/

#include "childRInterface.h"

Predicates predicate;

/**************************************************************************/
/**
**  Default constructor for childInterface
**
**  Sets pointers to NULL and initialized flag to false.
*/
/**************************************************************************/
childRInterface::
childRInterface()
{
	initialized = false;

	rand = NULL;
	mesh  = NULL;
	output = NULL;
	storm = NULL;
	strmNet = NULL;
	erosion = NULL;
	uplift = NULL;
	time = NULL;
	stratGrid = NULL;
	loess = NULL;
	vegetation = NULL;
}

/**************************************************************************/
/**
**  Initialize
**
**  This method accesses the input file given on the command line (and
**  passed via the parameters argc and argv), and creates the necessary
**  objects.
*/
/**************************************************************************/
void childRInterface::
Initialize( int argc, char **argv )
{

   /****************** INITIALIZATION *************************************\
   **  ALGORITHM
   **    Get command-line arguments (name of input file + any other opts)
   **    Set silent_mode flag
   **    Open main input file
   **    Create and initialize objects for...
   **      Mesh
   **      Output files
   **      Storm
   **      Stream network
   **      Erosion
   **      Uplift (or baselevel change)
   **      Run timer
   **    Write output for initial state
   **    Get options for erosion type, meandering, etc.
   \**********************************************************************/

   // Check command-line arguments
   tOption option( argc, argv );

   // Say hello
   option.version();

   // Open main input file
   tInputFile inputFile( option.inputFile );

   // Create a random number generator for the simulation itself
   rand = new tRand( inputFile );

   // Create and initialize objects:
   std::cout << "Creating mesh...\n";
   mesh = new tMesh<tLNode>( inputFile, option.checkMeshConsistency );

   std::cout << "Creating output files...\n";
   output = new tLOutput<tLNode>( mesh, inputFile, rand );

   storm = new tStorm( inputFile, rand );

   std::cout << "Creating stream network...\n";
   strmNet = new tStreamNet( *mesh, *storm, inputFile );
   erosion = new tErosion( mesh, inputFile );
   uplift = new tUplift( inputFile );

   // Get various options
   optDetachLim = inputFile.ReadBool( "OPTDETACHLIM" );
   optFloodplainDep = 0; // Floodplain module not linked into this release version
   optDiffuseDepo = inputFile.ReadBool( "OPTDIFFDEP" );
   optLoessDep = inputFile.ReadBool( "OPTLOESSDEP" );
   optStratGrid = inputFile.ReadBool( "OPTSTRATGRID" ,false);
   optNonlinearDiffusion = inputFile.ReadBool( "OPT_NONLINEAR_DIFFUSION", false );
   optVegetation = inputFile.ReadBool( "OPTVEG" );

   // If applicable, create Vegetation object
   if( optVegetation )
       vegetation = new tVegetation( mesh, inputFile );

   // If applicable, create eolian deposition object
   if( optLoessDep )
       loess = new tEolian( inputFile );

   // If applicable, create Stratigraphy Grid object
   // and pass it to output
   if( optStratGrid ) {
     if (!optFloodplainDep)
       ReportFatalError("OPTFLOODPLAIN must be enabled.");
     stratGrid = new tStratGrid (inputFile, mesh);
     output->SetStratGrid( stratGrid, strmNet );
   }

   std::cout << "Writing data for time zero...\n";
   time = new tRunTimer( inputFile, !option.silent_mode );
   output->WriteOutput( 0. );
   initialized = true;
   std::cout << "Initialization done.\n";

}

/**************************************************************************/
/**
**  RunOneStorm
**
**  This method executes the model for one storm, calling each of several
**  subroutines in turn. It returns the updated simulation time.
*/
/**************************************************************************/

double childRInterface::
RunOneStorm()
{

	/**************** Run 1 storm ****************************************\
	**  ALGORITHM
	**    Generate storm
	**    Do storm...
	**      Update network (flow directions, drainage area, runoff)
	**      Water erosion/deposition (vertical)
	**    Do interstorm...
	**      Hillslope transport
	**      Exposure history
	**      Mesh densification (if applicable)
	**      Eolian (loess) deposition (if applicable)
	**      Uplift (or baselevel change)
	**********************************************************************/
	if(0) //debug
      	std::cout << "         " << std::endl;
	time->ReportTimeStatus();

	// Do storm...
	storm->GenerateStorm( time->getCurrentTime(),
						  strmNet->getInfilt(), strmNet->getSoilStore() );
	strmNet->UpdateNet( time->getCurrentTime(), *storm );

	// Link tLNodes to StratNodes, adjust elevation StratNode to surrounding tLNodes
	if( optStratGrid )
		stratGrid->UpdateStratGrid(tStratGrid::k0, time->getCurrentTime());

	//Diffusion is now before fluvial erosion in case the tools
	//detachment laws are being used.
	if( optNonlinearDiffusion )
		erosion->DiffuseNonlinear( storm->getStormDuration() + storm->interstormDur(),
								   optDiffuseDepo );
	else
		erosion->Diffuse( storm->getStormDuration() + storm->interstormDur(),
						  optDiffuseDepo );

	if( optDetachLim )
		erosion->ErodeDetachLim( storm->getStormDuration(), strmNet,
								 vegetation );
	else{
		erosion->DetachErode( storm->getStormDuration(), strmNet,
							  time->getCurrentTime(), vegetation );
		// To use tools rules, you must use DetachErode2 NMG 07/05
		//erosion.DetachErode2( storm.getStormDuration(), &strmNet,
		//                      time.getCurrentTime(), vegetation );
	}

	// Link tLNodes to StratNodes, adjust elevation StratNode to surrounding tLNodes
	if( optStratGrid )
		stratGrid->UpdateStratGrid(tStratGrid::k1,time->getCurrentTime() );

#define NEWVEG 1
	if( optVegetation ) {
		if( NEWVEG )
			vegetation->GrowVegetation( mesh, storm->interstormDur() );
		else
			vegetation->UpdateVegetation( mesh, storm->getStormDuration(),
										  storm->interstormDur() );
	}
#undef NEWVEG

	erosion->UpdateExposureTime( storm->getStormDuration() +
								 storm->interstormDur() );

	if( optLoessDep )
		loess->DepositLoess( mesh,
							 storm->getStormDuration()+storm->interstormDur(),
							 time->getCurrentTime() );

	if( time->getCurrentTime() < uplift->getDuration() )
		uplift->DoUplift( mesh,
						  storm->getStormDuration() + storm->interstormDur(),
						  time->getCurrentTime() );

	time->Advance( storm->getStormDuration() + storm->interstormDur() );

	if( time->CheckOutputTime() )
		output->WriteOutput( time->getCurrentTime() );

	if( output->OptTSOutput() ) output->WriteTSOutput();

	return( time->getCurrentTime() );
}

/**************************************************************************/
/**
**  Run
**
**  This method runs CHILD for a duration specified on the command line or,
**  if that duration is <=0, for the duration specified in the previously
**  read input file.
*/
/**************************************************************************/

void childRInterface::
Run( double run_duration )
{
	if( initialized==false )
		ReportFatalError( "childInterface must be initialized (with Initialize() method) before Run() method is called." );

	if( run_duration>0.0 )
		time->Start( time->getCurrentTime(), time->getCurrentTime()+run_duration );

   while( !time->IsFinished() )
		RunOneStorm();

}

/**************************************************************************/
/**
**  CleanUp
**
**  This method deletes the various objects created. Note that this
**  function is called by the destructor, so if a user function calls it
**  explicitly, it will end up being called twice.
*/
/**************************************************************************/

void childRInterface::
CleanUp()
{
	if( rand ) {
		delete rand;
		rand = NULL;
	}
	if( mesh ) {
		delete mesh;
		mesh = NULL;
	}
	if( output ) {
		delete output;
		output = NULL;
	}
	if( storm ) {
		delete storm;
		storm = NULL;
	}
	if( strmNet ) {
		delete strmNet;
		strmNet = NULL;
	}
	if( erosion ) {
		delete erosion;
		erosion = NULL;
	}
	if( uplift ) {
		delete uplift;
		uplift = NULL;
	}
	if( time ) {
		delete time;
		time = NULL;
	}
	if( optVegetation && vegetation ) {
		delete vegetation;
		vegetation = NULL;
	}
	if( optLoessDep && loess ) {
		delete loess;
		loess = NULL;
	}
	if( optStratGrid && stratGrid ) {
		delete stratGrid;
		stratGrid = NULL;
	}
	initialized = false;
}

childRInterface::
~childRInterface()
{
	CleanUp();
}

/**************************************************************************/
/**
**  childInterface::ExternalErosionAndDeposition
**
**  This function allows a calling program to tell CHILD to perform a
**  given depth of erosion and/or sedimentation at each node.
**
**  Presently, it is set up without any grain-size information. A future
**  version could also pass grain-size information.
**
**  GT, June 09
*/
/**************************************************************************/

void childRInterface::ExternalErosionAndDeposition( vector<double> dz )
{
  tMesh< tLNode >::nodeListIter_t mli( mesh->getNodeList() );  // gets nodes from the list
  tLNode * cn;
  for( cn=mli.FirstP(); mli.IsActive(); cn=mli.NextP() )
  {
    int current_id = cn->getPermID();
    cn->EroDep( dz[current_id] );
  }
}

<commit_msg>added time->getCurrentTime() to Diffuse calls in childRInterface<commit_after>/**************************************************************************/
/**
**  ChildRInterface.cpp: This is the C++ source file for ChildRInterface, which
**    provides a generalized, OpenMI-style interface to the release
**    version of the CHILD
**    landscape evolution model.
**
**  For information regarding this program, please contact Greg Tucker at:
**
**     Cooperative Institute for Research in Environmental Sciences (CIRES)
**     and Department of Geological Sciences
**     University of Colorado
**     2200 Colorado Avenue, Campus Box 399
**     Boulder, CO 80309-0399
**
*/
/**************************************************************************/

#include "childRInterface.h"

Predicates predicate;

/**************************************************************************/
/**
**  Default constructor for childInterface
**
**  Sets pointers to NULL and initialized flag to false.
*/
/**************************************************************************/
childRInterface::
childRInterface()
{
	initialized = false;

	rand = NULL;
	mesh  = NULL;
	output = NULL;
	storm = NULL;
	strmNet = NULL;
	erosion = NULL;
	uplift = NULL;
	time = NULL;
	stratGrid = NULL;
	loess = NULL;
	vegetation = NULL;
}

/**************************************************************************/
/**
**  Initialize
**
**  This method accesses the input file given on the command line (and
**  passed via the parameters argc and argv), and creates the necessary
**  objects.
*/
/**************************************************************************/
void childRInterface::
Initialize( int argc, char **argv )
{

   /****************** INITIALIZATION *************************************\
   **  ALGORITHM
   **    Get command-line arguments (name of input file + any other opts)
   **    Set silent_mode flag
   **    Open main input file
   **    Create and initialize objects for...
   **      Mesh
   **      Output files
   **      Storm
   **      Stream network
   **      Erosion
   **      Uplift (or baselevel change)
   **      Run timer
   **    Write output for initial state
   **    Get options for erosion type, meandering, etc.
   \**********************************************************************/

   // Check command-line arguments
   tOption option( argc, argv );

   // Say hello
   option.version();

   // Open main input file
   tInputFile inputFile( option.inputFile );

   // Create a random number generator for the simulation itself
   rand = new tRand( inputFile );

   // Create and initialize objects:
   std::cout << "Creating mesh...\n";
   mesh = new tMesh<tLNode>( inputFile, option.checkMeshConsistency );

   std::cout << "Creating output files...\n";
   output = new tLOutput<tLNode>( mesh, inputFile, rand );

   storm = new tStorm( inputFile, rand );

   std::cout << "Creating stream network...\n";
   strmNet = new tStreamNet( *mesh, *storm, inputFile );
   erosion = new tErosion( mesh, inputFile );
   uplift = new tUplift( inputFile );

   // Get various options
   optDetachLim = inputFile.ReadBool( "OPTDETACHLIM" );
   optFloodplainDep = 0; // Floodplain module not linked into this release version
   optDiffuseDepo = inputFile.ReadBool( "OPTDIFFDEP" );
   optLoessDep = inputFile.ReadBool( "OPTLOESSDEP" );
   optStratGrid = inputFile.ReadBool( "OPTSTRATGRID" ,false);
   optNonlinearDiffusion = inputFile.ReadBool( "OPT_NONLINEAR_DIFFUSION", false );
   optVegetation = inputFile.ReadBool( "OPTVEG" );

   // If applicable, create Vegetation object
   if( optVegetation )
       vegetation = new tVegetation( mesh, inputFile );

   // If applicable, create eolian deposition object
   if( optLoessDep )
       loess = new tEolian( inputFile );

   // If applicable, create Stratigraphy Grid object
   // and pass it to output
   if( optStratGrid ) {
     if (!optFloodplainDep)
       ReportFatalError("OPTFLOODPLAIN must be enabled.");
     stratGrid = new tStratGrid (inputFile, mesh);
     output->SetStratGrid( stratGrid, strmNet );
   }

   std::cout << "Writing data for time zero...\n";
   time = new tRunTimer( inputFile, !option.silent_mode );
   output->WriteOutput( 0. );
   initialized = true;
   std::cout << "Initialization done.\n";

}

/**************************************************************************/
/**
**  RunOneStorm
**
**  This method executes the model for one storm, calling each of several
**  subroutines in turn. It returns the updated simulation time.
*/
/**************************************************************************/

double childRInterface::
RunOneStorm()
{

	/**************** Run 1 storm ****************************************\
	**  ALGORITHM
	**    Generate storm
	**    Do storm...
	**      Update network (flow directions, drainage area, runoff)
	**      Water erosion/deposition (vertical)
	**    Do interstorm...
	**      Hillslope transport
	**      Exposure history
	**      Mesh densification (if applicable)
	**      Eolian (loess) deposition (if applicable)
	**      Uplift (or baselevel change)
	**********************************************************************/
	if(0) //debug
      	std::cout << "         " << std::endl;
	time->ReportTimeStatus();

	// Do storm...
	storm->GenerateStorm( time->getCurrentTime(),
						  strmNet->getInfilt(), strmNet->getSoilStore() );
	strmNet->UpdateNet( time->getCurrentTime(), *storm );

	// Link tLNodes to StratNodes, adjust elevation StratNode to surrounding tLNodes
	if( optStratGrid )
		stratGrid->UpdateStratGrid(tStratGrid::k0, time->getCurrentTime());

	//Diffusion is now before fluvial erosion in case the tools
	//detachment laws are being used.
	if( optNonlinearDiffusion )
		erosion->DiffuseNonlinear( storm->getStormDuration() + storm->interstormDur(),
								   optDiffuseDepo, time->getCurrentTime() );
	else
		erosion->Diffuse( storm->getStormDuration() + storm->interstormDur(),
						  optDiffuseDepo, time->getCurrentTime() );

	if( optDetachLim )
		erosion->ErodeDetachLim( storm->getStormDuration(), strmNet,
								 vegetation );
	else{
		erosion->DetachErode( storm->getStormDuration(), strmNet,
							  time->getCurrentTime(), vegetation );
		// To use tools rules, you must use DetachErode2 NMG 07/05
		//erosion.DetachErode2( storm.getStormDuration(), &strmNet,
		//                      time.getCurrentTime(), vegetation );
	}

	// Link tLNodes to StratNodes, adjust elevation StratNode to surrounding tLNodes
	if( optStratGrid )
		stratGrid->UpdateStratGrid(tStratGrid::k1,time->getCurrentTime() );

#define NEWVEG 1
	if( optVegetation ) {
		if( NEWVEG )
			vegetation->GrowVegetation( mesh, storm->interstormDur() );
		else
			vegetation->UpdateVegetation( mesh, storm->getStormDuration(),
										  storm->interstormDur() );
	}
#undef NEWVEG

	erosion->UpdateExposureTime( storm->getStormDuration() +
								 storm->interstormDur() );

	if( optLoessDep )
		loess->DepositLoess( mesh,
							 storm->getStormDuration()+storm->interstormDur(),
							 time->getCurrentTime() );

	if( time->getCurrentTime() < uplift->getDuration() )
		uplift->DoUplift( mesh,
						  storm->getStormDuration() + storm->interstormDur(),
						  time->getCurrentTime() );

	time->Advance( storm->getStormDuration() + storm->interstormDur() );

	if( time->CheckOutputTime() )
		output->WriteOutput( time->getCurrentTime() );

	if( output->OptTSOutput() ) output->WriteTSOutput();

	return( time->getCurrentTime() );
}

/**************************************************************************/
/**
**  Run
**
**  This method runs CHILD for a duration specified on the command line or,
**  if that duration is <=0, for the duration specified in the previously
**  read input file.
*/
/**************************************************************************/

void childRInterface::
Run( double run_duration )
{
	if( initialized==false )
		ReportFatalError( "childInterface must be initialized (with Initialize() method) before Run() method is called." );

	if( run_duration>0.0 )
		time->Start( time->getCurrentTime(), time->getCurrentTime()+run_duration );

   while( !time->IsFinished() )
		RunOneStorm();

}

/**************************************************************************/
/**
**  CleanUp
**
**  This method deletes the various objects created. Note that this
**  function is called by the destructor, so if a user function calls it
**  explicitly, it will end up being called twice.
*/
/**************************************************************************/

void childRInterface::
CleanUp()
{
	if( rand ) {
		delete rand;
		rand = NULL;
	}
	if( mesh ) {
		delete mesh;
		mesh = NULL;
	}
	if( output ) {
		delete output;
		output = NULL;
	}
	if( storm ) {
		delete storm;
		storm = NULL;
	}
	if( strmNet ) {
		delete strmNet;
		strmNet = NULL;
	}
	if( erosion ) {
		delete erosion;
		erosion = NULL;
	}
	if( uplift ) {
		delete uplift;
		uplift = NULL;
	}
	if( time ) {
		delete time;
		time = NULL;
	}
	if( optVegetation && vegetation ) {
		delete vegetation;
		vegetation = NULL;
	}
	if( optLoessDep && loess ) {
		delete loess;
		loess = NULL;
	}
	if( optStratGrid && stratGrid ) {
		delete stratGrid;
		stratGrid = NULL;
	}
	initialized = false;
}

childRInterface::
~childRInterface()
{
	CleanUp();
}

/**************************************************************************/
/**
**  childInterface::ExternalErosionAndDeposition
**
**  This function allows a calling program to tell CHILD to perform a
**  given depth of erosion and/or sedimentation at each node.
**
**  Presently, it is set up without any grain-size information. A future
**  version could also pass grain-size information.
**
**  GT, June 09
*/
/**************************************************************************/

void childRInterface::ExternalErosionAndDeposition( vector<double> dz )
{
  tMesh< tLNode >::nodeListIter_t mli( mesh->getNodeList() );  // gets nodes from the list
  tLNode * cn;
  for( cn=mli.FirstP(); mli.IsActive(); cn=mli.NextP() )
  {
    int current_id = cn->getPermID();
    cn->EroDep( dz[current_id] );
  }
}

<|endoftext|>


<commit_before>/**
 * @file mega/posix/drivenotifyposix.cpp
 * @brief Mega SDK various utilities and helper classes
 *
 * (c) 2013-2020 by Mega Limited, Auckland, New Zealand
 *
 * This file is part of the MEGA SDK - Client Access Engine.
 *
 * Applications using the MEGA API must present a valid application key
 * and comply with the the rules set forth in the Terms of Service.
 *
 * The MEGA SDK 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.
 *
 * @copyright Simplified (2-clause) BSD License.
 *
 * You should have received a copy of the license along with this
 * program.
 */

#ifdef USE_DRIVE_NOTIFICATIONS

#include "mega/drivenotify.h"
#include <libudev.h> // Ubuntu: sudo apt-get install libudev-dev
#include <mntent.h>
#include <cstring>
#include <chrono>

namespace mega {

    //
    // DriveNotifyPosix
    /////////////////////////////////////////////

    bool DriveNotifyPosix::startNotifier()
    {
        if (mEventSinkThread.joinable() || mStop.load())  return false;

        // init udev resource
        mUdev = udev_new();
        if (!mUdev)  return false;  // is udevd daemon running?

        cacheMountedPartitions();

        // init udev monitor
        mUdevMon = udev_monitor_new_from_netlink(mUdev, "udev");
        if (!mUdevMon)
        {
            udev_unref(mUdev);
            mUdev = nullptr;
            return false;
        }

        // On unix systems you need to define your udev rules to allow notifications for
        // your device.
        //
        // i.e. on Ubuntu create file "99-z-mega.rules" either in
        // /etc/udev/rules.d/        OR
        // /usr/lib/udev/rules.d/
        // and add line:
        // SUBSYSTEM=="block", ATTRS{idDevtype}=="partition", MODE="0666"
        udev_monitor_filter_add_match_subsystem_devtype(mUdevMon, "block", nullptr);
        udev_monitor_enable_receiving(mUdevMon);

        // start worker thread
        mEventSinkThread = std::thread(&DriveNotifyPosix::doInThread, this);

        return true;
    }

    void DriveNotifyPosix::stopNotifier()
    {
        // begin the stopping routine
        mStop.store(true);

        // stop the worker thread
        if (mEventSinkThread.joinable())
        {
            mEventSinkThread.join();
        }

        // release udev monitor
        if (mUdevMon)
        {
            udev_monitor_filter_remove(mUdevMon);
            udev_monitor_unref(mUdevMon);
            mUdevMon = nullptr;
        }

        // release udev resource
        if (mUdev)
        {
            udev_unref(mUdev);
            mUdev = nullptr;
        }

        // end the stopping routine
        mStop.store(false); // and allow reusing this instance
    }

    void DriveNotifyPosix::doInThread()
    {
        int fd = udev_monitor_get_fd(mUdevMon);
        while (!mStop.load())
        {
            // use a blocking call, with a timeout, to check for device events
            fd_set fds;
            FD_ZERO(&fds);
            FD_SET(fd, &fds);

            timeval tv;
            tv.tv_sec = 0;
            tv.tv_usec = 250 * 1000; // 250ms

            int ret = select(fd+1, &fds, nullptr, nullptr, &tv);
            if (ret <= 0 || !FD_ISSET(fd, &fds))  continue;

            // get any [dis]connected device
            udev_device* dev = udev_monitor_receive_device(mUdevMon);
            if (dev)
            {
                evaluateDevice(dev);

                udev_device_unref(dev);
            }
        }
    }

    void DriveNotifyPosix::evaluateDevice(udev_device* dev)  // dev must Not be null
    {
        // filter "partition" events
        const char* devtype = udev_device_get_devtype(dev); // "partition"
        if(strcmp(devtype, "partition"))  return;

        // filter "add"/"remove" actions
        const char* action = udev_device_get_action(dev); // "add" / "remove"
        bool added = !strcmp(action, "add");
        bool removed = !added && !strcmp(action, "remove");
        if (!(added || removed))  return; // ignore other possible actions

        // get device location
        const char* devNode = udev_device_get_devnode(dev); // "/dev/sda1"
        if (!devNode)  return; // did something go wrong?

        const std::string& devNodeStr(devNode);

        // gather drive info
        DriveInfo drvInfo;
        drvInfo.connected = added;

        // get the mount point
        if (removed)
        {
            // get it from the cache, because it will have already been removed from
            // the relevant locations by the time getMountPoint() will attempt to read it
            drvInfo.mountPoint = mMounted[devNodeStr];
            mMounted.erase(devNodeStr); // remove from cache
        }

        else // added
        {
            // reading it might happen before the relevant locations have been updated,
            // so allow retrying a few times, say at 100ms intervals
            for (int i = 0; i < 5; ++i)
            {
                drvInfo.mountPoint = getMountPoint(devNodeStr);

                if (!drvInfo.mountPoint.empty())
                {
                    mMounted[devNodeStr] = drvInfo.mountPoint; // cache it
                    break;
                }

                std::this_thread::sleep_for(std::chrono::milliseconds(100));
            }
        }

        // send notification
        if (!drvInfo.mountPoint.empty())
        {
            add(std::move(drvInfo));
        }
    }

    std::string DriveNotifyPosix::getMountPoint(const std::string& device)
    {
        std::string mountPoint;

        // go to all mounts
        FILE* fsMounts = setmntent("/proc/mounts", "r");
        if (!fsMounts) // this should never happen
        {
            // make another attempt
            fsMounts = setmntent("/etc/mtab", "r");
            if (!fsMounts)  return mountPoint;
        }

        // search mount point for the current device
        for (mntent* mnt = getmntent(fsMounts); mnt; mnt = getmntent(fsMounts))
        {
            if (device == mnt->mnt_fsname)
            {
                mountPoint = mnt->mnt_dir;
                break;
            }
        }

        endmntent(fsMounts); // closes the file descriptor

        return mountPoint;
    }

    void DriveNotifyPosix::cacheMountedPartitions()
    {
        // enumerate all mounted partitions
        udev_enumerate* enumerate = udev_enumerate_new(mUdev);

        udev_enumerate_add_match_subsystem(enumerate, "block");
        udev_enumerate_add_match_property(enumerate, "DEVTYPE", "partition");
        udev_enumerate_scan_devices(enumerate);

        udev_list_entry *devices = udev_enumerate_get_list_entry(enumerate);
        udev_list_entry *entry;

        udev_list_entry_foreach(entry, devices) // for loop
        {
            // get a partition
            const char* entryName = udev_list_entry_get_name(entry);
            udev_device* blockDev = udev_device_new_from_syspath(mUdev, entryName);
            if (!blockDev)  continue;

            // filter only removable ones
            if (isRemovable(blockDev))
            {
                // get partition node
                const char* devNode = udev_device_get_devnode(blockDev); // "/dev/sda1"

                // cache mount point
                std::string mountPoint = getMountPoint(devNode);
                if (!mountPoint.empty())
                {
                    mMounted[devNode] = mountPoint;
                }
            }

            udev_device_unref(blockDev);
        }

        udev_enumerate_unref(enumerate);
    }

    bool DriveNotifyPosix::isRemovable(udev_device* part)
    {
        udev_device* parent = udev_device_get_parent(part); // do not unref this one!
        if (!parent)  return false;

        const char* removable = udev_device_get_sysattr_value(parent, "removable");
        return removable && !strcmp(removable, "1");
    }

    DriveNotifyPosix::~DriveNotifyPosix()
    {
        stop();
    }

} // namespace

#endif // USE_DRIVE_NOTIFICATIONS
<commit_msg>Restrict drive monitor filter even more<commit_after>/**
 * @file mega/posix/drivenotifyposix.cpp
 * @brief Mega SDK various utilities and helper classes
 *
 * (c) 2013-2020 by Mega Limited, Auckland, New Zealand
 *
 * This file is part of the MEGA SDK - Client Access Engine.
 *
 * Applications using the MEGA API must present a valid application key
 * and comply with the the rules set forth in the Terms of Service.
 *
 * The MEGA SDK 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.
 *
 * @copyright Simplified (2-clause) BSD License.
 *
 * You should have received a copy of the license along with this
 * program.
 */

#ifdef USE_DRIVE_NOTIFICATIONS

#include "mega/drivenotify.h"
#include <libudev.h> // Ubuntu: sudo apt-get install libudev-dev
#include <mntent.h>
#include <cstring>
#include <chrono>

namespace mega {

    //
    // DriveNotifyPosix
    /////////////////////////////////////////////

    bool DriveNotifyPosix::startNotifier()
    {
        if (mEventSinkThread.joinable() || mStop.load())  return false;

        // init udev resource
        mUdev = udev_new();
        if (!mUdev)  return false;  // is udevd daemon running?

        cacheMountedPartitions();

        // init udev monitor
        mUdevMon = udev_monitor_new_from_netlink(mUdev, "udev");
        if (!mUdevMon)
        {
            udev_unref(mUdev);
            mUdev = nullptr;
            return false;
        }

        // On unix systems you need to define your udev rules to allow notifications for
        // your device.
        //
        // i.e. on Ubuntu create file "100-megasync-udev.rules" either in
        // /etc/udev/rules.d/        OR
        // /usr/lib/udev/rules.d/
        // and add line:
        // SUBSYSTEM=="block", ATTRS{idDevtype}=="partition"
        udev_monitor_filter_add_match_subsystem_devtype(mUdevMon, "block", "partition");
        udev_monitor_enable_receiving(mUdevMon);

        // start worker thread
        mEventSinkThread = std::thread(&DriveNotifyPosix::doInThread, this);

        return true;
    }

    void DriveNotifyPosix::stopNotifier()
    {
        // begin the stopping routine
        mStop.store(true);

        // stop the worker thread
        if (mEventSinkThread.joinable())
        {
            mEventSinkThread.join();
        }

        // release udev monitor
        if (mUdevMon)
        {
            udev_monitor_filter_remove(mUdevMon);
            udev_monitor_unref(mUdevMon);
            mUdevMon = nullptr;
        }

        // release udev resource
        if (mUdev)
        {
            udev_unref(mUdev);
            mUdev = nullptr;
        }

        // end the stopping routine
        mStop.store(false); // and allow reusing this instance
    }

    void DriveNotifyPosix::doInThread()
    {
        int fd = udev_monitor_get_fd(mUdevMon);
        while (!mStop.load())
        {
            // use a blocking call, with a timeout, to check for device events
            fd_set fds;
            FD_ZERO(&fds);
            FD_SET(fd, &fds);

            timeval tv;
            tv.tv_sec = 0;
            tv.tv_usec = 250 * 1000; // 250ms

            int ret = select(fd+1, &fds, nullptr, nullptr, &tv);
            if (ret <= 0 || !FD_ISSET(fd, &fds))  continue;

            // get any [dis]connected device
            udev_device* dev = udev_monitor_receive_device(mUdevMon);
            if (dev)
            {
                evaluateDevice(dev);

                udev_device_unref(dev);
            }
        }
    }

    void DriveNotifyPosix::evaluateDevice(udev_device* dev)  // dev must Not be null
    {
        // filter "partition" events
        const char* devtype = udev_device_get_devtype(dev); // "partition"
        if(strcmp(devtype, "partition"))  return;

        // filter "add"/"remove" actions
        const char* action = udev_device_get_action(dev); // "add" / "remove"
        bool added = !strcmp(action, "add");
        bool removed = !added && !strcmp(action, "remove");
        if (!(added || removed))  return; // ignore other possible actions

        // get device location
        const char* devNode = udev_device_get_devnode(dev); // "/dev/sda1"
        if (!devNode)  return; // did something go wrong?

        const std::string& devNodeStr(devNode);

        // gather drive info
        DriveInfo drvInfo;
        drvInfo.connected = added;

        // get the mount point
        if (removed)
        {
            // get it from the cache, because it will have already been removed from
            // the relevant locations by the time getMountPoint() will attempt to read it
            drvInfo.mountPoint = mMounted[devNodeStr];
            mMounted.erase(devNodeStr); // remove from cache
        }

        else // added
        {
            // reading it might happen before the relevant locations have been updated,
            // so allow retrying a few times, say at 100ms intervals
            for (int i = 0; i < 5; ++i)
            {
                drvInfo.mountPoint = getMountPoint(devNodeStr);

                if (!drvInfo.mountPoint.empty())
                {
                    mMounted[devNodeStr] = drvInfo.mountPoint; // cache it
                    break;
                }

                std::this_thread::sleep_for(std::chrono::milliseconds(100));
            }
        }

        // send notification
        if (!drvInfo.mountPoint.empty())
        {
            add(std::move(drvInfo));
        }
    }

    std::string DriveNotifyPosix::getMountPoint(const std::string& device)
    {
        std::string mountPoint;

        // go to all mounts
        FILE* fsMounts = setmntent("/proc/mounts", "r");
        if (!fsMounts) // this should never happen
        {
            // make another attempt
            fsMounts = setmntent("/etc/mtab", "r");
            if (!fsMounts)  return mountPoint;
        }

        // search mount point for the current device
        for (mntent* mnt = getmntent(fsMounts); mnt; mnt = getmntent(fsMounts))
        {
            if (device == mnt->mnt_fsname)
            {
                mountPoint = mnt->mnt_dir;
                break;
            }
        }

        endmntent(fsMounts); // closes the file descriptor

        return mountPoint;
    }

    void DriveNotifyPosix::cacheMountedPartitions()
    {
        // enumerate all mounted partitions
        udev_enumerate* enumerate = udev_enumerate_new(mUdev);

        udev_enumerate_add_match_subsystem(enumerate, "block");
        udev_enumerate_add_match_property(enumerate, "DEVTYPE", "partition");
        udev_enumerate_scan_devices(enumerate);

        udev_list_entry *devices = udev_enumerate_get_list_entry(enumerate);
        udev_list_entry *entry;

        udev_list_entry_foreach(entry, devices) // for loop
        {
            // get a partition
            const char* entryName = udev_list_entry_get_name(entry);
            udev_device* blockDev = udev_device_new_from_syspath(mUdev, entryName);
            if (!blockDev)  continue;

            // filter only removable ones
            if (isRemovable(blockDev))
            {
                // get partition node
                const char* devNode = udev_device_get_devnode(blockDev); // "/dev/sda1"

                // cache mount point
                std::string mountPoint = getMountPoint(devNode);
                if (!mountPoint.empty())
                {
                    mMounted[devNode] = mountPoint;
                }
            }

            udev_device_unref(blockDev);
        }

        udev_enumerate_unref(enumerate);
    }

    bool DriveNotifyPosix::isRemovable(udev_device* part)
    {
        udev_device* parent = udev_device_get_parent(part); // do not unref this one!
        if (!parent)  return false;

        const char* removable = udev_device_get_sysattr_value(parent, "removable");
        return removable && !strcmp(removable, "1");
    }

    DriveNotifyPosix::~DriveNotifyPosix()
    {
        stop();
    }

} // namespace

#endif // USE_DRIVE_NOTIFICATIONS
<|endoftext|>


<commit_before>#ifdef HAVE_CONFIG_H
#include "sys_config.h"
#endif

#include "arch/MGSystem.h"
#include "simreadline.h"
#include "commands.h"
#include "sim/config.h"

#ifdef ENABLE_MONITOR
# include "sim/monitor.h"
#endif

#include <sstream>
#include <iostream>
#include <limits>

#ifdef USE_SDL
#include <SDL.h>
#endif

using namespace Simulator;
using namespace std;

struct ProgramConfig
{
    string                           m_programFile;
    string                           m_configFile;
    string                           m_symtableFile;
    bool                             m_enableMonitor;
    bool                             m_interactive;
    bool                             m_terminate;
    bool                             m_dumpconf;
    bool                             m_quiet;
    bool                             m_dumpvars;
    bool                             m_earlyquit;
    vector<pair<string,string> >     m_overrides;

    vector<pair<RegAddr, RegValue> > m_regs;
    vector<pair<RegAddr, string> >   m_loads;
};

static void ParseArguments(int argc, const char ** argv, ProgramConfig& config)
{
    config.m_configFile = MGSIM_CONFIG_PATH;
    config.m_enableMonitor = false;
    config.m_interactive = false;
    config.m_terminate = false;
    config.m_dumpconf = false;
    config.m_quiet = false;
    config.m_dumpvars = false;
    config.m_earlyquit = false;

    for (int i = 1; i < argc; ++i)
    {
        const string arg = argv[i];
        if (arg[0] != '-')
        {
            if (config.m_programFile != "")
                cerr << "Warning: program already set ("
                     << config.m_programFile
                     << "), ignoring extra arg: " << arg << endl;
            else
                config.m_programFile = arg;
        }
        else if (arg == "-c" || arg == "--config")      config.m_configFile    = argv[++i];
        else if (arg == "-i" || arg == "--interactive") config.m_interactive   = true;
        else if (arg == "-t" || arg == "--terminate")   config.m_terminate     = true;
        else if (arg == "-q" || arg == "--quiet")       config.m_quiet         = true;
        else if (arg == "-s" || arg == "--symtable")    config.m_symtableFile  = argv[++i];
        else if (arg == "--version")                    { PrintVersion(std::cout); exit(0); }
        else if (arg == "-h" || arg == "--help")        { PrintUsage(std::cout, argv[0]); exit(0); }
        else if (arg == "-d" || arg == "--dumpconf")    config.m_dumpconf      = true;
        else if (arg == "-m" || arg == "--monitor")     config.m_enableMonitor = true;
        else if (arg == "-D" || arg == "--dumpvars")    config.m_dumpvars      = true;
        else if (arg == "-n" || arg == "--do-nothing")  config.m_earlyquit     = true;
        else if (arg == "-o" || arg == "--override")
        {
            if (argv[++i] == NULL) {
                throw runtime_error("Error: expected configuration option");
            }
            string arg = argv[i];
            string::size_type eq = arg.find_first_of("=");
            if (eq == string::npos) {
                throw runtime_error("Error: malformed configuration override syntax");
            }
            string name = arg.substr(0, eq);
            transform(name.begin(), name.end(), name.begin(), ::toupper);
            config.m_overrides.push_back(make_pair(name, arg.substr(eq + 1)));
        }
        else if (toupper(arg[1]) == 'L')
        {
            if (argv[++i] == NULL) {
                throw runtime_error("Error: expected filename");
            }
            string filename(argv[i]);
            char* endptr;
            RegAddr  addr;
            unsigned long index = strtoul(&arg[2], &endptr, 0);
            if (*endptr != '\0') {
                throw runtime_error("Error: invalid register specifier in option");
            }
            addr = MAKE_REGADDR(RT_INTEGER, index);
            config.m_loads.push_back(make_pair(addr, filename));
        }
        else if (toupper(arg[1]) == 'R' || toupper(arg[1]) == 'F')
        {
            if (argv[++i] == NULL) {
                throw runtime_error("Error: expected register value");
            }
            stringstream value;
            value << argv[i];

            RegAddr  addr;
            RegValue val;

            char* endptr;
            unsigned long index = strtoul(&arg[2], &endptr, 0);
            if (*endptr != '\0') {
                throw runtime_error("Error: invalid register specifier in option");
            }

            if (toupper(arg[1]) == 'R') {
                value >> *(signed Integer*)&val.m_integer;
                addr = MAKE_REGADDR(RT_INTEGER, index);
            } else {
                double f;
                value >> f;
                val.m_float.fromfloat(f);
                addr = MAKE_REGADDR(RT_FLOAT, index);
            }
            if (value.fail()) {
                throw runtime_error("Error: invalid value for register");
            }
            val.m_state = RST_FULL;
            config.m_regs.push_back(make_pair(addr, val));
        }
    }

    if (config.m_programFile.empty())
    {
        throw runtime_error("Error: no program file specified");
    }

}

#ifdef USE_SDL
extern "C"
#endif
int main(int argc, char** argv)
{
    srand(time(NULL));

    try
    {
        // Parse command line arguments
        ProgramConfig config;
        ParseArguments(argc, (const char**)argv, config);

        if (config.m_interactive)
        {
            // Interactive mode
            PrintVersion(std::cout);
        }

        // Read configuration
        Config configfile(config.m_configFile, config.m_overrides);

        // Create the system
        MGSystem sys(configfile,
                     config.m_programFile, config.m_symtableFile,
                     config.m_regs, config.m_loads, !config.m_interactive, !config.m_earlyquit);

#ifdef ENABLE_MONITOR
        string mo_mdfile = configfile.getValue<string>("MonitorMetadataFile", "mgtrace.md");
        string mo_tfile = configfile.getValue<string>("MonitorTraceFile", "mgtrace.out");
        Monitor mo(sys, config.m_enableMonitor,
                   mo_mdfile, config.m_earlyquit ? "" : mo_tfile, !config.m_interactive);
#endif

        if (config.m_dumpconf)
        {
            std::clog << "### simulator version: " PACKAGE_VERSION << std::endl;
            configfile.dumpConfiguration(std::clog, config.m_configFile);
        }

        if (config.m_dumpvars)
        {
            std::cout << "### begin monitor variables" << std::endl;
            ListSampleVariables(std::cout);
            std::cout << "### end monitor variables" << std::endl;
        }

        if (config.m_earlyquit)
            exit(0);

        bool interactive = config.m_interactive;
        if (!interactive)
        {
            // Non-interactive mode; run and dump cycle count
            try
            {
#ifdef ENABLE_MONITOR
                mo.start();
#endif
                StepSystem(sys, INFINITE_CYCLES);
#ifdef ENABLE_MONITOR
                mo.stop();
#endif

                if (!config.m_quiet)
                {
                    clog << "### begin end-of-simulation statistics" << endl;
                    sys.PrintAllStatistics(clog);
                    clog << "### end end-of-simulation statistics" << endl;
                }
            }
            catch (const exception& e)
            {
#ifdef ENABLE_MONITOR
                mo.stop();
#endif
                if (config.m_terminate)
                {
                    // We do not want to go to interactive mode,
                    // rethrow so it abort the program.
                    throw;
                }

                PrintException(cerr, e);

                // When we get an exception in non-interactive mode,
                // jump into interactive mode
                interactive = true;
            }
        }

        if (interactive)
        {
            // Command loop
            cout << endl;
            CommandLineReader clr;
            cli_context ctx = { clr, sys
#ifdef ENABLE_MONITOR
                                , mo
#endif
            };

            while (HandleCommandLine(ctx) == false)
                /* just loop */;
        }
    }
    catch (const exception& e)
    {
        PrintException(cerr, e);
        return 1;
    }

    return 0;
}
<commit_msg>[mgsim-refactor] Allow to report the internal state of the simulation at the end of execution.<commit_after>#ifdef HAVE_CONFIG_H
#include "sys_config.h"
#endif

#include "arch/MGSystem.h"
#include "simreadline.h"
#include "commands.h"
#include "sim/config.h"

#ifdef ENABLE_MONITOR
# include "sim/monitor.h"
#endif

#include <sstream>
#include <iostream>
#include <limits>

#ifdef USE_SDL
#include <SDL.h>
#endif

using namespace Simulator;
using namespace std;

struct ProgramConfig
{
    string                           m_programFile;
    string                           m_configFile;
    string                           m_symtableFile;
    bool                             m_enableMonitor;
    bool                             m_interactive;
    bool                             m_terminate;
    bool                             m_dumpconf;
    bool                             m_quiet;
    bool                             m_dumpvars;
    vector<string>                   m_printvars;
    bool                             m_earlyquit;
    vector<pair<string,string> >     m_overrides;

    vector<pair<RegAddr, RegValue> > m_regs;
    vector<pair<RegAddr, string> >   m_loads;
};

static void ParseArguments(int argc, const char ** argv, ProgramConfig& config)
{
    config.m_configFile = MGSIM_CONFIG_PATH;
    config.m_enableMonitor = false;
    config.m_interactive = false;
    config.m_terminate = false;
    config.m_dumpconf = false;
    config.m_quiet = false;
    config.m_dumpvars = false;
    config.m_earlyquit = false;

    for (int i = 1; i < argc; ++i)
    {
        const string arg = argv[i];
        if (arg[0] != '-')
        {
            if (config.m_programFile != "")
                cerr << "Warning: program already set ("
                     << config.m_programFile
                     << "), ignoring extra arg: " << arg << endl;
            else
                config.m_programFile = arg;
        }
        else if (arg == "-c" || arg == "--config")      config.m_configFile    = argv[++i];
        else if (arg == "-i" || arg == "--interactive") config.m_interactive   = true;
        else if (arg == "-t" || arg == "--terminate")   config.m_terminate     = true;
        else if (arg == "-q" || arg == "--quiet")       config.m_quiet         = true;
        else if (arg == "-s" || arg == "--symtable")    config.m_symtableFile  = argv[++i];
        else if (arg == "--version")                    { PrintVersion(std::cout); exit(0); }
        else if (arg == "-h" || arg == "--help")        { PrintUsage(std::cout, argv[0]); exit(0); }
        else if (arg == "-d" || arg == "--dumpconf")    config.m_dumpconf      = true;
        else if (arg == "-m" || arg == "--monitor")     config.m_enableMonitor = true;
        else if (arg == "-l" || arg == "--list-mvars")  config.m_dumpvars      = true;
        else if (arg == "-p" || arg == "--print-final-mvars")
        {
            if (argv[++i] == NULL) {
                throw runtime_error("Error: expected variable name");
            }
            config.m_printvars.push_back(argv[i]);
        }
        else if (arg == "-n" || arg == "--do-nothing")  config.m_earlyquit     = true;
        else if (arg == "-o" || arg == "--override")
        {
            if (argv[++i] == NULL) {
                throw runtime_error("Error: expected configuration option");
            }
            string arg = argv[i];
            string::size_type eq = arg.find_first_of("=");
            if (eq == string::npos) {
                throw runtime_error("Error: malformed configuration override syntax");
            }
            string name = arg.substr(0, eq);
            transform(name.begin(), name.end(), name.begin(), ::toupper);
            config.m_overrides.push_back(make_pair(name, arg.substr(eq + 1)));
        }
        else if (arg[1] == 'L')
        {
            if (argv[++i] == NULL) {
                throw runtime_error("Error: expected filename");
            }
            string filename(argv[i]);
            char* endptr;
            RegAddr  addr;
            unsigned long index = strtoul(&arg[2], &endptr, 0);
            if (*endptr != '\0') {
                throw runtime_error("Error: invalid register specifier in option");
            }
            addr = MAKE_REGADDR(RT_INTEGER, index);
            config.m_loads.push_back(make_pair(addr, filename));
        }
        else if (arg[1] == 'R' || arg[1] == 'F')
        {
            if (argv[++i] == NULL) {
                throw runtime_error("Error: expected register value");
            }
            stringstream value;
            value << argv[i];

            RegAddr  addr;
            RegValue val;

            char* endptr;
            unsigned long index = strtoul(&arg[2], &endptr, 0);
            if (*endptr != '\0') {
                throw runtime_error("Error: invalid register specifier in option");
            }

            if (arg[1] == 'R') {
                value >> *(signed Integer*)&val.m_integer;
                addr = MAKE_REGADDR(RT_INTEGER, index);
            } else {
                double f;
                value >> f;
                val.m_float.fromfloat(f);
                addr = MAKE_REGADDR(RT_FLOAT, index);
            }
            if (value.fail()) {
                throw runtime_error("Error: invalid value for register");
            }
            val.m_state = RST_FULL;
            config.m_regs.push_back(make_pair(addr, val));
        }
    }

    if (config.m_programFile.empty())
    {
        throw runtime_error("Error: no program file specified");
    }

}

void PrintFinalVariables(const ProgramConfig& cfg)
{
    if (!cfg.m_printvars.empty())
    {
        std::cout << "### begin end-of-simulation variables" << std::endl;
        for (size_t i = 0; i < cfg.m_printvars.size(); ++i)
            ReadSampleVariables(cout, cfg.m_printvars[i]);
        std::cout << "### end end-of-simulation variables" << std::endl;
    }
}

#ifdef USE_SDL
extern "C"
#endif
int main(int argc, char** argv)
{
    srand(time(NULL));

    try
    {
        // Parse command line arguments
        ProgramConfig config;
        ParseArguments(argc, (const char**)argv, config);

        if (config.m_interactive)
        {
            // Interactive mode
            PrintVersion(std::cout);
        }

        // Read configuration
        Config configfile(config.m_configFile, config.m_overrides);

        // Create the system
        MGSystem sys(configfile,
                     config.m_programFile, config.m_symtableFile,
                     config.m_regs, config.m_loads, !config.m_interactive, !config.m_earlyquit);

#ifdef ENABLE_MONITOR
        string mo_mdfile = configfile.getValue<string>("MonitorMetadataFile", "mgtrace.md");
        string mo_tfile = configfile.getValue<string>("MonitorTraceFile", "mgtrace.out");
        Monitor mo(sys, config.m_enableMonitor,
                   mo_mdfile, config.m_earlyquit ? "" : mo_tfile, !config.m_interactive);
#endif

        if (config.m_dumpconf)
        {
            std::clog << "### simulator version: " PACKAGE_VERSION << std::endl;
            configfile.dumpConfiguration(std::clog, config.m_configFile);
        }

        if (config.m_dumpvars)
        {
            std::cout << "### begin monitor variables" << std::endl;
            ListSampleVariables(std::cout);
            std::cout << "### end monitor variables" << std::endl;
        }

        if (config.m_earlyquit)
            exit(0);

        bool interactive = config.m_interactive;
        if (!interactive)
        {
            // Non-interactive mode; run and dump cycle count
            try
            {
#ifdef ENABLE_MONITOR
                mo.start();
#endif
                StepSystem(sys, INFINITE_CYCLES);
#ifdef ENABLE_MONITOR
                mo.stop();
#endif

                if (!config.m_quiet)
                {
                    clog << "### begin end-of-simulation statistics" << endl;
                    sys.PrintAllStatistics(clog);
                    clog << "### end end-of-simulation statistics" << endl;
                }
            }
            catch (const exception& e)
            {
#ifdef ENABLE_MONITOR
                mo.stop();
#endif
                if (config.m_terminate)
                {
                    // We do not want to go to interactive mode,
                    // rethrow so it abort the program.
                    PrintFinalVariables(config);
                    throw;
                }

                PrintException(cerr, e);

                // When we get an exception in non-interactive mode,
                // jump into interactive mode
                interactive = true;
            }
        }

        if (interactive)
        {
            // Command loop
            cout << endl;
            CommandLineReader clr;
            cli_context ctx = { clr, sys
#ifdef ENABLE_MONITOR
                                , mo
#endif
            };

            while (HandleCommandLine(ctx) == false)
                /* just loop */;
        }

        PrintFinalVariables(config);
    }
    catch (const exception& e)
    {
        PrintException(cerr, e);
        return 1;
    }

    return 0;
}
<|endoftext|>