<commit_before>#include <iostream>                     // std::cout ...

#include "logMsg.h"                     // lmInit, LM_*
#include "coreTracelevels.h"            // LMT_*

#include "Message.h"                    // Message
#include "Macros.h"                     // EXIT, ...
#include "Packet.h"                     // ss::Packet
#include "Network.h"                    // NetworkInterface
#include "Endpoint.h"                   // Endpoint
#include "CommandLine.h"                // CommandLine
#include "ProcessAssistant.h"           // ProcessAssistant
#include "SamsonWorker.h"               // Own interfce
#include "EndpointMgr.h"				// ss::EndpointMgr
#include "SamsonSetup.h"				// ss::SamsonSetup
#include "Format.h"						// au::Format

#include "MemoryManager.h"				// ss::SharedMemory

namespace ss {

/* ****************************************************************************
*
* Constructor
*/
SamsonWorker::SamsonWorker(char* controller, char* alias, unsigned short port, int workers, int endpoints) :  taskManager(this) , dataBuffer(this), loadDataManager(this)
{
	this->controller  = controller;
	this->alias       = alias;
	this->port        = port;
	this->workers     = workers;
	this->endpoints   = endpoints;

	// Define the number of process
	num_processes = SamsonSetup::shared()->num_processes;

	srand( (unsigned int) time(NULL) );

}

/* ****************************************************************************
*
* endpointMgrSet -
*/
void SamsonWorker::endpointMgrSet(ss::EndpointMgr* _epMgr)
{
	epMgr = _epMgr;

	// epMgr->init(Endpoint::Worker, alias.c_str(), port, controller.c_str());
	// epMgr->packetReceiverSet(this);
}

/* ****************************************************************************
*
* networkSet -
*/
void SamsonWorker::networkSet(NetworkInterface* network)
{
	this->network = network;
	network->setPacketReceiverInterface(this);

	network->init(Endpoint::Worker, alias.c_str(), port, controller.c_str());

	// Get my id as worker
	myWorkerId = network->getWorkerFromIdentifier(network->getMyidentifier());

	this->workers     = network->getNumWorkers();

	// This is only necessary when running multiple samsonworkers as separated process in the same machine
	// MemoryManager::shared()->setOtherSharedMemoryAsMarked( myWorkerId , workers );
}

/* ****************************************************************************
*
* run -
*/
void SamsonWorker::run()
{
	workerStatus(&status);

	// //////////////////////////////////////////////////////////////////////
	//
	// Create one ProcessAssistant per core
	//
	if (num_processes == -1)
		LM_X(1, ("Invalid number of cores. Please edit /opt/samson/setup.txt"));

	LM_T(LMT_WINIT, ("initializing %d process assistants", num_processes));

	processAssistant = (ProcessAssistant**) calloc(num_processes, sizeof(ProcessAssistant*));
	if (processAssistant == NULL)
		LM_XP(1, ("calloc(%d, %d)", num_processes, sizeof(ProcessAssistant*)));

	int coreId;
	for (coreId = 0; coreId < num_processes ; coreId++)
	{

		// Fake id to debig locally multiple workers
		int fake_core_id = myWorkerId * workers + coreId;

		processAssistant[coreId] = new ProcessAssistant(fake_core_id, this);
	}

	LM_T(LMT_WINIT, ("Got %d process assistants", coreId));

	// assert(epMgr);
	// epMgr->run();

	assert(network);
	network->run();
}

#if 0
void SamsonWorker::sendWorkerStatus()
{
	Packet *p = new Packet();
	network::WorkerStatus*  w = p->message.mutable_worker_status();

	// Fill with all data related to data
	data.fillWorkerStatus(w);

	// Fill to all data related with task manager
	taskManager.fillWorkerStatus(w);

	network->send(this, network->controllerGetIdentifier(), Message::WorkerStatus, NULL, 0, p);
}
#endif

int SamsonWorker::receive(int fromId, Message::MessageCode msgCode, Packet* packet)
{

	if (msgCode == Message::StatusRequest)
	{
		Packet* p = new Packet();
		network::StatusResponse *response = p->message.mutable_status_response();

		response->set_title( "Worker " + au::Format::string( network->getWorkerFromIdentifier( network->getMyidentifier() ) ) );
		response->set_senderid( packet->message.status_request().senderid() ) ;
		response->set_response( getStatus( packet->message.status_request().command() ) );

		network->send(this, network->controllerGetIdentifier() , Message::StatusResponse, p);
		return 0;
	}

	if (msgCode == Message::WorkerTask)
	{
		// A packet with a particular command is received (controller expect to send a confirmation message)
		LM_T(LMT_TASK, ("Got a WorkerTask message"));

		// add task to the task manager
		taskManager.addTask( packet->message.worker_task() );
		return 0;
	}

	// Load data files to be latter confirmed to controller
	if (msgCode == Message::UploadData)
	{
		std::ostringstream fileName;
		fileName << "/tmp/file_"<< getpid() << "_" << rand() << rand();	// Just to test

		loadDataManager.addUploadItem(fromId, packet->message.upload_data(), packet->message.delilah_id() , packet->buffer );
		return 0;
	}

	// Download data files
	if (msgCode == Message::DownloadData)
	{
		loadDataManager.addDownloadItem(fromId, packet->message.download_data() , packet->message.delilah_id() );
		return 0;
	}

		/**
		 Data packets go directly to the DataBuffer to be joined and flushed to disk
		 DataManager is notifyed when created a new file or finish everything
		 */

		if( msgCode == Message::WorkerDataExchange )
		{
			// New data packet for a particular queue inside a particular task environment

			size_t task_id = packet->message.data().task_id();
			network::Queue queue = packet->message.data().queue();

			dataBuffer.addBuffer(task_id, queue, packet->buffer );

			return 0;
		}

		/**
		 Data Close message is sent to notify that no more data will be generated
		 We have to wait for "N" messages ( one per worker )
		 */

		if( msgCode == Message::WorkerDataExchangeClose )
		{

			size_t task_id = packet->message.data_close().task_id();
			dataBuffer.finishWorker( task_id );
			return 0;
		}

		return 0;
	}

	std::string SamsonWorker::getStatus(std::string command)
	{
		std::ostringstream output;
		output << "** Memory: " << MemoryManager::shared()->getStatus() << std::endl;

		output << "** TaskManager:\n";
		output << taskManager.getStatus();

		output << "** ProcessAssistants: (" << num_processes << " process):\n";
		for (int i = 0 ; i < num_processes ; i++)
			output << "\t" << processAssistant[i]->getStatus() << std::endl;

		output << "** DataBuffer:\n";
		output << dataBuffer.getStatus();

		output << "** LoadManager:\n";
		output << loadDataManager.getStatus();

		return output.str();

	}

}
<commit_msg>more info about File Manager<commit_after>#include <iostream>                     // std::cout ...

#include "logMsg.h"                     // lmInit, LM_*
#include "coreTracelevels.h"            // LMT_*

#include "Message.h"                    // Message
#include "Macros.h"                     // EXIT, ...
#include "Packet.h"                     // ss::Packet
#include "Network.h"                    // NetworkInterface
#include "Endpoint.h"                   // Endpoint
#include "CommandLine.h"                // CommandLine
#include "ProcessAssistant.h"           // ProcessAssistant
#include "SamsonWorker.h"               // Own interfce
#include "EndpointMgr.h"				// ss::EndpointMgr
#include "SamsonSetup.h"				// ss::SamsonSetup
#include "Format.h"						// au::Format

#include "MemoryManager.h"				// ss::SharedMemory
#include "FileManager.h"				// ss::FileManager

namespace ss {

/* ****************************************************************************
*
* Constructor
*/
SamsonWorker::SamsonWorker(char* controller, char* alias, unsigned short port, int workers, int endpoints) :  taskManager(this) , dataBuffer(this), loadDataManager(this)
{
	this->controller  = controller;
	this->alias       = alias;
	this->port        = port;
	this->workers     = workers;
	this->endpoints   = endpoints;

	// Define the number of process
	num_processes = SamsonSetup::shared()->num_processes;

	srand( (unsigned int) time(NULL) );

}

/* ****************************************************************************
*
* endpointMgrSet -
*/
void SamsonWorker::endpointMgrSet(ss::EndpointMgr* _epMgr)
{
	epMgr = _epMgr;

	// epMgr->init(Endpoint::Worker, alias.c_str(), port, controller.c_str());
	// epMgr->packetReceiverSet(this);
}

/* ****************************************************************************
*
* networkSet -
*/
void SamsonWorker::networkSet(NetworkInterface* network)
{
	this->network = network;
	network->setPacketReceiverInterface(this);

	network->init(Endpoint::Worker, alias.c_str(), port, controller.c_str());

	// Get my id as worker
	myWorkerId = network->getWorkerFromIdentifier(network->getMyidentifier());

	this->workers     = network->getNumWorkers();

	// This is only necessary when running multiple samsonworkers as separated process in the same machine
	// MemoryManager::shared()->setOtherSharedMemoryAsMarked( myWorkerId , workers );
}

/* ****************************************************************************
*
* run -
*/
void SamsonWorker::run()
{
	workerStatus(&status);

	// //////////////////////////////////////////////////////////////////////
	//
	// Create one ProcessAssistant per core
	//
	if (num_processes == -1)
		LM_X(1, ("Invalid number of cores. Please edit /opt/samson/setup.txt"));

	LM_T(LMT_WINIT, ("initializing %d process assistants", num_processes));

	processAssistant = (ProcessAssistant**) calloc(num_processes, sizeof(ProcessAssistant*));
	if (processAssistant == NULL)
		LM_XP(1, ("calloc(%d, %d)", num_processes, sizeof(ProcessAssistant*)));

	int coreId;
	for (coreId = 0; coreId < num_processes ; coreId++)
	{

		// Fake id to debig locally multiple workers
		int fake_core_id = myWorkerId * workers + coreId;

		processAssistant[coreId] = new ProcessAssistant(fake_core_id, this);
	}

	LM_T(LMT_WINIT, ("Got %d process assistants", coreId));

	// assert(epMgr);
	// epMgr->run();

	assert(network);
	network->run();
}

#if 0
void SamsonWorker::sendWorkerStatus()
{
	Packet *p = new Packet();
	network::WorkerStatus*  w = p->message.mutable_worker_status();

	// Fill with all data related to data
	data.fillWorkerStatus(w);

	// Fill to all data related with task manager
	taskManager.fillWorkerStatus(w);

	network->send(this, network->controllerGetIdentifier(), Message::WorkerStatus, NULL, 0, p);
}
#endif

int SamsonWorker::receive(int fromId, Message::MessageCode msgCode, Packet* packet)
{

	if (msgCode == Message::StatusRequest)
	{
		Packet* p = new Packet();
		network::StatusResponse *response = p->message.mutable_status_response();

		response->set_title( "Worker " + au::Format::string( network->getWorkerFromIdentifier( network->getMyidentifier() ) ) );
		response->set_senderid( packet->message.status_request().senderid() ) ;
		response->set_response( getStatus( packet->message.status_request().command() ) );

		network->send(this, network->controllerGetIdentifier() , Message::StatusResponse, p);
		return 0;
	}

	if (msgCode == Message::WorkerTask)
	{
		// A packet with a particular command is received (controller expect to send a confirmation message)
		LM_T(LMT_TASK, ("Got a WorkerTask message"));

		// add task to the task manager
		taskManager.addTask( packet->message.worker_task() );
		return 0;
	}

	// Load data files to be latter confirmed to controller
	if (msgCode == Message::UploadData)
	{
		std::ostringstream fileName;
		fileName << "/tmp/file_"<< getpid() << "_" << rand() << rand();	// Just to test

		loadDataManager.addUploadItem(fromId, packet->message.upload_data(), packet->message.delilah_id() , packet->buffer );
		return 0;
	}

	// Download data files
	if (msgCode == Message::DownloadData)
	{
		loadDataManager.addDownloadItem(fromId, packet->message.download_data() , packet->message.delilah_id() );
		return 0;
	}

		/**
		 Data packets go directly to the DataBuffer to be joined and flushed to disk
		 DataManager is notifyed when created a new file or finish everything
		 */

		if( msgCode == Message::WorkerDataExchange )
		{
			// New data packet for a particular queue inside a particular task environment

			size_t task_id = packet->message.data().task_id();
			network::Queue queue = packet->message.data().queue();

			dataBuffer.addBuffer(task_id, queue, packet->buffer );

			return 0;
		}

		/**
		 Data Close message is sent to notify that no more data will be generated
		 We have to wait for "N" messages ( one per worker )
		 */

		if( msgCode == Message::WorkerDataExchangeClose )
		{

			size_t task_id = packet->message.data_close().task_id();
			dataBuffer.finishWorker( task_id );
			return 0;
		}

		return 0;
	}

	std::string SamsonWorker::getStatus(std::string command)
	{
		std::ostringstream output;
		output << "** Memory: " << MemoryManager::shared()->getStatus() << std::endl;

		output << "** TaskManager:\n";
		output << taskManager.getStatus();

		output << "** ProcessAssistants: (" << num_processes << " process):\n";
		for (int i = 0 ; i < num_processes ; i++)
			output << "\t" << processAssistant[i]->getStatus() << std::endl;

		output << "** DataBuffer:\n";
		output << dataBuffer.getStatus();

		output << "** LoadManager:\n";
		output << loadDataManager.getStatus();

		output << "** File Manager:\n";
		output << FileManager::shared()->getStatus();

		return output.str();

	}

}
<|endoftext|>


<commit_before><commit_msg>removing temp file<commit_after><|endoftext|>


<commit_before>
// This file is part of lipstick, a QML desktop library
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License version 2.1 as published by the Free Software Foundation
// and appearing in the file LICENSE.LGPL included in the packaging
// of this file.
//
// This code 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 Lesser General Public License for more details.
//
// Copyright (c) 2012, Timur Kristóf <venemo@fedoraproject.org>

#include <QDir>
#include <QFileSystemWatcher>
#include <QDebug>
#include <QSettings>

#include "launchermodel.h"

// Define this if you'd like to see debug messages from the launcher
#ifdef DEBUG_LAUNCHER
#define LAUNCHER_DEBUG(things) qDebug() << Q_FUNC_INFO << things
#else
#define LAUNCHER_DEBUG(things)
#endif

LauncherModel::LauncherModel(QObject *parent) :
    QObjectListModel(parent),
    _fileSystemWatcher(new QFileSystemWatcher(this))
{
    // This is the most common path for .desktop files in most distributions
    QString defaultAppsPath("/usr/share/applications");

    // Setting up the file system wacher
    _fileSystemWatcher->addPath(defaultAppsPath);
    monitoredDirectoryChanged(defaultAppsPath);
    connect(_fileSystemWatcher, SIGNAL(directoryChanged(QString)), this, SLOT(monitoredDirectoryChanged(QString)));
    connect(this, SIGNAL(rowsMoved(const QModelIndex&,int,int,const QModelIndex&,int)), this, SLOT(savePositions()));
    // watch for changes to order
    QSettings launcherSettings("nemomobile", "lipstick");
    _settingsPath = launcherSettings.fileName();
    _fileSystemWatcher->addPath(_settingsPath);
    connect(_fileSystemWatcher, SIGNAL(fileChanged(QString)), this, SLOT(monitoredFileChanged(QString)));
}

LauncherModel::~LauncherModel()
{
}

void LauncherModel::monitoredDirectoryChanged(const QString &changedPath)
{
    QFileInfoList fileInfoList = QDir(changedPath).entryInfoList(QStringList() << "*.desktop", QDir::Files);

    // Find removed and invalidated desktop entries
    foreach (LauncherItem *item, *getList<LauncherItem>()) {
        bool isValid = false;
        foreach (const QFileInfo &fileInfo, fileInfoList) {
            if (fileInfo.absoluteFilePath() == item->filePath()) {
                isValid = item->isStillValid() && item->shouldDisplay();
                break;
            }
        }

        if (!isValid) {
            LAUNCHER_DEBUG(item->filePath() << "no longer a valid .desktop entry");
            removeItem(item);
        }
    }

    QMap<int, LauncherItem *> itemsWithPositions;
    QSettings launcherSettings("nemomobile", "lipstick");
    QSettings globalSettings("/usr/share/lipstick/lipstick.conf", QSettings::IniFormat);

    // Finding newly added desktop entries
    foreach (const QFileInfo &fileInfo, fileInfoList) {
        QString filePath = fileInfo.absoluteFilePath();
        if (!_fileSystemWatcher->files().contains(filePath)) {
            _fileSystemWatcher->addPath(filePath);
        }

        if (itemInModel(filePath) == 0) {
            addItemIfValid(filePath, itemsWithPositions, launcherSettings, globalSettings);
        }
    }

    reorderItems(itemsWithPositions);

    savePositions();
}

void LauncherModel::monitoredFileChanged(const QString &changedPath)
{
    if (changedPath == _settingsPath) {
        loadPositions();
    } else {
        LauncherItem *item = itemInModel(changedPath);
        if (item == 0) {
            QMap<int, LauncherItem *> itemsWithPositions;
            QSettings launcherSettings("nemomobile", "lipstick");
            QSettings globalSettings("/usr/share/lipstick/lipstick.conf", QSettings::IniFormat);
            addItemIfValid(changedPath, itemsWithPositions, launcherSettings, globalSettings);
            reorderItems(itemsWithPositions);
            savePositions();
        } else if (!(item->isStillValid() && item->shouldDisplay())) {
            LAUNCHER_DEBUG(item->filePath() << "no longer a valid .desktop entry");
            removeItem(item);
        }
    }
}

void LauncherModel::loadPositions()
{
    QMap<int, LauncherItem *> itemsWithPositions;
    QSettings launcherSettings("nemomobile", "lipstick");
    QSettings globalSettings("/usr/share/lipstick/lipstick.conf", QSettings::IniFormat);

    QList<LauncherItem *> *currentLauncherList = getList<LauncherItem>();
    foreach (LauncherItem *item, *currentLauncherList) {
        QVariant pos = launcherSettings.value("LauncherOrder/" + item->filePath());

        // fall back to vendor configuration if the user hasn't specified a location
        if (!pos.isValid()) {
            pos = globalSettings.value("LauncherOrder/" + item->filePath());
        }

        if (pos.isValid()) {
            int gridPos = pos.toInt();
            itemsWithPositions.insert(gridPos, item);
        }
    }

    reorderItems(itemsWithPositions);
}

void LauncherModel::reorderItems(const QMap<int, LauncherItem *> &itemsWithPositions)
{
    // QMap is key-ordered, the int here is the desired position in the launcher we want the item to appear
    // so, we'll iterate from the lowest desired position to the highest, and move the items there.
    for (QMap<int, LauncherItem *>::ConstIterator it = itemsWithPositions.constBegin();
         it != itemsWithPositions.constEnd(); ++it) {
        LauncherItem *item = it.value();
        int gridPos = it.key();
        LAUNCHER_DEBUG("Moving" << item->filePath() << "to" << gridPos);

        if (gridPos < 0 || gridPos >= itemCount()) {
            LAUNCHER_DEBUG("Invalid planned position for" << item->filePath());
            continue;
        }

        int currentPos = indexOf(item);
        Q_ASSERT(currentPos >= 0);
        if (currentPos == -1)
            continue;

        if (gridPos == currentPos)
            continue;

        move(currentPos, gridPos);
    }
}

QStringList LauncherModel::directories() const
{
    return _fileSystemWatcher->directories();
}

void LauncherModel::setDirectories(QStringList newDirectories)
{
    _fileSystemWatcher->removePaths(_fileSystemWatcher->directories());

    foreach (const QString &path, newDirectories) {
        if (!path.startsWith('/')) {
            LAUNCHER_DEBUG(Q_FUNC_INFO << "Not an absolute path, not adding" << path);
            continue;
        }

        _fileSystemWatcher->addPath(path);
        monitoredDirectoryChanged(path);
    }

    emit this->directoriesChanged();
}

void LauncherModel::savePositions()
{
    QSettings launcherSettings("nemomobile", "lipstick");
    _fileSystemWatcher->removePath(launcherSettings.fileName());
    QList<LauncherItem *> *currentLauncherList = getList<LauncherItem>();

    int pos = 0;
    foreach (LauncherItem *item, *currentLauncherList) {
        launcherSettings.setValue("LauncherOrder/" + item->filePath(), pos);
        ++pos;
    }

    launcherSettings.sync();
    _fileSystemWatcher->addPath(launcherSettings.fileName());
}

LauncherItem *LauncherModel::itemInModel(const QString &path)
{
    foreach (LauncherItem *item, *getList<LauncherItem>()) {
        if (item->filePath() == path) {
            return item;
        }
    }
    return 0;
}

void LauncherModel::addItemIfValid(const QString &path, QMap<int, LauncherItem *> &itemsWithPositions, QSettings &launcherSettings, QSettings &globalSettings)
{
    LAUNCHER_DEBUG("Creating LauncherItem for desktop entry" << path);
    LauncherItem *item = new LauncherItem(path, this);

    bool isValid = item->isValid();
    bool shouldDisplay = item->shouldDisplay();
    if (isValid && shouldDisplay) {
        addItem(item);

        QVariant pos = launcherSettings.value("LauncherOrder/" + item->filePath());

        // fall back to vendor configuration if the user hasn't specified a location
        if (!pos.isValid()) {
            pos = globalSettings.value("LauncherOrder/" + item->filePath());
        }

        if (pos.isValid()) {
            int gridPos = pos.toInt();
            itemsWithPositions.insert(gridPos, item);
            LAUNCHER_DEBUG("Planned move of" << item->filePath() << "to" << gridPos);
        }
    } else {
        LAUNCHER_DEBUG("Item" << path << (!isValid ? "is not valid" : "should not be displayed"));
        delete item;
    }
}
<commit_msg>Store the launcher icon positions when a .desktop file changes to be non-displayable<commit_after>
// This file is part of lipstick, a QML desktop library
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License version 2.1 as published by the Free Software Foundation
// and appearing in the file LICENSE.LGPL included in the packaging
// of this file.
//
// This code 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 Lesser General Public License for more details.
//
// Copyright (c) 2012, Timur Kristóf <venemo@fedoraproject.org>

#include <QDir>
#include <QFileSystemWatcher>
#include <QDebug>
#include <QSettings>

#include "launchermodel.h"

// Define this if you'd like to see debug messages from the launcher
#ifdef DEBUG_LAUNCHER
#define LAUNCHER_DEBUG(things) qDebug() << Q_FUNC_INFO << things
#else
#define LAUNCHER_DEBUG(things)
#endif

LauncherModel::LauncherModel(QObject *parent) :
    QObjectListModel(parent),
    _fileSystemWatcher(new QFileSystemWatcher(this))
{
    // This is the most common path for .desktop files in most distributions
    QString defaultAppsPath("/usr/share/applications");

    // Setting up the file system wacher
    _fileSystemWatcher->addPath(defaultAppsPath);
    monitoredDirectoryChanged(defaultAppsPath);
    connect(_fileSystemWatcher, SIGNAL(directoryChanged(QString)), this, SLOT(monitoredDirectoryChanged(QString)));
    connect(this, SIGNAL(rowsMoved(const QModelIndex&,int,int,const QModelIndex&,int)), this, SLOT(savePositions()));
    // watch for changes to order
    QSettings launcherSettings("nemomobile", "lipstick");
    _settingsPath = launcherSettings.fileName();
    _fileSystemWatcher->addPath(_settingsPath);
    connect(_fileSystemWatcher, SIGNAL(fileChanged(QString)), this, SLOT(monitoredFileChanged(QString)));
}

LauncherModel::~LauncherModel()
{
}

void LauncherModel::monitoredDirectoryChanged(const QString &changedPath)
{
    QFileInfoList fileInfoList = QDir(changedPath).entryInfoList(QStringList() << "*.desktop", QDir::Files);

    // Find removed and invalidated desktop entries
    foreach (LauncherItem *item, *getList<LauncherItem>()) {
        bool isValid = false;
        foreach (const QFileInfo &fileInfo, fileInfoList) {
            if (fileInfo.absoluteFilePath() == item->filePath()) {
                isValid = item->isStillValid() && item->shouldDisplay();
                break;
            }
        }

        if (!isValid) {
            LAUNCHER_DEBUG(item->filePath() << "no longer a valid .desktop entry");
            removeItem(item);
        }
    }

    QMap<int, LauncherItem *> itemsWithPositions;
    QSettings launcherSettings("nemomobile", "lipstick");
    QSettings globalSettings("/usr/share/lipstick/lipstick.conf", QSettings::IniFormat);

    // Finding newly added desktop entries
    foreach (const QFileInfo &fileInfo, fileInfoList) {
        QString filePath = fileInfo.absoluteFilePath();
        if (!_fileSystemWatcher->files().contains(filePath)) {
            _fileSystemWatcher->addPath(filePath);
        }

        if (itemInModel(filePath) == 0) {
            addItemIfValid(filePath, itemsWithPositions, launcherSettings, globalSettings);
        }
    }

    reorderItems(itemsWithPositions);

    savePositions();
}

void LauncherModel::monitoredFileChanged(const QString &changedPath)
{
    if (changedPath == _settingsPath) {
        loadPositions();
    } else {
        LauncherItem *item = itemInModel(changedPath);
        if (item == 0) {
            QMap<int, LauncherItem *> itemsWithPositions;
            QSettings launcherSettings("nemomobile", "lipstick");
            QSettings globalSettings("/usr/share/lipstick/lipstick.conf", QSettings::IniFormat);
            addItemIfValid(changedPath, itemsWithPositions, launcherSettings, globalSettings);
            reorderItems(itemsWithPositions);
            savePositions();
        } else if (!(item->isStillValid() && item->shouldDisplay())) {
            LAUNCHER_DEBUG(item->filePath() << "no longer a valid .desktop entry");
            removeItem(item);
            savePositions();
        }
    }
}

void LauncherModel::loadPositions()
{
    QMap<int, LauncherItem *> itemsWithPositions;
    QSettings launcherSettings("nemomobile", "lipstick");
    QSettings globalSettings("/usr/share/lipstick/lipstick.conf", QSettings::IniFormat);

    QList<LauncherItem *> *currentLauncherList = getList<LauncherItem>();
    foreach (LauncherItem *item, *currentLauncherList) {
        QVariant pos = launcherSettings.value("LauncherOrder/" + item->filePath());

        // fall back to vendor configuration if the user hasn't specified a location
        if (!pos.isValid()) {
            pos = globalSettings.value("LauncherOrder/" + item->filePath());
        }

        if (pos.isValid()) {
            int gridPos = pos.toInt();
            itemsWithPositions.insert(gridPos, item);
        }
    }

    reorderItems(itemsWithPositions);
}

void LauncherModel::reorderItems(const QMap<int, LauncherItem *> &itemsWithPositions)
{
    // QMap is key-ordered, the int here is the desired position in the launcher we want the item to appear
    // so, we'll iterate from the lowest desired position to the highest, and move the items there.
    for (QMap<int, LauncherItem *>::ConstIterator it = itemsWithPositions.constBegin();
         it != itemsWithPositions.constEnd(); ++it) {
        LauncherItem *item = it.value();
        int gridPos = it.key();
        LAUNCHER_DEBUG("Moving" << item->filePath() << "to" << gridPos);

        if (gridPos < 0 || gridPos >= itemCount()) {
            LAUNCHER_DEBUG("Invalid planned position for" << item->filePath());
            continue;
        }

        int currentPos = indexOf(item);
        Q_ASSERT(currentPos >= 0);
        if (currentPos == -1)
            continue;

        if (gridPos == currentPos)
            continue;

        move(currentPos, gridPos);
    }
}

QStringList LauncherModel::directories() const
{
    return _fileSystemWatcher->directories();
}

void LauncherModel::setDirectories(QStringList newDirectories)
{
    _fileSystemWatcher->removePaths(_fileSystemWatcher->directories());

    foreach (const QString &path, newDirectories) {
        if (!path.startsWith('/')) {
            LAUNCHER_DEBUG(Q_FUNC_INFO << "Not an absolute path, not adding" << path);
            continue;
        }

        _fileSystemWatcher->addPath(path);
        monitoredDirectoryChanged(path);
    }

    emit this->directoriesChanged();
}

void LauncherModel::savePositions()
{
    QSettings launcherSettings("nemomobile", "lipstick");
    _fileSystemWatcher->removePath(launcherSettings.fileName());
    QList<LauncherItem *> *currentLauncherList = getList<LauncherItem>();

    int pos = 0;
    foreach (LauncherItem *item, *currentLauncherList) {
        launcherSettings.setValue("LauncherOrder/" + item->filePath(), pos);
        ++pos;
    }

    launcherSettings.sync();
    _fileSystemWatcher->addPath(launcherSettings.fileName());
}

LauncherItem *LauncherModel::itemInModel(const QString &path)
{
    foreach (LauncherItem *item, *getList<LauncherItem>()) {
        if (item->filePath() == path) {
            return item;
        }
    }
    return 0;
}

void LauncherModel::addItemIfValid(const QString &path, QMap<int, LauncherItem *> &itemsWithPositions, QSettings &launcherSettings, QSettings &globalSettings)
{
    LAUNCHER_DEBUG("Creating LauncherItem for desktop entry" << path);
    LauncherItem *item = new LauncherItem(path, this);

    bool isValid = item->isValid();
    bool shouldDisplay = item->shouldDisplay();
    if (isValid && shouldDisplay) {
        addItem(item);

        QVariant pos = launcherSettings.value("LauncherOrder/" + item->filePath());

        // fall back to vendor configuration if the user hasn't specified a location
        if (!pos.isValid()) {
            pos = globalSettings.value("LauncherOrder/" + item->filePath());
        }

        if (pos.isValid()) {
            int gridPos = pos.toInt();
            itemsWithPositions.insert(gridPos, item);
            LAUNCHER_DEBUG("Planned move of" << item->filePath() << "to" << gridPos);
        }
    } else {
        LAUNCHER_DEBUG("Item" << path << (!isValid ? "is not valid" : "should not be displayed"));
        delete item;
    }
}
<|endoftext|>


<commit_before>#include <fstream>
#include <iostream>
#include <cstdlib>

#include "game.hpp"

using std::cout;
using std::cin;
using std::rand;

void Game::addShipFromPlayer(string, Board*)
{

}

void Game::addShipRandomly(string name, Board* board)
{
    bool valid = true;
    Ship ship;
    int length = getShipLengthFromName(name);

    ship.setLength(length);
    ship.setName(name);

    do
    {
        valid = true;

        int orientation = rand() % 2;
        int x = 0, y = 0;

        if (orientation == 1) // horizontal
        {
            x = rand() % (10 - length);
            y = rand() % 10;
            ship.setOrientation(HORIZONTAL);
        }
        else // vertical
        {
            x = rand() % 10;
            y = rand() % (10 - length);
            ship.setOrientation(VERTICAL);
        }

        ship.setPosX(x);
        ship.setPosY(y);

        try
        {
            board->addShip(ship);
        }
        catch (ExceptionShipPlacementOccupied)
        {
            valid = false;
        }
    } while (!valid);
}

void Game::readShips(Board *board)
{
    ifstream file("./ship_placement.csv");
    file.ignore(256, '\n'); // ignore first line

    for (int shipCount = 5; shipCount > 0; shipCount--)
    {
        string name;
        char x, y;
        char orientation;

        getline(file, name, ',');
        name = toLowercase(name);

        file >> x;
        file >> y;
        file.ignore(); // ignore comma

        file >> orientation;
        file.ignore(2); // go to next line

        Ship newShip = Ship(name, int(x - 'A'), int(y - '1'), orientation);

        try
        {
            board->addShip(newShip);
        }
        catch (ExceptionShipOutOfBounds)
        {
            clearScreen();
            cout << "The " << name << " from the file was out of bounds.\n\n"
            << "Would you like to:\n1) Enter a new position\n2) Get a random position";

            if (getMenuChoice(2) == 1)
            {
                addShipFromPlayer(name, board);
            }
            else
            {
                addShipRandomly(name, board);
            }
        }
        catch (ExceptionShipPlacementOccupied)
        {
            clearScreen();
            cout << "The position for the " << name << " read in from the file was occupied by another ship.\n\n"
            << "Would you like to:\n1) Enter a new position\n2) Get a random position";

            if (getMenuChoice(2) == 1)
            {
                addShipFromPlayer(name, board);
            }
            else
            {
                addShipRandomly(name, board);
            }
        }
    }

    file.close();
}

void Game::randomizeShips(Board *board)
{
    // Adds one ship of each kind to a random location
    // on the given board.

    do
    {
        clearScreen();
        board->removeShips();

        for (auto ship : SHIPTYPES)
        {
            addShipRandomly(ship.first, board);
        }

        board->printShipGrid();

    } while (getMenuChoice(2, "\nWould you like to keep these positions or generate a new fleet?\n1) Keep positions\n2) Generate new ships") == 2);
}

void Game::start()
{
    // This function sets up a game.
    // It prints the title, creates boards of specific types
    // (human or computer), gets the names of the players, and when the game
    // is over it asks if the players would like to play again.

    srand(int(time(NULL)));

    if (!debug)
    {
        // Display title
        clearScreen();
        cout << title;
        cout << setw(44) << "Cody Kelly" << endl;
        cout << setw(43) << "© 2017" << endl << endl;
        cout << "Press enter to continue.\n\n";
        cin.get();
    }

    do
    {
        // Display main menu
        clearScreen();
        cout << "\n\nWelcome to Battleship!\n\n";
        cout << "Main Menu\n1) Single player game\n2) Two player game";
        singlePlayer = getMenuChoice(2) == 1;
        clearScreen();

        if(singlePlayer)
        {
            // Setup single player game
            string name;
            boards[0] = new Board(Board::PlayerType::Human), boards[1] = new Board(Board::PlayerType::Computer);

            if (!debug)
            {
                cout << "Please enter your name: ";
                name = getStringInput();
                boards[0]->setName(name);
            }

            boards[1]->setName("Computer");

            readShips(boards[0]); // Read ships from file for player
            randomizeShips(boards[1]); // Get a random ship layout for AI
        }
        else
        {
            // Setup multiplayer game
            string name;

            boards[0] = new Board(Board::PlayerType::Human), boards[1] = new Board(Board::PlayerType::Human);

            cout << "Player 1, please enter your name: ";
            name = getStringInput();
            boards[0]->setName(name);

            clearScreen();
            cout << "Would you like to: \n";
            cout << "1) Choose ship locations manually or\n";
            cout << "2) Randomize ship locations";

            if (getMenuChoice(2) == 1)
            {
                for (auto ship : SHIPTYPES)
                {
                    addShipFromPlayer(ship.first, boards[0]);
                }
            }
            else
            {
                randomizeShips(boards[0]);
            }

            clearScreen();
            cout << "Player 2, please enter your name: ";
            name = getStringInput();
            boards[1]->setName(name);

            clearScreen();
            cout << "Would you like to: \n";
            cout << "1) Choose ship locations manually or\n";
            cout << "2) Randomize ship locations";

            if (getMenuChoice(2) == 1)
            {
                for (auto ship : SHIPTYPES)
                {
                    addShipFromPlayer(ship.first, boards[1]);
                }
            }
            else
            {
                randomizeShips(boards[1]);
            }
        }

        // Now that the game is set up, we may run it.
        run();

        // Delete all board pointers in boards array
        for (auto boardPointer : boards)
        {
            delete boardPointer;
        }

        clearScreen();

    } while (getMenuChoice(2, "Would you like to play again?\n1) Yes\n2) No") == 1);
}

ShotResult Game::playerAttack(int attackerIndex)
{
    Coordinate coord;
    bool validCoordinate = true;
    int otherPlayerIndex;
    ShotResult result;

    if (attackerIndex == 0)
    {
        otherPlayerIndex = 1;
    }
    else
    {
        otherPlayerIndex = 0;
    }

    cout << "Enter attack coordinate information:\n";

    do
    {
        try
        {
            bool validColumn = true;
            bool validRow = true;
            validCoordinate = true;

            // Get x coordinate
            do
            {
                char column;

                validColumn = true;

                cout << "Please enter a column letter (from A to J): ";
                cin >> column;
                column = toupper(column);

                if (!(column >= 'A' && column <= 'J'))
                {
                    validColumn = false;
                    cout << "\nInvalid column. Please enter a letter from A to J.\n";
                }
                else
                {
                    coord.x = int(column - 'A');
                }
            } while (!validColumn);

            // Get y coordinate
            do
            {
                int row;

                validRow = true;

                cout << "Please enter a row number (from 1 to 10): ";
                cin >> row;

                if (!(row >= 1 && row <= 10))
                {
                    validRow = false;
                    cout << "\nInvalid row. Please enter a number from 1 to 10.\n";
                }
                else
                {
                    coord.y = row - 1;
                }
            } while (!validRow);

            // Try attack
            result = boards[otherPlayerIndex]->attack(coord);
        }
        catch (ExceptionShotCoordinateOccupied)
        {
            cout << "\n\nThat position has been fired at already. Please choose another.\n";
            validCoordinate = false;
        }
    }
    while (!validCoordinate);

    return result;
}

void Game::run()
{
    string winner = "";
    ShotResult lastShot;
    int turnNumber = 1;

    while (true)
    {
        if (singlePlayer)
        {

        }
        else
        {
            for (int count = 0; count < 2; count++)
            {
                int otherPlayerIndex = 0;

                if (count == 0)
                {
                    otherPlayerIndex = 1;
                }
                else
                {
                    otherPlayerIndex = 0;
                }

                clearScreen();
                cout << "Your turn, " << boards[count]->getName() << ".\n";
                cout << "Press enter when ready.";
                cin.get();

                clearScreen();

                // First tell the player where the other player shot last.
                if (turnNumber != 1)
                {
                    cout << "Last enemy shot: " << char('A' + lastShot.shotPosition.x) << lastShot.shotPosition.y + 1;

                    if (lastShot.sunk)
                    {
                        cout << "\nThey sank your " << toLowercase(lastShot.shipName) << "!";
                    }
                    else if(lastShot.hit)
                    {
                        cout << "\nThey hit your " << toLowercase(lastShot.shipName) << "!";
                    }

                    cout << endl << endl;
                }

                // Display grids for player
                cout << *boards[count] << endl;

                // Get the player's choice for a shot and process it
                ShotResult shotResult = playerAttack(count);
                boards[count]->markShot(shotResult.shotPosition, shotResult.hit);

                // Give the player shot results..
                clearScreen();
                if (shotResult.hit)
                {
                    cout << "Hit!";

                    if (shotResult.sunk)
                    {
                        cout << "\nYou sank their " << toLowercase(shotResult.shipName) << "!";
                    }
                }
                else
                {
                    cout << "Miss.";
                }

                cout << "\n\nPress enter to continue.";
                cin.ignore();
                cin.get();

                // If the other player lost, then the current one won!
                if (boards[otherPlayerIndex]->getLost())
                {
                    clearScreen();
                    cout << "Congratulations, " << boards[count]->getName()
                    << "! You've sunk the enemy's entire fleet.\n\nYou win!!";
                    cout << "\n\nPress enter to continue.";
                    cin.get();
                    return;
                }

                lastShot = shotResult;
                turnNumber++;
            }
        }
    }
}
<commit_msg>Plays an alert sound on hit<commit_after>#include <fstream>
#include <iostream>
#include <cstdlib>

#include "game.hpp"

using std::cout;
using std::cin;
using std::rand;

void Game::addShipFromPlayer(string, Board*)
{

}

void Game::addShipRandomly(string name, Board* board)
{
    bool valid = true;
    Ship ship;
    int length = getShipLengthFromName(name);

    ship.setLength(length);
    ship.setName(name);

    do
    {
        valid = true;

        int orientation = rand() % 2;
        int x = 0, y = 0;

        if (orientation == 1) // horizontal
        {
            x = rand() % (10 - length);
            y = rand() % 10;
            ship.setOrientation(HORIZONTAL);
        }
        else // vertical
        {
            x = rand() % 10;
            y = rand() % (10 - length);
            ship.setOrientation(VERTICAL);
        }

        ship.setPosX(x);
        ship.setPosY(y);

        try
        {
            board->addShip(ship);
        }
        catch (ExceptionShipPlacementOccupied)
        {
            valid = false;
        }
    } while (!valid);
}

void Game::readShips(Board *board)
{
    ifstream file("./ship_placement.csv");
    file.ignore(256, '\n'); // ignore first line

    for (int shipCount = 5; shipCount > 0; shipCount--)
    {
        string name;
        char x, y;
        char orientation;

        getline(file, name, ',');
        name = toLowercase(name);

        file >> x;
        file >> y;
        file.ignore(); // ignore comma

        file >> orientation;
        file.ignore(2); // go to next line

        Ship newShip = Ship(name, int(x - 'A'), int(y - '1'), orientation);

        try
        {
            board->addShip(newShip);
        }
        catch (ExceptionShipOutOfBounds)
        {
            clearScreen();
            cout << "The " << name << " from the file was out of bounds.\n\n"
            << "Would you like to:\n1) Enter a new position\n2) Get a random position";

            if (getMenuChoice(2) == 1)
            {
                addShipFromPlayer(name, board);
            }
            else
            {
                addShipRandomly(name, board);
            }
        }
        catch (ExceptionShipPlacementOccupied)
        {
            clearScreen();
            cout << "The position for the " << name << " read in from the file was occupied by another ship.\n\n"
            << "Would you like to:\n1) Enter a new position\n2) Get a random position";

            if (getMenuChoice(2) == 1)
            {
                addShipFromPlayer(name, board);
            }
            else
            {
                addShipRandomly(name, board);
            }
        }
    }

    file.close();
}

void Game::randomizeShips(Board *board)
{
    // Adds one ship of each kind to a random location
    // on the given board.

    do
    {
        clearScreen();
        board->removeShips();

        for (auto ship : SHIPTYPES)
        {
            addShipRandomly(ship.first, board);
        }

        board->printShipGrid();

    } while (getMenuChoice(2, "\nWould you like to keep these positions or generate a new fleet?\n1) Keep positions\n2) Generate new ships") == 2);
}

void Game::start()
{
    // This function sets up a game.
    // It prints the title, creates boards of specific types
    // (human or computer), gets the names of the players, and when the game
    // is over it asks if the players would like to play again.

    srand(int(time(NULL)));

    if (!debug)
    {
        // Display title
        clearScreen();
        cout << title;
        cout << setw(44) << "Cody Kelly" << endl;
        cout << setw(43) << "© 2017" << endl << endl;
        cout << "Press enter to continue.\n\n";
        cin.get();
    }

    do
    {
        // Display main menu
        clearScreen();
        cout << "\n\nWelcome to Battleship!\n\n";
        cout << "Main Menu\n1) Single player game\n2) Two player game";
        singlePlayer = getMenuChoice(2) == 1;
        clearScreen();

        if(singlePlayer)
        {
            // Setup single player game
            string name;
            boards[0] = new Board(Board::PlayerType::Human), boards[1] = new Board(Board::PlayerType::Computer);

            if (!debug)
            {
                cout << "Please enter your name: ";
                name = getStringInput();
                boards[0]->setName(name);
            }

            boards[1]->setName("Computer");

            readShips(boards[0]); // Read ships from file for player
            randomizeShips(boards[1]); // Get a random ship layout for AI
        }
        else
        {
            // Setup multiplayer game
            string name;

            boards[0] = new Board(Board::PlayerType::Human), boards[1] = new Board(Board::PlayerType::Human);

            cout << "Player 1, please enter your name: ";
            name = getStringInput();
            boards[0]->setName(name);

            clearScreen();
            cout << "Would you like to: \n";
            cout << "1) Choose ship locations manually or\n";
            cout << "2) Randomize ship locations";

            if (getMenuChoice(2) == 1)
            {
                for (auto ship : SHIPTYPES)
                {
                    addShipFromPlayer(ship.first, boards[0]);
                }
            }
            else
            {
                randomizeShips(boards[0]);
            }

            clearScreen();
            cout << "Player 2, please enter your name: ";
            name = getStringInput();
            boards[1]->setName(name);

            clearScreen();
            cout << "Would you like to: \n";
            cout << "1) Choose ship locations manually or\n";
            cout << "2) Randomize ship locations";

            if (getMenuChoice(2) == 1)
            {
                for (auto ship : SHIPTYPES)
                {
                    addShipFromPlayer(ship.first, boards[1]);
                }
            }
            else
            {
                randomizeShips(boards[1]);
            }
        }

        // Now that the game is set up, we may run it.
        run();

        // Delete all board pointers in boards array
        for (auto boardPointer : boards)
        {
            delete boardPointer;
        }

        clearScreen();

    } while (getMenuChoice(2, "Would you like to play again?\n1) Yes\n2) No") == 1);
}

ShotResult Game::playerAttack(int attackerIndex)
{
    Coordinate coord;
    bool validCoordinate = true;
    int otherPlayerIndex;
    ShotResult result;

    if (attackerIndex == 0)
    {
        otherPlayerIndex = 1;
    }
    else
    {
        otherPlayerIndex = 0;
    }

    cout << "Enter attack coordinate information:\n";

    do
    {
        try
        {
            bool validColumn = true;
            bool validRow = true;
            validCoordinate = true;

            // Get x coordinate
            do
            {
                char column;

                validColumn = true;

                cout << "Please enter a column letter (from A to J): ";
                cin >> column;
                column = toupper(column);

                if (!(column >= 'A' && column <= 'J'))
                {
                    validColumn = false;
                    cout << "\nInvalid column. Please enter a letter from A to J.\n";
                }
                else
                {
                    coord.x = int(column - 'A');
                }
            } while (!validColumn);

            // Get y coordinate
            do
            {
                int row;

                validRow = true;

                cout << "Please enter a row number (from 1 to 10): ";
                cin >> row;

                if (!(row >= 1 && row <= 10))
                {
                    validRow = false;
                    cout << "\nInvalid row. Please enter a number from 1 to 10.\n";
                }
                else
                {
                    coord.y = row - 1;
                }
            } while (!validRow);

            // Try attack
            result = boards[otherPlayerIndex]->attack(coord);
        }
        catch (ExceptionShotCoordinateOccupied)
        {
            cout << "\n\nThat position has been fired at already. Please choose another.\n";
            validCoordinate = false;
        }
    }
    while (!validCoordinate);

    return result;
}

void Game::run()
{
    string winner = "";
    ShotResult lastShot;
    int turnNumber = 1;

    while (true)
    {
        if (singlePlayer)
        {

        }
        else
        {
            for (int count = 0; count < 2; count++)
            {
                int otherPlayerIndex = 0;

                if (count == 0)
                {
                    otherPlayerIndex = 1;
                }
                else
                {
                    otherPlayerIndex = 0;
                }

                clearScreen();
                cout << "Your turn, " << boards[count]->getName() << ".\n";
                cout << "Press enter when ready.";
                cin.get();

                clearScreen();

                // First tell the player where the other player shot last.
                if (turnNumber != 1)
                {
                    cout << "Last enemy shot: " << char('A' + lastShot.shotPosition.x) << lastShot.shotPosition.y + 1;

                    if (lastShot.sunk)
                    {
                        cout << "\nThey sank your " << toLowercase(lastShot.shipName) << "!";
                    }
                    else if(lastShot.hit)
                    {
                        cout << "\nThey hit your " << toLowercase(lastShot.shipName) << "!";
                    }

                    cout << endl << endl;
                }

                // Display grids for player
                cout << *boards[count] << endl;

                // Get the player's choice for a shot and process it
                ShotResult shotResult = playerAttack(count);
                boards[count]->markShot(shotResult.shotPosition, shotResult.hit);

                // Give the player shot results..
                clearScreen();
                if (shotResult.hit)
                {
                    cout << "\aHit!";

                    if (shotResult.sunk)
                    {
                        cout << "\nYou sank their " << toLowercase(shotResult.shipName) << "!";
                    }
                }
                else
                {
                    cout << "Miss.";
                }

                cout << "\n\nPress enter to continue.";
                cin.ignore();
                cin.get();

                // If the other player lost, then the current one won!
                if (boards[otherPlayerIndex]->getLost())
                {
                    clearScreen();
                    cout << "Congratulations, " << boards[count]->getName()
                    << "! You've sunk the enemy's entire fleet.\n\nYou win!!";
                    cout << "\n\nPress enter to continue.";
                    cin.get();
                    return;
                }

                lastShot = shotResult;
                turnNumber++;
            }
        }
    }
}
<|endoftext|>


<commit_before>#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "interpreter.h"
#include "symbols.h"
#include <forward_list>
#include <iostream>

using namespace Interpreter;
using namespace Symbols;
using namespace std;

Id::Id(const char *name) : name(name) {
}

int Id::Evaluate() // TODO: Allow more than just int
{
    const char* name = this->name;
    try
    {
        Object* object = current_symbol_table->Get(name);
        if(object->GetKind() != SymbolInt)
        {
            fprintf(stderr, "error: variable '%s' was not an int\n", name);
            exit(1);
        }
        int val = object->GetInt();
        return val;
    }
    catch(std::out_of_range e)
    {
        fprintf(stderr, "error: use of undeclared variable '%s'\n", name);
        exit(1);
    }
}

void Id::Assign(int val) { // TODO: Allow more than just int
    Object* object = new Object(val);
    current_symbol_table->Set(this->name, object);
}

Val::Val(int val) : val(val) {
}

int Val::Evaluate()
{
    return this->val;
}

Op::Op(const char *glyph) : glyph(glyph) {
}

Statements::Statements(Statement *statement, Statements *childStatements)
    : statement(statement), childStatements(childStatements)
{
}

void Statements::Execute()
{
    // fprintf(stderr, "Inside statements\n"); // TODO: Debug
    Statements *nexts = this;
    while(nexts != nullptr)
    {
       nexts->statement->Execute();
       nexts = nexts->childStatements;
    }
}

Assignment::Assignment(Id *id, Expression* right) : id(id), right(right) {
}

void Assignment::Execute() {
    int val = this->right->Evaluate();
    this->id->Assign(val);
}

Conditional::Conditional(Expression* condition, Statement* statement)
    : condition(condition), statement(statement) { }

void Conditional::Execute()
{
    int result = this->condition->Evaluate();
    if(result) {
        this->statement->Execute();
    }
}

Print::Print(Expression *expr) : expr(expr) { }

void Print::Execute()
{
    int result = this->expr->Evaluate();
    printf("%d\n", result);
}

ExpressionNode::ExpressionNode(Expression *left, Expression *right, Op* op)
    : left(left), right(right), op(op) { }

int ExpressionNode::Evaluate()
{
    const char* op = this->op->glyph;
    int left = this->left->Evaluate();
    int right = this->right->Evaluate();

    if(strcmp(op,"+")==0) {
        return left+right;
    } else if(strcmp(op,"-")==0) {
        return left-right;
    } else if(strcmp(op,"*")==0) {
        return left*right;
    } else if(strcmp(op,"/")==0) {
        return left/right;
    } else if(strcmp(op,"<")==0) {
        return left<right;
    } else if(strcmp(op,"<=")==0) {
        return left<=right;
    } else if(strcmp(op,">")==0) {
        return left>right;
    } else if(strcmp(op,">=")==0) {
        return left>=right;
    } else if(strcmp(op,"==")==0) {
        return left==right;
    } else if(strcmp(op,"!=")==0) {
        return left!=right;
    } else {
        fprintf(stderr,"fatal error: invalid op '%s'\n", op);
        exit(1);
    }
}

ProcedureDeclaration::ProcedureDeclaration(Id *id, forward_list<Id*>* arguments, Statements *statements)
    : id(id), arguments(arguments), statements(statements) { }

void ProcedureDeclaration::Execute()
{

    // Create object for procedure, with current symbol table as its closure
    Object* object = new Object(this, current_symbol_table);

    // Place this object in the current symbol table
    current_symbol_table->Set(this->id->name, object);

    // Note: The rest is not needed.
    //  the ProcedureDeclaration closure does not contain arguments or variables
    //  until it is called:

    // Create closure for this procedure definition
    // shared_ptr<SymbolTable> closure = make_shared<SymbolTable>(*current_symbol_table);

    // Place this object in the closure
    //closure->Set(this->id->name, object);

/* TODO: For debugging
    // fprintf(stderr, "Created function '%s' in closure %d\n", this->id->name, current_symbol_table->sequence); // TODO: Debugging

    // Get desired procedure object
    shared_ptr<Object> object2 = current_symbol_table->Get(this->id->name);

    // Assert  it's really a procedure (TODO: For debug)
    if(object2->GetKind() != SymbolProcedure)
    {
            fprintf(stderr, "error: '%s' failed to save into closure %d)\n", this->id->name, current_symbol_table->sequence);
            exit(1);
    }
*/
}

ProcedureCall::ProcedureCall(Id *id, forward_list<ProcedureCallArgument*>* arguments) : id(id), arguments(arguments)
{
}

typedef forward_list<Id*> argDefList;
typedef forward_list<Id*>::iterator argDefListIter;
typedef forward_list<ProcedureCallArgument*> argCallList;
typedef forward_list<ProcedureCallArgument*>::iterator argCallListIter;

void ProcedureCall::Execute()
{
    try
    {
        // Get procedure object out of current symbol table
        Object* object = current_symbol_table->Get(this->id->name);

        // Assert  it's really a procedure
        if(object->GetKind() != SymbolProcedure)
        {
            fprintf(stderr, "error: '%s' was not a procedure (closure %d)\n", this->id->name, current_symbol_table->sequence);
            exit(1);
        }

        // Create a list with all all FCD and FCA mappings
        forward_list<shared_ptr<pair<argCallList,argDefList>>> argList; // TODO: Wtf?

        /* TODO: Need Object class before this will work
        auto a = this->arguments;
        auto b = object->fVal->arguments;
        for(pair<argCallListIter,argDefListIter> i(a->begin(),b->begin());
            i.first !=  a->end() && i.second != b->end();
            ++i.first, ++i.second)
        {
            fprintf(stderr, "created new closure with arg=%s\n", (*i.second)->id->name); // TODO: Just doing this for debugging
            string argName = (*i.second)->id->name;
            shared_ptr<Symbol> argValue = make_shared<Symbol>(argName, (*i.first)->expression->Evaluate()); // TODO: Need to do this before entering closure!!!!!
            // ^ TODO:
            argCallList.push_front(make_shared<pair<argList,argDefList>>(argName,argValue));
        }
        */

        // Backup the current symbol table
        SymbolTableStateGuard guard();

        // Pull the procedure's closure
        SymbolTable* closure = object->closure;

        // Create a new closure with arguments added
        SymbolTable* closureWithArgs = new SymbolTable(*closure);

        // Pull out the FCA and FDA mappings and put them in the closure
        /* TODO: Need Objects before this will work
        for(shared_ptr<pair<argCallList,argDefList>> argNameAndValue : argList)
        {
            string argName = argNameAndValue->second;
            int argValue = argNameAndValue->first;
            closureWithArgs->Set(argName, argValue);
        }
        */

        current_symbol_table = closureWithArgs;

        // Execute the procedure
        //fprintf(stderr, "executing procedure '%s'\n", this->id->name); // TODO: Just doing this for debugging
        ProcedureDeclaration* assignment = object->GetProcedure();
        assignment->statements->Execute();
    }
    catch(std::out_of_range e)
    {
        fprintf(stderr, "error: use of undeclared function '%s'\n", this->id->name);
        exit(1);
    }
}

ProcedureCallArgument::ProcedureCallArgument(Expression* expression) : expression(expression)
{
}
<commit_msg>Fix lambda handling<commit_after>#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "interpreter.h"
#include "symbols.h"
#include <forward_list>
#include <iostream>

using namespace Interpreter;
using namespace Symbols;
using namespace std;

Id::Id(const char *name) : name(name) {
}

int Id::Evaluate() // TODO: Allow more than just int
{
    const char* name = this->name;
    try
    {
        Object* object = current_symbol_table->Get(name);
        if(object->GetKind() != SymbolInt)
        {
            fprintf(stderr, "error: variable '%s' was not an int\n", name);
            exit(1);
        }
        int val = object->GetInt();
        return val;
    }
    catch(std::out_of_range e)
    {
        fprintf(stderr, "error: use of undeclared variable '%s'\n", name);
        exit(1);
    }
}

void Id::Assign(int val) { // TODO: Allow more than just int
    Object* object = new Object(val);
    current_symbol_table->Set(this->name, object);
}

Val::Val(int val) : val(val) {
}

int Val::Evaluate()
{
    return this->val;
}

Op::Op(const char *glyph) : glyph(glyph) {
}

Statements::Statements(Statement *statement, Statements *childStatements)
    : statement(statement), childStatements(childStatements)
{
}

void Statements::Execute()
{
    // fprintf(stderr, "Inside statements\n"); // TODO: Debug
    Statements *nexts = this;
    while(nexts != nullptr)
    {
       nexts->statement->Execute();
       nexts = nexts->childStatements;
    }
}

Assignment::Assignment(Id *id, Expression* right) : id(id), right(right) {
}

void Assignment::Execute() {
    int val = this->right->Evaluate();
    this->id->Assign(val);
}

Conditional::Conditional(Expression* condition, Statement* statement)
    : condition(condition), statement(statement) { }

void Conditional::Execute()
{
    int result = this->condition->Evaluate();
    if(result) {
        this->statement->Execute();
    }
}

Print::Print(Expression *expr) : expr(expr) { }

void Print::Execute()
{
    int result = this->expr->Evaluate();
    printf("%d\n", result);
}

ExpressionNode::ExpressionNode(Expression *left, Expression *right, Op* op)
    : left(left), right(right), op(op) { }

int ExpressionNode::Evaluate()
{
    const char* op = this->op->glyph;
    int left = this->left->Evaluate();
    int right = this->right->Evaluate();

    if(strcmp(op,"+")==0) {
        return left+right;
    } else if(strcmp(op,"-")==0) {
        return left-right;
    } else if(strcmp(op,"*")==0) {
        return left*right;
    } else if(strcmp(op,"/")==0) {
        return left/right;
    } else if(strcmp(op,"<")==0) {
        return left<right;
    } else if(strcmp(op,"<=")==0) {
        return left<=right;
    } else if(strcmp(op,">")==0) {
        return left>right;
    } else if(strcmp(op,">=")==0) {
        return left>=right;
    } else if(strcmp(op,"==")==0) {
        return left==right;
    } else if(strcmp(op,"!=")==0) {
        return left!=right;
    } else {
        fprintf(stderr,"fatal error: invalid op '%s'\n", op);
        exit(1);
    }
}

ProcedureDeclaration::ProcedureDeclaration(Id *id, forward_list<Id*>* arguments, Statements *statements)
    : id(id), arguments(arguments), statements(statements) { }

void ProcedureDeclaration::Execute()
{
    // Clone the current symbol table into a closure
    SymbolTable* closure = new SymbolTable(*current_symbol_table);

    // Create object for procedure, with newly created closure as its closure
    Object* procedure = new Object(this, closure);

    // Place this object in the current symbol table
    current_symbol_table->Set(this->id->name, procedure);

    // Note: The rest is not needed.
    //  the ProcedureDeclaration closure does not contain arguments or variables
    //  until it is called:

    // Create closure for this procedure definition
    // shared_ptr<SymbolTable> closure = make_shared<SymbolTable>(*current_symbol_table);

    // Place this object in the closure
    //closure->Set(this->id->name, object);

/* TODO: For debugging
    // fprintf(stderr, "Created function '%s' in closure %d\n", this->id->name, current_symbol_table->sequence); // TODO: Debugging

    // Get desired procedure object
    shared_ptr<Object> object2 = current_symbol_table->Get(this->id->name);

    // Assert  it's really a procedure (TODO: For debug)
    if(object2->GetKind() != SymbolProcedure)
    {
            fprintf(stderr, "error: '%s' failed to save into closure %d)\n", this->id->name, current_symbol_table->sequence);
            exit(1);
    }
*/
}

ProcedureCall::ProcedureCall(Id *id, forward_list<ProcedureCallArgument*>* arguments) : id(id), arguments(arguments)
{
}

typedef forward_list<Id*> argDefList_t;
typedef forward_list<Id*>::iterator argDefListIter_t;
typedef forward_list<ProcedureCallArgument*> argCallList_t;
typedef forward_list<ProcedureCallArgument*>::iterator argCallListIter_t;

void ProcedureCall::Execute()
{
    try
    {
        // Get procedure object out of current symbol table
        Object* procedure = current_symbol_table->Get(this->id->name);

        // Assert  it's really a procedure
        if(procedure->GetKind() != SymbolProcedure)
        {
            fprintf(stderr, "error: '%s' was not a procedure (closure %d)\n", this->id->name, current_symbol_table->sequence);
            exit(1);
        }

        // Clone the procedure's closure, to which we will add arguments
        SymbolTable* closureWithArgs = new SymbolTable(*procedure->closure);

        // Populate the closureWithArgs with arguments
        fprintf(stderr, "Creating argument closure...\n"); // TODO: Just for debug
        argCallList_t* a = this->arguments;
        argDefList_t* b = procedure->fVal->arguments;

        for(pair<argCallListIter_t,argDefListIter_t> i(a->begin(),b->begin());
            i.first !=  a->end() && i.second != b->end();
            ++i.first, ++i.second)
        {
            ProcedureCallArgument* callArgument = (*i.first);
            Id* declaredArgument = (*i.second);
            fprintf(stderr, "adding arg, name='%s'\n", declaredArgument->name); // TODO: Just for debug
            const char *argName = declaredArgument->name;
            Object* argValue = new Object(callArgument->expression->Evaluate());
            closureWithArgs->Set(argName, argValue);
        }

        // Backup the current symbol table
        SymbolTableStateGuard guard();

        // Use our new closureWithArgs during our function call
        current_symbol_table = closureWithArgs;

        // Execute the procedure
        fprintf(stderr, "executing procedure '%s'\n", this->id->name); // TODO: Just doing this for debugging
        ProcedureDeclaration* assignment = procedure->GetProcedure();
        assignment->statements->Execute();
    }
    catch(std::out_of_range e)
    {
        fprintf(stderr, "error: use of undeclared function '%s'\n", this->id->name);
        exit(1);
    }
}

ProcedureCallArgument::ProcedureCallArgument(Expression* expression) : expression(expression)
{
}
<|endoftext|>


<commit_before>#include "ideutils.h"

#include <QDir>
#include <QFileInfo>
#include <QCheckBox>
#include <QLineEdit>
#include <QSpinBox>
#include <QDoubleSpinBox>
#include <QComboBox>
#include <QGroupBox>
#include <QTableWidget>
#include <QPlainTextEdit>

namespace IDEUtils {

QString formatTime(qint64 time) {
    int hours =  time / 3600000;
    int minutes = (time % 3600000) / 60000;
    int seconds = (time % 60000) / 1000;
    int msec = (time % 1000);
    QString elapsed;
    if (hours > 0) {
        elapsed += QString("%1h ").arg(hours);
    }
    if (hours > 0 || minutes > 0) {
        elapsed += QString("%1m ").arg(minutes);
    }
    if (hours > 0 || minutes > 0 || seconds > 0) {
        elapsed += QString("%1s").arg(seconds);
    }
    if (hours==0 && minutes==0) {
        if (seconds > 0) {
            elapsed += " ";
        }
        elapsed += QString("%1msec").arg(msec);
    }
    return elapsed;
}

bool isChildPath(const QString& parent, const QString& child)
{
    return !QDir(parent).relativeFilePath(child).startsWith(".");
}

void watchChildChanges(QWidget* target, QObject* receiver, std::function<void()> action)
{
    for (auto widget : target->findChildren<QWidget*>()) {
        QCheckBox* checkBox;
        QLineEdit* lineEdit;
        QSpinBox* spinBox;
        QDoubleSpinBox* doubleSpinBox;
        QComboBox* comboBox;
        QGroupBox* groupBox;
        QTableWidget* tableWidget;
        QPlainTextEdit* plainTextEdit;

        if ((checkBox = qobject_cast<QCheckBox*>(widget))) {
            QObject::connect(checkBox, &QCheckBox::stateChanged, receiver, [=] (int) { action(); });
        } else if ((lineEdit = qobject_cast<QLineEdit*>(widget))) {
            QObject::connect(lineEdit, &QLineEdit::textChanged, receiver, [=] (const QString&) { action(); });
        } else if ((spinBox = qobject_cast<QSpinBox*>(widget))) {
            QObject::connect(spinBox, QOverload<int>::of(&QSpinBox::valueChanged), receiver, [=] (int) { action(); });
        } else if ((doubleSpinBox = qobject_cast<QDoubleSpinBox*>(widget))) {
            QObject::connect(doubleSpinBox, QOverload<double>::of(&QDoubleSpinBox::valueChanged), receiver, [=] (double) { action(); });
        } else if ((comboBox = qobject_cast<QComboBox*>(widget))) {
            QObject::connect(comboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), receiver, [=] (int) { action(); });
        } else if ((groupBox = qobject_cast<QGroupBox*>(widget))) {
            QObject::connect(groupBox, &QGroupBox::toggled, receiver, [=] (bool) { action(); });
        } else if ((tableWidget = qobject_cast<QTableWidget*>(widget))) {
            QObject::connect(tableWidget, &QTableWidget::cellChanged, receiver, [=] (int, int) { action(); });
        } else if ((plainTextEdit = qobject_cast<QPlainTextEdit*>(widget))) {
            QObject::connect(plainTextEdit, &QPlainTextEdit::textChanged,receiver, [=] () { action(); });
        }
    }
}

QFont fontFromString(const QString& s)
{
    QFont font;
    if (font.fromString(s)) {
        return font;
    }

    QStringList families({"Menlo", "Consolas", "Courier New"});

    font.setPointSize(13);
    font.setStyleHint(QFont::TypeWriter);
    for (auto& family : families) {
        font.setFamily(family);
        if (font.exactMatch()) {
            break;
        }
    }
    return font;
}

}
<commit_msg>Don't call QFont::fromString with empty string<commit_after>#include "ideutils.h"

#include <QDir>
#include <QFileInfo>
#include <QCheckBox>
#include <QLineEdit>
#include <QSpinBox>
#include <QDoubleSpinBox>
#include <QComboBox>
#include <QGroupBox>
#include <QTableWidget>
#include <QPlainTextEdit>

namespace IDEUtils {

QString formatTime(qint64 time) {
    int hours =  time / 3600000;
    int minutes = (time % 3600000) / 60000;
    int seconds = (time % 60000) / 1000;
    int msec = (time % 1000);
    QString elapsed;
    if (hours > 0) {
        elapsed += QString("%1h ").arg(hours);
    }
    if (hours > 0 || minutes > 0) {
        elapsed += QString("%1m ").arg(minutes);
    }
    if (hours > 0 || minutes > 0 || seconds > 0) {
        elapsed += QString("%1s").arg(seconds);
    }
    if (hours==0 && minutes==0) {
        if (seconds > 0) {
            elapsed += " ";
        }
        elapsed += QString("%1msec").arg(msec);
    }
    return elapsed;
}

bool isChildPath(const QString& parent, const QString& child)
{
    return !QDir(parent).relativeFilePath(child).startsWith(".");
}

void watchChildChanges(QWidget* target, QObject* receiver, std::function<void()> action)
{
    for (auto widget : target->findChildren<QWidget*>()) {
        QCheckBox* checkBox;
        QLineEdit* lineEdit;
        QSpinBox* spinBox;
        QDoubleSpinBox* doubleSpinBox;
        QComboBox* comboBox;
        QGroupBox* groupBox;
        QTableWidget* tableWidget;
        QPlainTextEdit* plainTextEdit;

        if ((checkBox = qobject_cast<QCheckBox*>(widget))) {
            QObject::connect(checkBox, &QCheckBox::stateChanged, receiver, [=] (int) { action(); });
        } else if ((lineEdit = qobject_cast<QLineEdit*>(widget))) {
            QObject::connect(lineEdit, &QLineEdit::textChanged, receiver, [=] (const QString&) { action(); });
        } else if ((spinBox = qobject_cast<QSpinBox*>(widget))) {
            QObject::connect(spinBox, QOverload<int>::of(&QSpinBox::valueChanged), receiver, [=] (int) { action(); });
        } else if ((doubleSpinBox = qobject_cast<QDoubleSpinBox*>(widget))) {
            QObject::connect(doubleSpinBox, QOverload<double>::of(&QDoubleSpinBox::valueChanged), receiver, [=] (double) { action(); });
        } else if ((comboBox = qobject_cast<QComboBox*>(widget))) {
            QObject::connect(comboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), receiver, [=] (int) { action(); });
        } else if ((groupBox = qobject_cast<QGroupBox*>(widget))) {
            QObject::connect(groupBox, &QGroupBox::toggled, receiver, [=] (bool) { action(); });
        } else if ((tableWidget = qobject_cast<QTableWidget*>(widget))) {
            QObject::connect(tableWidget, &QTableWidget::cellChanged, receiver, [=] (int, int) { action(); });
        } else if ((plainTextEdit = qobject_cast<QPlainTextEdit*>(widget))) {
            QObject::connect(plainTextEdit, &QPlainTextEdit::textChanged,receiver, [=] () { action(); });
        }
    }
}

QFont fontFromString(const QString& s)
{
    QFont font;
    if (!s.isEmpty() && font.fromString(s)) {
        return font;
    }

    QStringList families({"Menlo", "Consolas", "Courier New"});

    font.setPointSize(13);
    font.setStyleHint(QFont::TypeWriter);
    for (auto& family : families) {
        font.setFamily(family);
        if (font.exactMatch()) {
            break;
        }
    }
    return font;
}

}
<|endoftext|>


<commit_before>/*
 *
 *    Copyright (c) 2016-2017 Nest Labs, Inc.
 *    All rights reserved.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

/**
 *    @file
 *      Implementation of a simple std::map based persisted store.
 *
 */

#ifndef __STDC_FORMAT_MACROS
#define __STDC_FORMAT_MACROS
#endif

#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS
#endif

#include <stdint.h>
#include <string.h>
#include <unistd.h>

#include "ToolCommon.h"
#include <Weave/Support/Base64.h>
#include <Weave/Support/CodeUtils.h>
#include <Weave/Support/platform/PersistedStorage.h>

#include "TestPersistedStorageImplementation.h"

std::map<std::string, std::string> sPersistentStore;

FILE *sPersistentStoreFile = NULL;

namespace nl {
namespace Weave {
namespace Platform {
namespace PersistedStorage {

static void RemoveEndOfLineSymbol(char *str)
{
    size_t len = strlen(str) - 1;
    if (str[len] == '\n')
        str[len] = '\0';
}

static WEAVE_ERROR GetCounterValueFromFile(const char *aKey, uint32_t &aValue)
{
    WEAVE_ERROR err = WEAVE_NO_ERROR;
    char key[WEAVE_CONFIG_PERSISTED_STORAGE_MAX_KEY_LENGTH];
    char value[WEAVE_CONFIG_PERSISTED_STORAGE_MAX_VALUE_LENGTH];

    rewind(sPersistentStoreFile);

    while (fgets(key, sizeof(key), sPersistentStoreFile) != NULL)
    {
        RemoveEndOfLineSymbol(key);

        if (strcmp(key, aKey) == 0)
        {
            if (fgets(value, sizeof(value), sPersistentStoreFile) == NULL)
            {
                err = WEAVE_ERROR_PERSISTED_STORAGE_FAIL;
            }
            else
            {
                RemoveEndOfLineSymbol(value);

                if (!ParseInt(value, aValue, 0))
                    err = WEAVE_ERROR_PERSISTED_STORAGE_FAIL;
            }

            ExitNow();
        }
    }

    err = WEAVE_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND;

exit:
    return err;
}

static WEAVE_ERROR SaveCounterValueToFile(const char *aKey, uint32_t aValue)
{
    WEAVE_ERROR err = WEAVE_NO_ERROR;
    int res;
    char key[WEAVE_CONFIG_PERSISTED_STORAGE_MAX_KEY_LENGTH];
    char value[WEAVE_CONFIG_PERSISTED_STORAGE_MAX_VALUE_LENGTH];

    snprintf(value, sizeof(value), "0x%08X\n", aValue);

    rewind(sPersistentStoreFile);

    // Find the stored counter value location in the file.
    while (fgets(key, sizeof(key), sPersistentStoreFile) != NULL)
    {
        RemoveEndOfLineSymbol(key);

        // If value is found in the file then override it.
        if (strcmp(key, aKey) == 0)
        {
            res = fputs(value, sPersistentStoreFile);
            VerifyOrExit(res != EOF, err = WEAVE_ERROR_PERSISTED_STORAGE_FAIL);

            ExitNow();
        }
    }

    // If value not found in the file then write the counter key and
    // the counter value to the end of the file.
    res = fputs(aKey, sPersistentStoreFile);
    VerifyOrExit(res != EOF, err = WEAVE_ERROR_PERSISTED_STORAGE_FAIL);

    res = fputs("\n", sPersistentStoreFile);
    VerifyOrExit(res != EOF, err = WEAVE_ERROR_PERSISTED_STORAGE_FAIL);

    res = fputs(value, sPersistentStoreFile);
    VerifyOrExit(res != EOF, err = WEAVE_ERROR_PERSISTED_STORAGE_FAIL);

exit:
    fflush(sPersistentStoreFile);
    return err;
}

WEAVE_ERROR Read(const char *aKey, uint32_t &aValue)
{
    WEAVE_ERROR err = WEAVE_NO_ERROR;
    std::map<std::string, std::string>::iterator it;

    VerifyOrExit(aKey != NULL, err = WEAVE_ERROR_INVALID_ARGUMENT);
    VerifyOrExit(strlen(aKey) <= WEAVE_CONFIG_PERSISTED_STORAGE_MAX_KEY_LENGTH,
                 err = WEAVE_ERROR_INVALID_STRING_LENGTH);

    if (sPersistentStoreFile)
    {
        err = GetCounterValueFromFile(aKey, aValue);
    }
    else
    {
        it = sPersistentStore.find(aKey);
        VerifyOrExit(it != sPersistentStore.end(), err = WEAVE_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND);

        size_t aValueLength = Base64Decode(it->second.c_str(), strlen(it->second.c_str()), (uint8_t *)&aValue);
        VerifyOrExit(aValueLength == sizeof(uint32_t), err = WEAVE_ERROR_PERSISTED_STORAGE_FAIL);
    }

exit:
    return err;
}

WEAVE_ERROR Write(const char *aKey, uint32_t aValue)
{
    WEAVE_ERROR err = WEAVE_NO_ERROR;

    VerifyOrExit(aKey != NULL, err = WEAVE_ERROR_INVALID_ARGUMENT);
    VerifyOrExit(strlen(aKey) <= WEAVE_CONFIG_PERSISTED_STORAGE_MAX_KEY_LENGTH,
                 err = WEAVE_ERROR_INVALID_STRING_LENGTH);

    if (sPersistentStoreFile)
    {
        err = SaveCounterValueToFile(aKey, aValue);
    }
    else
    {
        char encodedValue[2 * sizeof(uint32_t)];

        memset(encodedValue, 0, sizeof(encodedValue));
        Base64Encode((uint8_t *)&aValue, sizeof(aValue), encodedValue);

        sPersistentStore[aKey] = encodedValue;
    }

exit:
    return err;
}

} // PersistentStorage
} // Platform
} // Weave
} // nl
<commit_msg>Fixed padding error and off by one error<commit_after>/*
 *
 *    Copyright (c) 2016-2017 Nest Labs, Inc.
 *    All rights reserved.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

/**
 *    @file
 *      Implementation of a simple std::map based persisted store.
 *
 */

#ifndef __STDC_FORMAT_MACROS
#define __STDC_FORMAT_MACROS
#endif

#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS
#endif

#include <stdint.h>
#include <string.h>
#include <unistd.h>

#include "ToolCommon.h"
#include <Weave/Support/Base64.h>
#include <Weave/Support/CodeUtils.h>
#include <Weave/Support/platform/PersistedStorage.h>

#include "TestPersistedStorageImplementation.h"

std::map<std::string, std::string> sPersistentStore;

FILE *sPersistentStoreFile = NULL;

namespace nl {
namespace Weave {
namespace Platform {
namespace PersistedStorage {

static void RemoveEndOfLineSymbol(char *str)
{
    size_t len = strlen(str) - 1;
    if (str[len] == '\n')
        str[len] = '\0';
}

static WEAVE_ERROR GetCounterValueFromFile(const char *aKey, uint32_t &aValue)
{
    WEAVE_ERROR err = WEAVE_NO_ERROR;
    char key[WEAVE_CONFIG_PERSISTED_STORAGE_MAX_KEY_LENGTH];
    char value[WEAVE_CONFIG_PERSISTED_STORAGE_MAX_VALUE_LENGTH];

    rewind(sPersistentStoreFile);

    while (fgets(key, sizeof(key), sPersistentStoreFile) != NULL)
    {
        RemoveEndOfLineSymbol(key);

        if (strcmp(key, aKey) == 0)
        {
            if (fgets(value, sizeof(value), sPersistentStoreFile) == NULL)
            {
                err = WEAVE_ERROR_PERSISTED_STORAGE_FAIL;
            }
            else
            {
                RemoveEndOfLineSymbol(value);

                if (!ParseInt(value, aValue, 0))
                    err = WEAVE_ERROR_PERSISTED_STORAGE_FAIL;
            }

            ExitNow();
        }
    }

    err = WEAVE_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND;

exit:
    return err;
}

static WEAVE_ERROR SaveCounterValueToFile(const char *aKey, uint32_t aValue)
{
    WEAVE_ERROR err = WEAVE_NO_ERROR;
    int res;
    char key[WEAVE_CONFIG_PERSISTED_STORAGE_MAX_KEY_LENGTH];
    char value[WEAVE_CONFIG_PERSISTED_STORAGE_MAX_VALUE_LENGTH];

    snprintf(value, sizeof(value), "0x%08X\n", aValue);

    rewind(sPersistentStoreFile);

    // Find the stored counter value location in the file.
    while (fgets(key, sizeof(key), sPersistentStoreFile) != NULL)
    {
        RemoveEndOfLineSymbol(key);

        // If value is found in the file then override it.
        if (strcmp(key, aKey) == 0)
        {
            res = fputs(value, sPersistentStoreFile);
            VerifyOrExit(res != EOF, err = WEAVE_ERROR_PERSISTED_STORAGE_FAIL);

            ExitNow();
        }
    }

    // If value not found in the file then write the counter key and
    // the counter value to the end of the file.
    res = fputs(aKey, sPersistentStoreFile);
    VerifyOrExit(res != EOF, err = WEAVE_ERROR_PERSISTED_STORAGE_FAIL);

    res = fputs("\n", sPersistentStoreFile);
    VerifyOrExit(res != EOF, err = WEAVE_ERROR_PERSISTED_STORAGE_FAIL);

    res = fputs(value, sPersistentStoreFile);
    VerifyOrExit(res != EOF, err = WEAVE_ERROR_PERSISTED_STORAGE_FAIL);

exit:
    fflush(sPersistentStoreFile);
    return err;
}

WEAVE_ERROR Read(const char *aKey, uint32_t &aValue)
{
    WEAVE_ERROR err = WEAVE_NO_ERROR;
    std::map<std::string, std::string>::iterator it;

    VerifyOrExit(aKey != NULL, err = WEAVE_ERROR_INVALID_ARGUMENT);
    VerifyOrExit(strlen(aKey) <= WEAVE_CONFIG_PERSISTED_STORAGE_MAX_KEY_LENGTH,
                 err = WEAVE_ERROR_INVALID_STRING_LENGTH);

    if (sPersistentStoreFile)
    {
        err = GetCounterValueFromFile(aKey, aValue);
    }
    else
    {
        it = sPersistentStore.find(aKey);
        VerifyOrExit(it != sPersistentStore.end(), err = WEAVE_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND);

        size_t aValueLength = Base64Decode(it->second.c_str(), strlen(it->second.c_str()), (uint8_t *)&aValue);
        VerifyOrExit(aValueLength == sizeof(uint32_t), err = WEAVE_ERROR_PERSISTED_STORAGE_FAIL);
    }

exit:
    return err;
}

WEAVE_ERROR Write(const char *aKey, uint32_t aValue)
{
    WEAVE_ERROR err = WEAVE_NO_ERROR;

    VerifyOrExit(aKey != NULL, err = WEAVE_ERROR_INVALID_ARGUMENT);
    VerifyOrExit(strlen(aKey) <= WEAVE_CONFIG_PERSISTED_STORAGE_MAX_KEY_LENGTH,
                 err = WEAVE_ERROR_INVALID_STRING_LENGTH);

    if (sPersistentStoreFile)
    {
        err = SaveCounterValueToFile(aKey, aValue);
    }
    else
    {
        char encodedValue[((sizeof(uint32_t) + 2) / 3) * 4 + 1];

        memset(encodedValue, 0, sizeof(encodedValue));
        Base64Encode((uint8_t *)&aValue, sizeof(aValue), encodedValue);

        sPersistentStore[aKey] = encodedValue;
    }

exit:
    return err;
}

} // PersistentStorage
} // Platform
} // Weave
} // nl
<|endoftext|>