<commit_before>#pragma once

#include <utki/config.hpp>

#include "file.hpp"

namespace papki{

//TODO: doxygen
class root_dir : public file{
	std::unique_ptr<file> baseFile;
	std::string rootDir;

public:
	/**
	 * @param baseFile - a file to wrap.
	 * @param rootDir - path to the root directory to set. It should have trailing '/' character.
	 */
	root_dir(std::unique_ptr<file> baseFile, const std::string& rootDir) :
			baseFile(std::move(baseFile)),
			rootDir(rootDir)
	{
		if(!this->baseFile){
			throw std::invalid_argument("root_dir(): passed in base file pointer is null");
		}
		this->file::set_path_internal(std::string(this->baseFile->path()));
		this->baseFile->set_path(this->rootDir + this->path());
	}

	static std::unique_ptr<const root_dir> make(std::unique_ptr<const file> baseFile, const std::string& rootDir){
		return utki::make_unique<const root_dir>(std::unique_ptr<file>(const_cast<file*>(baseFile.release())), rootDir);
	}

	root_dir(const root_dir&) = delete;
	root_dir& operator=(const root_dir&) = delete;

private:
	void set_path_internal(std::string&& pathName)const override{
		this->file::set_path_internal(std::move(pathName));
		this->baseFile->set_path(this->rootDir + this->path());
	}

	void open_internal(mode io_mode)override{
		this->baseFile->open(io_mode);
	}

	void close_internal()const noexcept override{
		this->baseFile->close();
	}

	std::vector<std::string> list_dir(size_t maxEntries = 0)const override{
		return this->baseFile->list_dir(maxEntries);
	}

	size_t read_internal(utki::span<uint8_t> buf)const override{
		return this->baseFile->read(buf);
	}

	size_t write_internal(utki::span<const uint8_t> buf)override{
		return this->baseFile->write(buf);
	}

	size_t seek_forward_internal(size_t numBytesToSeek)const override{
		return this->baseFile->seek_forward(numBytesToSeek);
	}

	size_t seek_backward_internal(size_t numBytesToSeek)const override{
		return this->baseFile->seek_backward(numBytesToSeek);
	}

	void rewind_internal()const override{
		this->baseFile->rewind();
	}

	void make_dir()override{
		this->baseFile->make_dir();
	}

	bool exists()const override{
		return this->baseFile->exists();
	}

	std::unique_ptr<file> spawn()override{
		return utki::make_unique<root_dir>(this->baseFile->spawn(), this->rootDir);
	}
};

}
<commit_msg>renamings root_dir<commit_after>#pragma once

#include <utki/config.hpp>

#include "file.hpp"

namespace papki{

//TODO: doxygen
class root_dir : public file{
	std::unique_ptr<file> base_file;
	std::string root_directory;

public:
	/**
	 * @param base_file - a file to wrap.
	 * @param root_directory - path to the root directory to set. It should have trailing '/' character.
	 */
	root_dir(std::unique_ptr<file> base_file, const std::string& root_directory) :
			base_file(std::move(base_file)),
			root_directory(root_directory)
	{
		if(!this->base_file){
			throw std::invalid_argument("root_dir(): passed in base file pointer is null");
		}
		this->file::set_path_internal(std::string(this->base_file->path()));
		this->base_file->set_path(this->root_directory + this->path());
	}

	static std::unique_ptr<const root_dir> make(std::unique_ptr<const file> base_file, const std::string& root_directory){
		return utki::make_unique<const root_dir>(std::unique_ptr<file>(const_cast<file*>(base_file.release())), root_directory);
	}

	root_dir(const root_dir&) = delete;
	root_dir& operator=(const root_dir&) = delete;

private:
	void set_path_internal(std::string&& pathName)const override{
		this->file::set_path_internal(std::move(pathName));
		this->base_file->set_path(this->root_directory + this->path());
	}

	void open_internal(mode io_mode)override{
		this->base_file->open(io_mode);
	}

	void close_internal()const noexcept override{
		this->base_file->close();
	}

	std::vector<std::string> list_dir(size_t maxEntries = 0)const override{
		return this->base_file->list_dir(maxEntries);
	}

	size_t read_internal(utki::span<uint8_t> buf)const override{
		return this->base_file->read(buf);
	}

	size_t write_internal(utki::span<const uint8_t> buf)override{
		return this->base_file->write(buf);
	}

	size_t seek_forward_internal(size_t numBytesToSeek)const override{
		return this->base_file->seek_forward(numBytesToSeek);
	}

	size_t seek_backward_internal(size_t numBytesToSeek)const override{
		return this->base_file->seek_backward(numBytesToSeek);
	}

	void rewind_internal()const override{
		this->base_file->rewind();
	}

	void make_dir()override{
		this->base_file->make_dir();
	}

	bool exists()const override{
		return this->base_file->exists();
	}

	std::unique_ptr<file> spawn()override{
		return utki::make_unique<root_dir>(this->base_file->spawn(), this->root_directory);
	}
};

}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: DStatement.cxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: oj $ $Date: 2001-05-14 11:37:37 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  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.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _CONNECTIVITY_DBASE_DSTATEMENT_HXX_
#include "dbase/DStatement.hxx"
#endif
#ifndef _CONNECTIVITY_DBASE_DRESULTSET_HXX_
#include "dbase/DResultSet.hxx"
#endif

using namespace connectivity::dbase;
using namespace connectivity::file;
using namespace com::sun::star::uno;

// -------------------------------------------------------------------------
OResultSet* ODbaseStatement::createResultSet()
{
    return new ODbaseResultSet(this,m_aSQLIterator);
}
// -------------------------------------------------------------------------
IMPLEMENT_SERVICE_INFO(ODbaseStatement,"com.sun.star.sdbc.driver.dbase.Statement","com.sun.star.sdbc.Statement");

<commit_msg>INTEGRATION: CWS ooo19126 (1.2.352); FILE MERGED 2005/09/05 17:23:28 rt 1.2.352.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: DStatement.cxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 05:40:00 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    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.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _CONNECTIVITY_DBASE_DSTATEMENT_HXX_
#include "dbase/DStatement.hxx"
#endif
#ifndef _CONNECTIVITY_DBASE_DRESULTSET_HXX_
#include "dbase/DResultSet.hxx"
#endif

using namespace connectivity::dbase;
using namespace connectivity::file;
using namespace com::sun::star::uno;

// -------------------------------------------------------------------------
OResultSet* ODbaseStatement::createResultSet()
{
    return new ODbaseResultSet(this,m_aSQLIterator);
}
// -------------------------------------------------------------------------
IMPLEMENT_SERVICE_INFO(ODbaseStatement,"com.sun.star.sdbc.driver.dbase.Statement","com.sun.star.sdbc.Statement");

<|endoftext|>


<commit_before>//
// Copyright (C) 2013-2018 University of Amsterdam
//
// 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.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//

#include "engine.h"

#include <sstream>
#include <cstdio>

#include "../JASP-Common/analysisloader.h"
#include "../JASP-Common/tempfiles.h"
#include "../JASP-Common/utils.h"
#include "../JASP-Common/sharedmemory.h"

#include "rbridge.h"

#ifdef __WIN32__

#undef Realloc
#undef Free

#endif

using namespace std;
using namespace boost::interprocess;
using namespace boost::posix_time;

Engine::Engine()
{

	tempfiles_attach(ProcessInfo::parentPID());

	rbridge_setDataSetSource(boost::bind(&Engine::provideDataSet, this));
	rbridge_setFileNameSource(boost::bind(&Engine::provideTempFileName, this, _1, _2, _3));
	rbridge_setStateFileSource(boost::bind(&Engine::provideStateFileName, this, _1, _2));

	rbridge_init();
}

void Engine::setSlaveNo(int no)
{
	_slaveNo = no;
}

void Engine::saveImage()
{
	if (_status != saveImg)
		return;

	vector<string> tempFilesFromLastTime = tempfiles_retrieveList(_analysisId);

	std::string name = _imageOptions.get("name", Json::nullValue).asString();
	std::string type = _imageOptions.get("type", Json::nullValue).asString();

	int height = _imageOptions.get("height", Json::nullValue).asInt();
	int width = _imageOptions.get("width", Json::nullValue).asInt();
	std::string result = rbridge_saveImage(name, type, height, width, _ppi);

	_status = complete;
	Json::Reader parser;
	parser.parse(result, _analysisResults, false);
	_analysisResults["results"]["inputOptions"] = _imageOptions;
	_progress = -1;
	sendResults();
	_status = empty;

}

void Engine::editImage()
{
    if (_status != editImg)
        return;

    vector<string> tempFilesFromLastTime = tempfiles_retrieveList(_analysisId);

    RCallback callback = boost::bind(&Engine::callback, this, _1, _2);

    std::string name = _imageOptions.get("name", Json::nullValue).asString();
		std::string type = _imageOptions.get("type", Json::nullValue).asString();
    int height = _imageOptions.get("height", Json::nullValue).asInt();
    int width = _imageOptions.get("width", Json::nullValue).asInt();
    std::string result = rbridge_editImage(name, type, height, width, _ppi);

    _status = complete;
    Json::Reader parser;
    parser.parse(result, _analysisResults, false);
    _progress = -1;
    sendResults();
    _status = empty;

    //tempfiles_deleteList(tempFilesFromLastTime);

}

void Engine::runAnalysis()
{
	if (_status == empty || _status == aborted)
		return;

	string perform;

	if (_status == toInit)
	{
		perform = "init";
		_status = initing;
	}
	else
	{
		perform = "run";
		_status = running;
	}

	vector<string> tempFilesFromLastTime = tempfiles_retrieveList(_analysisId);

	RCallback callback = boost::bind(&Engine::callback, this, _1, _2);

	_currentAnalysisKnowsAboutChange = false;
	_analysisResultsString = rbridge_run(_analysisName, _analysisTitle, _analysisRequiresInit, _analysisDataKey, _analysisOptions, _analysisResultsMeta, _analysisStateKey, perform, _ppi, callback);

	if (_status == initing || _status == running)  // if status hasn't changed
		receiveMessages();

	if (_status == toInit || _status == aborted || _status == error || _status == exception)
	{
		// analysis was aborted, and we shouldn't send the results
	}
	else if (_status == changed && (_currentAnalysisKnowsAboutChange == false || _analysisResultsString == "null"))
	{
		// analysis was changed, and the analysis either did not know about
		// the change (because it did not call a callback),
		// or it could not incorporate the changes (returned null).
		// in both cases it needs to be re-run, and results should
		// not be sent

		_status = toInit;
		if (_analysisResultsString == "null")
			tempfiles_deleteList(tempFilesFromLastTime);

	}
	else
	{
		Json::Reader parser;
		parser.parse(_analysisResultsString, _analysisResults, false);

		_status = _status == initing ? inited : complete;
		_progress = -1;
		sendResults();
		_status = empty;

		vector<string> filesToKeep;

		if (_analysisResults.isObject())
		{
			Json::Value filesToKeepValue = _analysisResults.get("keep", Json::nullValue);

			if (filesToKeepValue.isArray())
			{
				for (size_t i = 0; i < filesToKeepValue.size(); i++)
				{
					Json::Value fileToKeepValue = filesToKeepValue.get(i, Json::nullValue);
					if ( ! fileToKeepValue.isString())
						continue;

					filesToKeep.push_back(fileToKeepValue.asString());
				}
			}
			else if (filesToKeepValue.isString())
			{
				filesToKeep.push_back(filesToKeepValue.asString());
			}
		}

		Utils::remove(tempFilesFromLastTime, filesToKeep);

		tempfiles_deleteList(tempFilesFromLastTime);
	}
}

void Engine::run()
{
#if defined(QT_DEBUG) || defined(__linux__)
	if (_slaveNo == 0)
	{
		string engineInfo = rbridge_check();

		Json::Value v;
		Json::Reader r;
		r.parse(engineInfo, v);

		std::cout << v.toStyledString() << "\n";
		std::cout.flush();
	}
#endif

	stringstream ss;
	ss << "JASP-IPC-" << ProcessInfo::parentPID();
	string memoryName = ss.str();

	_channel = new IPCChannel(memoryName, _slaveNo, true);

	while (ProcessInfo::isParentRunning())
	{
		receiveMessages(100);
		if (_status == saveImg)
			saveImage();
        else if (_status == editImg)
            editImage();
		else
			runAnalysis();

		if(filterChanged)
			applyFilter();
	}

	shared_memory_object::remove(memoryName.c_str());
}

bool Engine::receiveMessages(int timeout)
{
	string data;

	if (_channel->receive(data, timeout))
	{
#ifdef JASP_DEBUG
		std::cout << "received message" << std::endl;
		std::cout << data << std::endl;
		std::cout.flush();
#endif
		Json::Value jsonRequest;
		Json::Reader r;
		r.parse(data, jsonRequest, false);

		if(jsonRequest.get("filter", "").asString() != "")
		{
			filterChanged = true;
			filter = jsonRequest.get("filter", "").asString();
			generatedFilter = jsonRequest.get("generatedFilter", "").asString();

			return false; //This is not an analysis-run-request or anything like that, so quit like a not-message.
		}

		int analysisId = jsonRequest.get("id", -1).asInt();
		string perform = jsonRequest.get("perform", "run").asString();

		if (analysisId == _analysisId && _status == running)
		{
			// if the current running analysis has changed

			if (perform == "init")
				_status = changed;
			else if (perform == "stop")
				_status = stopped;
			else
				_status = aborted;
		}
		else
		{
			// the new analysis should be init or run (existing analyses will be aborted)

			_analysisId = analysisId;

			if (perform == "init")
				_status = toInit;
			else if (perform == "run")
				_status = toRun;
			else if (perform == "saveImg")
				_status = saveImg;
            else if (perform == "editImg")
                _status = editImg;
			else
				_status = error;
		}

		if (_status == toInit || _status == toRun || _status == changed || _status == saveImg || _status == editImg)
		{
			_analysisName			= jsonRequest.get("name",			Json::nullValue).asString();
			_analysisTitle			= jsonRequest.get("title",			Json::nullValue).asString();
			_analysisDataKey		= jsonRequest.get("dataKey",		Json::nullValue).toStyledString();
			_analysisOptions		= jsonRequest.get("options",		Json::nullValue).toStyledString();
			_analysisResultsMeta	= jsonRequest.get("resultsMeta",	Json::nullValue).toStyledString();
			_analysisStateKey		= jsonRequest.get("stateKey",		Json::nullValue).toStyledString();
			_analysisRevision		= jsonRequest.get("revision",		-1).asInt();
			_imageOptions			= jsonRequest.get("image",			Json::nullValue);

			Json::Value analysisRequiresInit = jsonRequest.get("requiresInit", Json::nullValue);
			_analysisRequiresInit = analysisRequiresInit.isNull() ? true : analysisRequiresInit.asBool();

			Json::Value ppi, settings = jsonRequest.get("settings", Json::nullValue);
			if (settings.isObject() && (ppi = settings.get("ppi", Json::nullValue)).isInt())
				_ppi = ppi.asInt();
			else
				_ppi = 96;
		}

		return true;
	}

	return false;
}

void Engine::sendResults()
{
	Json::Value response = Json::Value(Json::objectValue);

	response["id"] = _analysisId;
	response["name"] = _analysisName;
	response["revision"] = _analysisRevision;
	response["progress"] = _progress;

	Json::Value resultsStatus = Json::nullValue;

	if (_analysisResults.isObject())
		resultsStatus = _analysisResults.get("status", Json::nullValue);

	if (resultsStatus != Json::nullValue)
	{
		response["results"] = _analysisResults.get("results", Json::nullValue);
		response["status"]  = resultsStatus.asString();
	}
	else
	{
		string status;

		switch (_status)
		{
		case inited:
			status = "inited";
			break;
		case running:
		case changed:
			status = "running";
			break;
		case complete:
			status = "complete";
			break;
		case stopped:
			status = "stopped";
			break;
		default:
			status = "error";
			break;
		}

		response["results"] = _analysisResults;
		response["status"] = status;
	}

	string message = response.toStyledString();

	_channel->send(message);
}

void Engine::sendFilterResult(std::vector<bool> filterResult)
{
	Json::Value filterResponse = Json::Value(Json::objectValue);

	Json::Value filterResultList = Json::Value(Json::arrayValue);
	for(bool f : filterResult)
		filterResultList.append(f);
	filterResponse["filterResult"] = filterResultList;

	std::string msg = filterResponse.toStyledString();
	_channel->send(msg);
}

void Engine::sendFilterError(std::string errorMessage)
{
	std::cout << "Gonna send sendFilterError "<< errorMessage <<"\n"<< std::flush;

	Json::Value filterResponse = Json::Value(Json::objectValue);

	filterResponse["filterError"] = errorMessage;

	std::string msg = filterResponse.toStyledString();
	_channel->send(msg);
}

string Engine::callback(const string &results, int progress)
{
	receiveMessages();

	if (_status == aborted || _status == toInit || _status == toRun)
		return "{ \"status\" : \"aborted\" }"; // abort

	if (_status == changed && _currentAnalysisKnowsAboutChange)
	{
		_status = running;
		_currentAnalysisKnowsAboutChange = false;
	}

	if (results != "null")
	{
		_analysisResultsString = results;

		Json::Reader parser;
		parser.parse(_analysisResultsString, _analysisResults, false);

		_progress = progress;

		sendResults();
	}
	else if (progress >= 0 && _status == running)
	{
		_analysisResultsString = Json::nullValue;
		_analysisResults = "";
		_progress = progress;

		sendResults();

	}

	if (_status == changed)
	{
		_currentAnalysisKnowsAboutChange = true; // because we're telling it now
		return "{ \"status\" : \"changed\", \"options\" : " + _analysisOptions + " }";
	}
	else if (_status == stopped)
	{
		return "{ \"status\" : \"stopped\" }";
	}
	else if (_status == aborted)
	{
		return "{ \"status\" : \"aborted\" }";
	}

	return "{ \"status\" : \"ok\" }";
}

DataSet * Engine::provideDataSet()
{
	return SharedMemory::retrieveDataSet();
}

void Engine::provideStateFileName(string &root, string &relativePath)
{
	return tempfiles_createSpecific("state", _analysisId, root, relativePath);
}

void Engine::provideTempFileName(const string &extension, string &root, string &relativePath)
{
	tempfiles_create(extension, _analysisId, root, relativePath);
}

void Engine::applyFilter()
{
	filterChanged = false;

	try
	{
		std::vector<bool> filterResult = rbridge_applyFilter(filter, generatedFilter);

		sendFilterResult(filterResult);

		std::string RConsoleOutput(jaspRCPP_getRConsoleOutput());

		if(RConsoleOutput.length() > 0)
			sendFilterError(RConsoleOutput);
	}
	catch(filterException & e)
	{
		std::cout << "filtererror caught: " << e.what() << std::endl << std::flush;
		if(std::string(e.what()).length() > 0)
			sendFilterError(e.what());
		else
			sendFilterError("Something went wrong with the filter but it is unclear what.");
	}
}

// Evaluating arbitrary R code (as string) which returns a string
void Engine::evalRCode(const string &rCode)
{
	std::string rCodeResult = rbridge_evalRCode(rCode);

	if (rCodeResult == "null")
	{
		// this means an error was generated;
		std::cout << "R Code yielded error" << std::endl << std::flush;
		sendRCodeError();
	}
	else
	{
		std::cout << "R Code yielded result: " << rCodeResult << std::endl << std::flush;
		sendRCodeResult(rCodeResult);
	}
}

void Engine::sendRCodeResult(std::string rCodeResult)
{
	Json::Value rCodeResponse = Json::Value(Json::objectValue);

	rCodeResponse["rCodeResult"] = rCodeResult;

	std::string msg = rCodeResponse.toStyledString();
	_channel->send(msg);
}

void Engine::sendRCodeError()
{
	Json::Value rCodeResponse = Json::Value(Json::objectValue);

	rCodeResponse["rCodeError"] = "R Code failed for unknown reason. Check that R function returns a string.";

	std::string msg = rCodeResponse.toStyledString();
	_channel->send(msg);
}
<commit_msg>Take out debug prints<commit_after>//
// Copyright (C) 2013-2018 University of Amsterdam
//
// 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.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//

#include "engine.h"

#include <sstream>
#include <cstdio>

#include "../JASP-Common/analysisloader.h"
#include "../JASP-Common/tempfiles.h"
#include "../JASP-Common/utils.h"
#include "../JASP-Common/sharedmemory.h"

#include "rbridge.h"

#ifdef __WIN32__

#undef Realloc
#undef Free

#endif

using namespace std;
using namespace boost::interprocess;
using namespace boost::posix_time;

Engine::Engine()
{

	tempfiles_attach(ProcessInfo::parentPID());

	rbridge_setDataSetSource(boost::bind(&Engine::provideDataSet, this));
	rbridge_setFileNameSource(boost::bind(&Engine::provideTempFileName, this, _1, _2, _3));
	rbridge_setStateFileSource(boost::bind(&Engine::provideStateFileName, this, _1, _2));

	rbridge_init();
}

void Engine::setSlaveNo(int no)
{
	_slaveNo = no;
}

void Engine::saveImage()
{
	if (_status != saveImg)
		return;

	vector<string> tempFilesFromLastTime = tempfiles_retrieveList(_analysisId);

	std::string name = _imageOptions.get("name", Json::nullValue).asString();
	std::string type = _imageOptions.get("type", Json::nullValue).asString();

	int height = _imageOptions.get("height", Json::nullValue).asInt();
	int width = _imageOptions.get("width", Json::nullValue).asInt();
	std::string result = rbridge_saveImage(name, type, height, width, _ppi);

	_status = complete;
	Json::Reader parser;
	parser.parse(result, _analysisResults, false);
	_analysisResults["results"]["inputOptions"] = _imageOptions;
	_progress = -1;
	sendResults();
	_status = empty;

}

void Engine::editImage()
{
    if (_status != editImg)
        return;

    vector<string> tempFilesFromLastTime = tempfiles_retrieveList(_analysisId);

    RCallback callback = boost::bind(&Engine::callback, this, _1, _2);

    std::string name = _imageOptions.get("name", Json::nullValue).asString();
		std::string type = _imageOptions.get("type", Json::nullValue).asString();
    int height = _imageOptions.get("height", Json::nullValue).asInt();
    int width = _imageOptions.get("width", Json::nullValue).asInt();
    std::string result = rbridge_editImage(name, type, height, width, _ppi);

    _status = complete;
    Json::Reader parser;
    parser.parse(result, _analysisResults, false);
    _progress = -1;
    sendResults();
    _status = empty;

    //tempfiles_deleteList(tempFilesFromLastTime);

}

void Engine::runAnalysis()
{
	if (_status == empty || _status == aborted)
		return;

	string perform;

	if (_status == toInit)
	{
		perform = "init";
		_status = initing;
	}
	else
	{
		perform = "run";
		_status = running;
	}

	vector<string> tempFilesFromLastTime = tempfiles_retrieveList(_analysisId);

	RCallback callback = boost::bind(&Engine::callback, this, _1, _2);

	_currentAnalysisKnowsAboutChange = false;
	_analysisResultsString = rbridge_run(_analysisName, _analysisTitle, _analysisRequiresInit, _analysisDataKey, _analysisOptions, _analysisResultsMeta, _analysisStateKey, perform, _ppi, callback);

	if (_status == initing || _status == running)  // if status hasn't changed
		receiveMessages();

	if (_status == toInit || _status == aborted || _status == error || _status == exception)
	{
		// analysis was aborted, and we shouldn't send the results
	}
	else if (_status == changed && (_currentAnalysisKnowsAboutChange == false || _analysisResultsString == "null"))
	{
		// analysis was changed, and the analysis either did not know about
		// the change (because it did not call a callback),
		// or it could not incorporate the changes (returned null).
		// in both cases it needs to be re-run, and results should
		// not be sent

		_status = toInit;
		if (_analysisResultsString == "null")
			tempfiles_deleteList(tempFilesFromLastTime);

	}
	else
	{
		Json::Reader parser;
		parser.parse(_analysisResultsString, _analysisResults, false);

		_status = _status == initing ? inited : complete;
		_progress = -1;
		sendResults();
		_status = empty;

		vector<string> filesToKeep;

		if (_analysisResults.isObject())
		{
			Json::Value filesToKeepValue = _analysisResults.get("keep", Json::nullValue);

			if (filesToKeepValue.isArray())
			{
				for (size_t i = 0; i < filesToKeepValue.size(); i++)
				{
					Json::Value fileToKeepValue = filesToKeepValue.get(i, Json::nullValue);
					if ( ! fileToKeepValue.isString())
						continue;

					filesToKeep.push_back(fileToKeepValue.asString());
				}
			}
			else if (filesToKeepValue.isString())
			{
				filesToKeep.push_back(filesToKeepValue.asString());
			}
		}

		Utils::remove(tempFilesFromLastTime, filesToKeep);

		tempfiles_deleteList(tempFilesFromLastTime);
	}
}

void Engine::run()
{
#if defined(QT_DEBUG) || defined(__linux__)
	if (_slaveNo == 0)
	{
		string engineInfo = rbridge_check();

		Json::Value v;
		Json::Reader r;
		r.parse(engineInfo, v);

		std::cout << v.toStyledString() << "\n";
		std::cout.flush();
	}
#endif

	stringstream ss;
	ss << "JASP-IPC-" << ProcessInfo::parentPID();
	string memoryName = ss.str();

	_channel = new IPCChannel(memoryName, _slaveNo, true);

	while (ProcessInfo::isParentRunning())
	{
		receiveMessages(100);
		if (_status == saveImg)
			saveImage();
        else if (_status == editImg)
            editImage();
		else
			runAnalysis();

		if(filterChanged)
			applyFilter();
	}

	shared_memory_object::remove(memoryName.c_str());
}

bool Engine::receiveMessages(int timeout)
{
	string data;

	if (_channel->receive(data, timeout))
	{
#ifdef JASP_DEBUG
		std::cout << "received message" << std::endl;
		std::cout << data << std::endl;
		std::cout.flush();
#endif
		Json::Value jsonRequest;
		Json::Reader r;
		r.parse(data, jsonRequest, false);

		if(jsonRequest.get("filter", "").asString() != "")
		{
			filterChanged = true;
			filter = jsonRequest.get("filter", "").asString();
			generatedFilter = jsonRequest.get("generatedFilter", "").asString();

			return false; //This is not an analysis-run-request or anything like that, so quit like a not-message.
		}

		int analysisId = jsonRequest.get("id", -1).asInt();
		string perform = jsonRequest.get("perform", "run").asString();

		if (analysisId == _analysisId && _status == running)
		{
			// if the current running analysis has changed

			if (perform == "init")
				_status = changed;
			else if (perform == "stop")
				_status = stopped;
			else
				_status = aborted;
		}
		else
		{
			// the new analysis should be init or run (existing analyses will be aborted)

			_analysisId = analysisId;

			if (perform == "init")
				_status = toInit;
			else if (perform == "run")
				_status = toRun;
			else if (perform == "saveImg")
				_status = saveImg;
            else if (perform == "editImg")
                _status = editImg;
			else
				_status = error;
		}

		if (_status == toInit || _status == toRun || _status == changed || _status == saveImg || _status == editImg)
		{
			_analysisName			= jsonRequest.get("name",			Json::nullValue).asString();
			_analysisTitle			= jsonRequest.get("title",			Json::nullValue).asString();
			_analysisDataKey		= jsonRequest.get("dataKey",		Json::nullValue).toStyledString();
			_analysisOptions		= jsonRequest.get("options",		Json::nullValue).toStyledString();
			_analysisResultsMeta	= jsonRequest.get("resultsMeta",	Json::nullValue).toStyledString();
			_analysisStateKey		= jsonRequest.get("stateKey",		Json::nullValue).toStyledString();
			_analysisRevision		= jsonRequest.get("revision",		-1).asInt();
			_imageOptions			= jsonRequest.get("image",			Json::nullValue);

			Json::Value analysisRequiresInit = jsonRequest.get("requiresInit", Json::nullValue);
			_analysisRequiresInit = analysisRequiresInit.isNull() ? true : analysisRequiresInit.asBool();

			Json::Value ppi, settings = jsonRequest.get("settings", Json::nullValue);
			if (settings.isObject() && (ppi = settings.get("ppi", Json::nullValue)).isInt())
				_ppi = ppi.asInt();
			else
				_ppi = 96;
		}

		return true;
	}

	return false;
}

void Engine::sendResults()
{
	Json::Value response = Json::Value(Json::objectValue);

	response["id"] = _analysisId;
	response["name"] = _analysisName;
	response["revision"] = _analysisRevision;
	response["progress"] = _progress;

	Json::Value resultsStatus = Json::nullValue;

	if (_analysisResults.isObject())
		resultsStatus = _analysisResults.get("status", Json::nullValue);

	if (resultsStatus != Json::nullValue)
	{
		response["results"] = _analysisResults.get("results", Json::nullValue);
		response["status"]  = resultsStatus.asString();
	}
	else
	{
		string status;

		switch (_status)
		{
		case inited:
			status = "inited";
			break;
		case running:
		case changed:
			status = "running";
			break;
		case complete:
			status = "complete";
			break;
		case stopped:
			status = "stopped";
			break;
		default:
			status = "error";
			break;
		}

		response["results"] = _analysisResults;
		response["status"] = status;
	}

	string message = response.toStyledString();

	_channel->send(message);
}

void Engine::sendFilterResult(std::vector<bool> filterResult)
{
	Json::Value filterResponse = Json::Value(Json::objectValue);

	Json::Value filterResultList = Json::Value(Json::arrayValue);
	for(bool f : filterResult)
		filterResultList.append(f);
	filterResponse["filterResult"] = filterResultList;

	std::string msg = filterResponse.toStyledString();
	_channel->send(msg);
}

void Engine::sendFilterError(std::string errorMessage)
{
	Json::Value filterResponse = Json::Value(Json::objectValue);

	filterResponse["filterError"] = errorMessage;

	std::string msg = filterResponse.toStyledString();
	_channel->send(msg);
}

string Engine::callback(const string &results, int progress)
{
	receiveMessages();

	if (_status == aborted || _status == toInit || _status == toRun)
		return "{ \"status\" : \"aborted\" }"; // abort

	if (_status == changed && _currentAnalysisKnowsAboutChange)
	{
		_status = running;
		_currentAnalysisKnowsAboutChange = false;
	}

	if (results != "null")
	{
		_analysisResultsString = results;

		Json::Reader parser;
		parser.parse(_analysisResultsString, _analysisResults, false);

		_progress = progress;

		sendResults();
	}
	else if (progress >= 0 && _status == running)
	{
		_analysisResultsString = Json::nullValue;
		_analysisResults = "";
		_progress = progress;

		sendResults();

	}

	if (_status == changed)
	{
		_currentAnalysisKnowsAboutChange = true; // because we're telling it now
		return "{ \"status\" : \"changed\", \"options\" : " + _analysisOptions + " }";
	}
	else if (_status == stopped)
	{
		return "{ \"status\" : \"stopped\" }";
	}
	else if (_status == aborted)
	{
		return "{ \"status\" : \"aborted\" }";
	}

	return "{ \"status\" : \"ok\" }";
}

DataSet * Engine::provideDataSet()
{
	return SharedMemory::retrieveDataSet();
}

void Engine::provideStateFileName(string &root, string &relativePath)
{
	return tempfiles_createSpecific("state", _analysisId, root, relativePath);
}

void Engine::provideTempFileName(const string &extension, string &root, string &relativePath)
{
	tempfiles_create(extension, _analysisId, root, relativePath);
}

void Engine::applyFilter()
{
	filterChanged = false;

	try
	{
		std::vector<bool> filterResult = rbridge_applyFilter(filter, generatedFilter);

		sendFilterResult(filterResult);

		std::string RConsoleOutput(jaspRCPP_getRConsoleOutput());

		if(RConsoleOutput.length() > 0)
			sendFilterError(RConsoleOutput);
	}
	catch(filterException & e)
	{
		if(std::string(e.what()).length() > 0)
			sendFilterError(e.what());
		else
			sendFilterError("Something went wrong with the filter but it is unclear what.");
	}
}

// Evaluating arbitrary R code (as string) which returns a string
void Engine::evalRCode(const string &rCode)
{
	std::string rCodeResult = rbridge_evalRCode(rCode);

	if (rCodeResult == "null")
	{
		// this means an error was generated;
		std::cout << "R Code yielded error" << std::endl << std::flush;
		sendRCodeError();
	}
	else
	{
		std::cout << "R Code yielded result: " << rCodeResult << std::endl << std::flush;
		sendRCodeResult(rCodeResult);
	}
}

void Engine::sendRCodeResult(std::string rCodeResult)
{
	Json::Value rCodeResponse = Json::Value(Json::objectValue);

	rCodeResponse["rCodeResult"] = rCodeResult;

	std::string msg = rCodeResponse.toStyledString();
	_channel->send(msg);
}

void Engine::sendRCodeError()
{
	Json::Value rCodeResponse = Json::Value(Json::objectValue);

	rCodeResponse["rCodeError"] = "R Code failed for unknown reason. Check that R function returns a string.";

	std::string msg = rCodeResponse.toStyledString();
	_channel->send(msg);
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2011 Josh A. Beam
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *   1. Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *   2. Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <cstring>
#include <xviweb/String.h>
#include "HttpResponseImpl.h"

using namespace std;

HttpResponseImpl::HttpResponseImpl(HttpConnection *conn)
{
	m_conn = conn;
	m_responding = false;

	// set some default values
	setStatus(200, "OK");
	setHeaderValue("Server", "xviweb");
	setContentType("text/html");
}

int
HttpResponseImpl::getStatusCode() const
{
	return m_statusCode;
}

string
HttpResponseImpl::getStatusMessage() const
{
	return m_statusMessage;
}

void
HttpResponseImpl::setStatus(int statusCode, const string &statusMessage)
{
	m_statusCode = statusCode;
	m_statusMessage = statusMessage;
}

string
HttpResponseImpl::getContentType() const
{
	return getHeaderValue("Content-Type");
}

void
HttpResponseImpl::setContentType(const string &contentType)
{
	setHeaderValue("Content-Type", contentType);
}

int
HttpResponseImpl::getContentLength() const
{
	return String::toInt(getHeaderValue("Content-Length"));
}

void
HttpResponseImpl::setContentLength(int contentLength)
{
	setHeaderValue("Content-Length", String::fromInt(contentLength));
}

string
HttpResponseImpl::getHeaderValue(const string &headerName) const
{
	HttpResponseMap::const_iterator iter = m_headerMap.find(headerName);
	return (iter != m_headerMap.end()) ? iter->second : string("");
}

void
HttpResponseImpl::setHeaderValue(const string &headerName,
                                 const string &headerValue)
{
	// see if there's already a value for
	// this header; if so, remove it
	HttpResponseMap::iterator iter = m_headerMap.find(headerName);
	if(iter != m_headerMap.end())
		m_headerMap.erase(iter);

	// insert the new header value
	m_headerMap.insert(make_pair(headerName, headerValue));
}

void
HttpResponseImpl::beginResponse()
{
	m_responding = true;
	m_conn->beginResponse();

	// send status code/message
	string status = "HTTP/1.1 " + String::fromInt(m_statusCode) + " " + m_statusMessage + "\r\n";
	sendString(status);

	// send headers
	HttpResponseMap::iterator iter = m_headerMap.begin();
	while(iter != m_headerMap.end()) {
		string header = iter->first + ": " + iter->second + "\r\n";
		sendString(header);
		++iter;
	}

	// send empty line between headers and response body
	sendString("\r\n");
}

void
HttpResponseImpl::sendString(const char *s, size_t length)
{
	if(m_responding == false)
		beginResponse();

	m_conn->sendString(s, length);
}

void
HttpResponseImpl::sendString(const char *s)
{
	sendString(s, strlen(s));
}

void
HttpResponseImpl::sendString(const string &s)
{
	sendString(s.c_str(), s.length());
}

void
HttpResponseImpl::sendLine(const char *line)
{
	sendLine(string(line));
}

void
HttpResponseImpl::sendLine(const string &line)
{
	sendString(line + "\r\n");
}

void
HttpResponseImpl::sendResponse(int statusCode, const char *statusMessage,
                               const char *contentType, const char *content)
{
	m_conn->beginResponse();

	// set the status, content type, and content length
	setStatus(statusCode, statusMessage);
	setContentType(contentType);
	setContentLength(strlen(content));

	// send content
	sendString(content);
	m_conn->endResponse();
}

void
HttpResponseImpl::sendErrorResponse(int errorCode, const char *errorDesc,
                                    const char *errorMessage)
{
	string code = String::fromInt(errorCode);

	string response = string() +
		"<!DOCTYPE html>\r\n"
		"\r\n"
		"\r\n"
		"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\r\n"
		"<title>" + code + " " + errorDesc + "</title>\r\n"
		"\r\n"
		"\r\n"
		"\r\n\r\n"
		"
" + errorDesc + "
\r\n"
		"
" + errorMessage + "
\r\n\r\n"
		"\r\n"
		"\r\n";

	sendResponse(errorCode, errorDesc, "text/html", response.c_str());
}

void
HttpResponseImpl::endResponse()
{
	if(m_responding == false)
		beginResponse();

	m_conn->endResponse();
}
<commit_msg>Made the HtmlResponseImpl::sendErrorResponse function do HTML-encoding of error messages.<commit_after>/*
 * Copyright (C) 2011 Josh A. Beam
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *   1. Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *   2. Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <cstring>
#include <xviweb/String.h>
#include "HttpResponseImpl.h"

using namespace std;

HttpResponseImpl::HttpResponseImpl(HttpConnection *conn)
{
	m_conn = conn;
	m_responding = false;

	// set some default values
	setStatus(200, "OK");
	setHeaderValue("Server", "xviweb");
	setContentType("text/html");
}

int
HttpResponseImpl::getStatusCode() const
{
	return m_statusCode;
}

string
HttpResponseImpl::getStatusMessage() const
{
	return m_statusMessage;
}

void
HttpResponseImpl::setStatus(int statusCode, const string &statusMessage)
{
	m_statusCode = statusCode;
	m_statusMessage = statusMessage;
}

string
HttpResponseImpl::getContentType() const
{
	return getHeaderValue("Content-Type");
}

void
HttpResponseImpl::setContentType(const string &contentType)
{
	setHeaderValue("Content-Type", contentType);
}

int
HttpResponseImpl::getContentLength() const
{
	return String::toInt(getHeaderValue("Content-Length"));
}

void
HttpResponseImpl::setContentLength(int contentLength)
{
	setHeaderValue("Content-Length", String::fromInt(contentLength));
}

string
HttpResponseImpl::getHeaderValue(const string &headerName) const
{
	HttpResponseMap::const_iterator iter = m_headerMap.find(headerName);
	return (iter != m_headerMap.end()) ? iter->second : string("");
}

void
HttpResponseImpl::setHeaderValue(const string &headerName,
                                 const string &headerValue)
{
	// see if there's already a value for
	// this header; if so, remove it
	HttpResponseMap::iterator iter = m_headerMap.find(headerName);
	if(iter != m_headerMap.end())
		m_headerMap.erase(iter);

	// insert the new header value
	m_headerMap.insert(make_pair(headerName, headerValue));
}

void
HttpResponseImpl::beginResponse()
{
	m_responding = true;
	m_conn->beginResponse();

	// send status code/message
	string status = "HTTP/1.1 " + String::fromInt(m_statusCode) + " " + m_statusMessage + "\r\n";
	sendString(status);

	// send headers
	HttpResponseMap::iterator iter = m_headerMap.begin();
	while(iter != m_headerMap.end()) {
		string header = iter->first + ": " + iter->second + "\r\n";
		sendString(header);
		++iter;
	}

	// send empty line between headers and response body
	sendString("\r\n");
}

void
HttpResponseImpl::sendString(const char *s, size_t length)
{
	if(m_responding == false)
		beginResponse();

	m_conn->sendString(s, length);
}

void
HttpResponseImpl::sendString(const char *s)
{
	sendString(s, strlen(s));
}

void
HttpResponseImpl::sendString(const string &s)
{
	sendString(s.c_str(), s.length());
}

void
HttpResponseImpl::sendLine(const char *line)
{
	sendLine(string(line));
}

void
HttpResponseImpl::sendLine(const string &line)
{
	sendString(line + "\r\n");
}

void
HttpResponseImpl::sendResponse(int statusCode, const char *statusMessage,
                               const char *contentType, const char *content)
{
	m_conn->beginResponse();

	// set the status, content type, and content length
	setStatus(statusCode, statusMessage);
	setContentType(contentType);
	setContentLength(strlen(content));

	// send content
	sendString(content);
	m_conn->endResponse();
}

void
HttpResponseImpl::sendErrorResponse(int errorCode, const char *errorDesc,
                                    const char *errorMessage)
{
	string code = String::fromInt(errorCode);
	string htmlErrorDesc = String::htmlEncode(errorDesc);
	string htmlErrorMessage = String::htmlEncode(errorMessage);

	string response = string() +
		"<!DOCTYPE html>\r\n"
		"\r\n"
		"\r\n"
		"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\r\n"
		"<title>" + code + " " + htmlErrorDesc + "</title>\r\n"
		"\r\n"
		"\r\n"
		"\r\n\r\n"
		"
" + htmlErrorDesc + "
\r\n"
		"
" + htmlErrorMessage + "
\r\n\r\n"
		"\r\n"
		"\r\n";

	sendResponse(errorCode, errorDesc, "text/html", response.c_str());
}

void
HttpResponseImpl::endResponse()
{
	if(m_responding == false)
		beginResponse();

	m_conn->endResponse();
}
<|endoftext|>


<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/common/gpu/media/rendering_helper.h"

#include <map>

#include "base/bind.h"
#include "base/mac/scoped_nsautorelease_pool.h"
#include "base/message_loop.h"
#include "base/stringize_macros.h"
#include "base/synchronization/waitable_event.h"
#include "third_party/angle/include/EGL/egl.h"

#if defined(OS_WIN)
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_context.h"
#include "ui/gl/gl_implementation.h"
#include "ui/gl/gl_surface.h"
#else  // OS_WIN
#include "third_party/angle/include/GLES2/gl2.h"
#endif  // OS_WIN

// Helper for Shader creation.
static void CreateShader(GLuint program,
                         GLenum type,
                         const char* source,
                         int size) {
  GLuint shader = glCreateShader(type);
  glShaderSource(shader, 1, &source, &size);
  glCompileShader(shader);
  int result = GL_FALSE;
  glGetShaderiv(shader, GL_COMPILE_STATUS, &result);
  if (!result) {
    char log[4096];
    glGetShaderInfoLog(shader, arraysize(log), NULL, log);
    LOG(FATAL) << log;
  }
  glAttachShader(program, shader);
  glDeleteShader(shader);
  CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR);
}

namespace video_test_util {

class RenderingHelperEGL : public RenderingHelper {
 public:
  RenderingHelperEGL();
  virtual ~RenderingHelperEGL();

  // Implement RenderingHelper.
  virtual void Initialize(bool suppress_swap_to_display,
                          int num_windows,
                          int width,
                          int height,
                          base::WaitableEvent* done) OVERRIDE;
  virtual void UnInitialize(base::WaitableEvent* done) OVERRIDE;
  virtual void CreateTexture(int window_id,
                             uint32 texture_target,
                             uint32* texture_id,
                             base::WaitableEvent* done) OVERRIDE;
  virtual void RenderTexture(uint32 texture_id) OVERRIDE;
  virtual void DeleteTexture(uint32 texture_id) OVERRIDE;
  virtual void* GetGLContext() OVERRIDE;
  virtual void* GetGLDisplay() OVERRIDE;

 private:
  void Clear();

  // Platform specific Init/Uninit.
  void PlatformInitialize();
  void PlatformUnInitialize();

  // Platform specific window creation.
  EGLNativeWindowType PlatformCreateWindow(int top_left_x, int top_left_y);

  // Platform specific display surface returned here.
  EGLDisplay PlatformGetDisplay();

  MessageLoop* message_loop_;
  int width_;
  int height_;
  bool suppress_swap_to_display_;

  EGLDisplay egl_display_;
  EGLContext egl_context_;
  std::vector<EGLSurface> egl_surfaces_;
  std::map<uint32, int> texture_id_to_surface_index_;

#if defined(OS_WIN)
  std::vector<HWND> windows_;
#else  // OS_WIN
  Display* x_display_;
  std::vector<Window> x_windows_;
#endif  // OS_WIN
};

// static
RenderingHelper* RenderingHelper::Create() {
  return new RenderingHelperEGL;
}

// static
void RenderingHelper::InitializePlatform() {
#if defined(OS_WIN)
  gfx::InitializeGLBindings(gfx::kGLImplementationEGLGLES2);
  gfx::GLSurface::InitializeOneOff();
  {
    // Hack to ensure that EGL extension function pointers are initialized.
    scoped_refptr<gfx::GLSurface> surface(
        gfx::GLSurface::CreateOffscreenGLSurface(false, gfx::Size(1, 1)));
    scoped_refptr<gfx::GLContext> context(
        gfx::GLContext::CreateGLContext(NULL, surface.get(),
                                        gfx::PreferIntegratedGpu));
    context->MakeCurrent(surface.get());
  }
#endif  // OS_WIN
}

RenderingHelperEGL::RenderingHelperEGL() {
  Clear();
}

RenderingHelperEGL::~RenderingHelperEGL() {
  CHECK_EQ(width_, 0) << "Must call UnInitialize before dtor.";
  Clear();
}

void RenderingHelperEGL::Initialize(bool suppress_swap_to_display,
                                    int num_windows,
                                    int width,
                                    int height,
                                    base::WaitableEvent* done) {
  // Use width_ != 0 as a proxy for the class having already been
  // Initialize()'d, and UnInitialize() before continuing.
  if (width_) {
    base::WaitableEvent done(false, false);
    UnInitialize(&done);
    done.Wait();
  }

  suppress_swap_to_display_ = suppress_swap_to_display;
  CHECK_GT(width, 0);
  CHECK_GT(height, 0);
  width_ = width;
  height_ = height;
  message_loop_ = MessageLoop::current();
  CHECK_GT(num_windows, 0);

  PlatformInitialize();

  egl_display_ = PlatformGetDisplay();

  EGLint major;
  EGLint minor;
  CHECK(eglInitialize(egl_display_, &major, &minor)) << eglGetError();
  static EGLint rgba8888[] = {
    EGL_RED_SIZE, 8,
    EGL_GREEN_SIZE, 8,
    EGL_BLUE_SIZE, 8,
    EGL_ALPHA_SIZE, 8,
    EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
    EGL_NONE,
  };
  EGLConfig egl_config;
  int num_configs;
  CHECK(eglChooseConfig(egl_display_, rgba8888, &egl_config, 1, &num_configs))
      << eglGetError();
  CHECK_GE(num_configs, 1);
  static EGLint context_attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
  egl_context_ = eglCreateContext(
      egl_display_, egl_config, EGL_NO_CONTEXT, context_attribs);
  CHECK_NE(egl_context_, EGL_NO_CONTEXT) << eglGetError();

  // Per-window/surface X11 & EGL initialization.
  for (int i = 0; i < num_windows; ++i) {
    // Arrange X windows whimsically, with some padding.
    int top_left_x = (width + 20) * (i % 4);
    int top_left_y = (height + 12) * (i % 3);

    EGLNativeWindowType window = PlatformCreateWindow(top_left_x, top_left_y);
    EGLSurface egl_surface =
        eglCreateWindowSurface(egl_display_, egl_config, window, NULL);
    egl_surfaces_.push_back(egl_surface);
    CHECK_NE(egl_surface, EGL_NO_SURFACE);
  }
  CHECK(eglMakeCurrent(egl_display_, egl_surfaces_[0],
                       egl_surfaces_[0], egl_context_)) << eglGetError();

  static const float kVertices[] =
      { -1.f, 1.f, -1.f, -1.f, 1.f, 1.f, 1.f, -1.f, };
  static const float kTextureCoordsEgl[] = { 0, 1, 0, 0, 1, 1, 1, 0, };
  static const char kVertexShader[] = STRINGIZE(
      varying vec2 interp_tc;
      attribute vec4 in_pos;
      attribute vec2 in_tc;
      void main() {
        interp_tc = in_tc;
        gl_Position = in_pos;
      });
  static const char kFragmentShaderEgl[] = STRINGIZE(
      precision mediump float;
      varying vec2 interp_tc;
      uniform sampler2D tex;
      void main() {
        gl_FragColor = texture2D(tex, interp_tc);
      });
  GLuint program = glCreateProgram();
  CreateShader(program, GL_VERTEX_SHADER,
               kVertexShader, arraysize(kVertexShader));
  CreateShader(program, GL_FRAGMENT_SHADER,
               kFragmentShaderEgl, arraysize(kFragmentShaderEgl));
  glLinkProgram(program);
  int result = GL_FALSE;
  glGetProgramiv(program, GL_LINK_STATUS, &result);
  if (!result) {
    char log[4096];
    glGetShaderInfoLog(program, arraysize(log), NULL, log);
    LOG(FATAL) << log;
  }
  glUseProgram(program);
  glDeleteProgram(program);

  glUniform1i(glGetUniformLocation(program, "tex"), 0);
  int pos_location = glGetAttribLocation(program, "in_pos");
  glEnableVertexAttribArray(pos_location);
  glVertexAttribPointer(pos_location, 2, GL_FLOAT, GL_FALSE, 0, kVertices);
  int tc_location = glGetAttribLocation(program, "in_tc");
  glEnableVertexAttribArray(tc_location);
  glVertexAttribPointer(tc_location, 2, GL_FLOAT, GL_FALSE, 0,
                        kTextureCoordsEgl);
  done->Signal();
}

void RenderingHelperEGL::UnInitialize(base::WaitableEvent* done) {
  CHECK_EQ(MessageLoop::current(), message_loop_);
  CHECK(eglMakeCurrent(egl_display_, EGL_NO_SURFACE, EGL_NO_SURFACE,
                       EGL_NO_CONTEXT)) << eglGetError();
  CHECK(eglDestroyContext(egl_display_, egl_context_));
  for (size_t i = 0; i < egl_surfaces_.size(); ++i)
    CHECK(eglDestroySurface(egl_display_, egl_surfaces_[i]));
  CHECK(eglTerminate(egl_display_));
  Clear();
  done->Signal();
}

void RenderingHelperEGL::CreateTexture(int window_id,
                                       uint32 texture_target,
                                       uint32* texture_id,
                                       base::WaitableEvent* done) {
  if (MessageLoop::current() != message_loop_) {
    message_loop_->PostTask(
        FROM_HERE,
        base::Bind(&RenderingHelper::CreateTexture, base::Unretained(this),
                   window_id, texture_target, texture_id, done));
    return;
  }
  CHECK_EQ(static_cast<uint32>(GL_TEXTURE_2D), texture_target);
  CHECK(eglMakeCurrent(egl_display_, egl_surfaces_[window_id],
                       egl_surfaces_[window_id], egl_context_))
      << eglGetError();
  glGenTextures(1, texture_id);
  glBindTexture(GL_TEXTURE_2D, *texture_id);
  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width_, height_, 0, GL_RGBA,
               GL_UNSIGNED_BYTE, NULL);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  // OpenGLES2.0.25 section 3.8.2 requires CLAMP_TO_EDGE for NPOT textures.
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR);
  CHECK_EQ(static_cast<int>(eglGetError()), EGL_SUCCESS);
  CHECK(texture_id_to_surface_index_.insert(
      std::make_pair(*texture_id, window_id)).second);
  done->Signal();
}

void RenderingHelperEGL::RenderTexture(uint32 texture_id) {
  CHECK_EQ(MessageLoop::current(), message_loop_);
  glActiveTexture(GL_TEXTURE0);
  glBindTexture(GL_TEXTURE_2D, texture_id);
  glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
  CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR);
  CHECK_EQ(static_cast<int>(eglGetError()), EGL_SUCCESS);
  if (!suppress_swap_to_display_) {
    int window_id = texture_id_to_surface_index_[texture_id];
    CHECK(eglMakeCurrent(egl_display_, egl_surfaces_[window_id],
                         egl_surfaces_[window_id], egl_context_))
        << eglGetError();
    eglSwapBuffers(egl_display_, egl_surfaces_[window_id]);
  }
  CHECK_EQ(static_cast<int>(eglGetError()), EGL_SUCCESS);
}

void RenderingHelperEGL::DeleteTexture(uint32 texture_id) {
  glDeleteTextures(1, &texture_id);
  CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR);
}

void* RenderingHelperEGL::GetGLContext() {
  return egl_context_;
}

void* RenderingHelperEGL::GetGLDisplay() {
  return egl_display_;
}

void RenderingHelperEGL::Clear() {
  suppress_swap_to_display_ = false;
  width_ = 0;
  height_ = 0;
  texture_id_to_surface_index_.clear();
  message_loop_ = NULL;
  egl_display_ = EGL_NO_DISPLAY;
  egl_context_ = EGL_NO_CONTEXT;
  egl_surfaces_.clear();
  PlatformUnInitialize();
}

#if defined(OS_WIN)
void RenderingHelperEGL::PlatformInitialize() {}

void RenderingHelperEGL::PlatformUnInitialize() {
  for (size_t i = 0; i < windows_.size(); ++i) {
    DestroyWindow(windows_[i]);
  }
  windows_.clear();
}

EGLNativeWindowType RenderingHelperEGL::PlatformCreateWindow(
    int top_left_x, int top_left_y) {
  HWND window = CreateWindowEx(0, L"Static", L"VideoDecodeAcceleratorTest",
                               WS_OVERLAPPEDWINDOW | WS_VISIBLE, top_left_x,
                               top_left_y, width_, height_, NULL, NULL, NULL,
                               NULL);
  CHECK(window != NULL);
  windows_.push_back(window);
  return window;
}

EGLDisplay RenderingHelperEGL::PlatformGetDisplay() {
  return eglGetDisplay(EGL_DEFAULT_DISPLAY);
}

#else  // OS_WIN

void RenderingHelperEGL::PlatformInitialize() {
  CHECK(x_display_ = base::MessagePumpForUI::GetDefaultXDisplay());
}

void RenderingHelperEGL::PlatformUnInitialize() {
  // Destroy resources acquired in Initialize, in reverse-acquisition order.
  for (size_t i = 0; i < x_windows_.size(); ++i) {
    CHECK(XUnmapWindow(x_display_, x_windows_[i]));
    CHECK(XDestroyWindow(x_display_, x_windows_[i]));
  }
  // Mimic newly created object.
  x_display_ = NULL;
  x_windows_.clear();
}

EGLDisplay RenderingHelperEGL::PlatformGetDisplay() {
  return eglGetDisplay(x_display_);
}

EGLNativeWindowType RenderingHelperEGL::PlatformCreateWindow(int top_left_x,
                                                             int top_left_y) {
  int depth = DefaultDepth(x_display_, DefaultScreen(x_display_));

  XSetWindowAttributes window_attributes;
  window_attributes.background_pixel =
      BlackPixel(x_display_, DefaultScreen(x_display_));
  window_attributes.override_redirect = true;

  Window x_window = XCreateWindow(
      x_display_, DefaultRootWindow(x_display_),
      top_left_x, top_left_y, width_, height_,
      0 /* border width */,
      depth, CopyFromParent /* class */, CopyFromParent /* visual */,
      (CWBackPixel | CWOverrideRedirect), &window_attributes);
  x_windows_.push_back(x_window);
  XStoreName(x_display_, x_window, "VideoDecodeAcceleratorTest");
  XSelectInput(x_display_, x_window, ExposureMask);
  XMapWindow(x_display_, x_window);
  return x_window;
}

#endif  // OS_WIN

}  // namespace video_test_util
<commit_msg>Delete content/common/gpu/media/rendering_helper_egl.cc which was cp'd instead of mv'd in r145561.<commit_after><|endoftext|>


<commit_before>#include "trikRuntimeUploaderPlugin.h"

#include <QtCore/QProcess>
#include <QtWidgets/QApplication>

#include <qrkernel/settingsManager.h>

using namespace trik;

TrikRuntimeUploaderPlugin::TrikRuntimeUploaderPlugin()
	: mAction(new QAction(QIcon(":/trik/images/flashRobot.svg"), tr("Upload Runtime"), nullptr))
{
	connect(mAction, &QAction::triggered, this, &TrikRuntimeUploaderPlugin::uploadRuntime);
}

QList<qReal::ActionInfo> TrikRuntimeUploaderPlugin::actions()
{
	QAction *separator = new QAction(this);
	separator->setSeparator(true);
	qReal::ActionInfo separatorInfo(separator, "generators", "tools");
	qReal::ActionInfo info(mAction, "generators", "tools");
	return { info, separatorInfo };
}

void TrikRuntimeUploaderPlugin::uploadRuntime()
{
	QProcess scpProcess;
	QString const openConnection = QString("\"open scp://root@%1\"")
			.arg(qReal::SettingsManager::value("TrikTcpServer").toString());

	QString const killTrikGui = "\"call killall trikGui\"";
	QString const removePermissions = "\"call chmod a-x trik/trik*\"";
	QString const restorePermissions = "\"call chmod a+x trik/trik*\"";
	QString const restartTrikGui = "\"call cd trik\" \"call ./trikGui -qws &\"";

	QString const moveCommand = " \"synchronize remote trikRuntime /home/root/trik\"";

	QString const rawWinscpPath = qReal::SettingsManager::value("WinScpPath").toString();
	QString const winscpPath = rawWinscpPath.startsWith("./")
			? QApplication::applicationDirPath() + rawWinscpPath.mid(1)
			: rawWinscpPath;

	QString const command = QString("\"%1\" /command %2 %3 %4 %5 %6 %7")
			.arg(winscpPath)
			.arg(openConnection)
			.arg(removePermissions)
			.arg(killTrikGui)
			.arg(moveCommand)
			.arg(restorePermissions)
			.arg(restartTrikGui);

	if (!scpProcess.startDetached(command + " \"exit\" ")) {
		mMainWindowInterface->errorReporter()->addError(
			tr("WinSCP process failed to launch, check path in settings.")
		);
	} else {
		mMainWindowInterface->errorReporter()->addWarning(
			tr("Attention! Started to download the runtime. Please do not turn off the robot.")
		);
	}
}

generatorBase::MasterGeneratorBase *TrikRuntimeUploaderPlugin::masterGenerator()
{
	return nullptr;
}
<commit_msg>Fixed trikGui restart after uploading new runtime version to robot<commit_after>#include "trikRuntimeUploaderPlugin.h"

#include <QtCore/QProcess>
#include <QtWidgets/QApplication>

#include <qrkernel/settingsManager.h>

using namespace trik;

TrikRuntimeUploaderPlugin::TrikRuntimeUploaderPlugin()
	: mAction(new QAction(QIcon(":/trik/images/flashRobot.svg"), tr("Upload Runtime"), nullptr))
{
	connect(mAction, &QAction::triggered, this, &TrikRuntimeUploaderPlugin::uploadRuntime);
}

QList<qReal::ActionInfo> TrikRuntimeUploaderPlugin::actions()
{
	QAction *separator = new QAction(this);
	separator->setSeparator(true);
	qReal::ActionInfo separatorInfo(separator, "generators", "tools");
	qReal::ActionInfo info(mAction, "generators", "tools");
	return { info, separatorInfo };
}

void TrikRuntimeUploaderPlugin::uploadRuntime()
{
	QProcess scpProcess;
	QString const openConnection = QString("\"open scp://root@%1\"")
			.arg(qReal::SettingsManager::value("TrikTcpServer").toString());

	QString const killTrikGui = "\"call killall trikGui\"";
	QString const createTrikDirectory = "\"call mkdir -p /home/root/trik\"";
	QString const removePermissions = "\"call chmod a-x trik/trik*\"";
	QString const restorePermissions = "\"call chmod a+x trik/trik*\"";
	QString const restartTrikGui = "\"call /bin/sh -c '/etc/trik/trikGui.sh &'\"";

	QString const moveCommand = " \"synchronize remote trikRuntime /home/root/trik\"";

	QString const rawWinscpPath = qReal::SettingsManager::value("WinScpPath").toString();
	QString const winscpPath = rawWinscpPath.startsWith("./")
			? QApplication::applicationDirPath() + rawWinscpPath.mid(1)
			: rawWinscpPath;

	QString const command = QString("\"%1\" /command %2 %3 %4 %5 %6 %7 %8")
			.arg(winscpPath)
			.arg(openConnection)
			.arg(createTrikDirectory)
			.arg(removePermissions)
			.arg(killTrikGui)
			.arg(moveCommand)
			.arg(restorePermissions)
			.arg(restartTrikGui);

	if (!scpProcess.startDetached(command + " \"exit\" ")) {
		mMainWindowInterface->errorReporter()->addError(
			tr("WinSCP process failed to launch, check path in settings.")
		);
	} else {
		mMainWindowInterface->errorReporter()->addWarning(
			tr("Attention! Started to download the runtime. Please do not turn off the robot.")
		);
	}
}

generatorBase::MasterGeneratorBase *TrikRuntimeUploaderPlugin::masterGenerator()
{
	return nullptr;
}
<|endoftext|>


<commit_before>/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#include "infill.h"

namespace cura {

void generateConcentricInfill(Polygons outline, Polygons& result, int inset_value)
{
    while(outline.size() < 1)
    {
        for (unsigned int polyNr = 0; polyNr < outline.size(); polyNr++)
        {
            PolygonRef r = outline[polyNr];
            result.add(r);
        }
        outline = outline.offset(-inset_value);
    }
}

void generateAutomaticInfill(const Polygons& in_outline, Polygons& result,
                             int extrusionWidth, int lineSpacing,
                             int infillOverlap, double rotation)
{
    if (lineSpacing > extrusionWidth * 4)
    {
        generateGridInfill(in_outline, result, extrusionWidth, lineSpacing,
                           infillOverlap, rotation);
    }
    else
    {
        generateLineInfill(in_outline, result, extrusionWidth, lineSpacing,
                           infillOverlap, rotation);
    }
}

void generateGridInfill(const Polygons& in_outline, Polygons& result,
                        int extrusionWidth, int lineSpacing, int infillOverlap,
                        double rotation)
{
    generateLineInfill(in_outline, result, extrusionWidth, lineSpacing * 2,
                       infillOverlap, rotation);
    generateLineInfill(in_outline, result, extrusionWidth, lineSpacing * 2,
                       infillOverlap, rotation + 90);
}

int compare_int64_t(const void* a, const void* b)
{
    int64_t n = (*(int64_t*)a) - (*(int64_t*)b);
    if (n < 0) return -1;
    if (n > 0) return 1;
    return 0;
}

void generateLineInfill(const Polygons& in_outline, Polygons& result, int extrusionWidth, int lineSpacing, int infillOverlap, double rotation)
{
    Polygons outline = in_outline.offset(extrusionWidth * infillOverlap / 100);
    PointMatrix matrix(rotation);

    outline.applyMatrix(matrix);

    AABB boundary(outline);

    boundary.min.X = ((boundary.min.X / lineSpacing) - 1) * lineSpacing;
    int lineCount = (boundary.max.X - boundary.min.X + (lineSpacing - 1)) / lineSpacing;
    vector<vector<int64_t> > cutList;
    for(int n=0; n<lineCount; n++)
        cutList.push_back(vector<int64_t>());

    for(unsigned int polyNr=0; polyNr < outline.size(); polyNr++)
    {
        Point p1 = outline[polyNr][outline[polyNr].size()-1];
        for(unsigned int i=0; i < outline[polyNr].size(); i++)
        {
            Point p0 = outline[polyNr][i];
            int idx0 = (p0.X - boundary.min.X) / lineSpacing;
            int idx1 = (p1.X - boundary.min.X) / lineSpacing;
            int64_t xMin = p0.X, xMax = p1.X;
            if (p0.X > p1.X) { xMin = p1.X; xMax = p0.X; }
            if (idx0 > idx1) { int tmp = idx0; idx0 = idx1; idx1 = tmp; }
            for(int idx = idx0; idx<=idx1; idx++)
            {
                int x = (idx * lineSpacing) + boundary.min.X + lineSpacing / 2;
                if (x < xMin) continue;
                if (x >= xMax) continue;
                int y = p0.Y + (p1.Y - p0.Y) * (x - p0.X) / (p1.X - p0.X);
                cutList[idx].push_back(y);
            }
            p1 = p0;
        }
    }

    int idx = 0;
    for(int64_t x = boundary.min.X + lineSpacing / 2; x < boundary.max.X; x += lineSpacing)
    {
        qsort(cutList[idx].data(), cutList[idx].size(), sizeof(int64_t), compare_int64_t);
        for(unsigned int i = 0; i + 1 < cutList[idx].size(); i+=2)
        {
            if (cutList[idx][i+1] - cutList[idx][i] < extrusionWidth / 5)
                continue;
            PolygonRef p = result.newPoly();
            p.add(matrix.unapply(Point(x, cutList[idx][i])));
            p.add(matrix.unapply(Point(x, cutList[idx][i+1])));
        }
        idx += 1;
    }
}

}//namespace cura
<commit_msg>Fix the bug introduced into the concentric infill in #90<commit_after>/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#include "infill.h"

namespace cura {

void generateConcentricInfill(Polygons outline, Polygons& result, int inset_value)
{
    while(outline.size() > 0)
    {
        for (unsigned int polyNr = 0; polyNr < outline.size(); polyNr++)
        {
            PolygonRef r = outline[polyNr];
            result.add(r);
        }
        outline = outline.offset(-inset_value);
    }
}

void generateAutomaticInfill(const Polygons& in_outline, Polygons& result,
                             int extrusionWidth, int lineSpacing,
                             int infillOverlap, double rotation)
{
    if (lineSpacing > extrusionWidth * 4)
    {
        generateGridInfill(in_outline, result, extrusionWidth, lineSpacing,
                           infillOverlap, rotation);
    }
    else
    {
        generateLineInfill(in_outline, result, extrusionWidth, lineSpacing,
                           infillOverlap, rotation);
    }
}

void generateGridInfill(const Polygons& in_outline, Polygons& result,
                        int extrusionWidth, int lineSpacing, int infillOverlap,
                        double rotation)
{
    generateLineInfill(in_outline, result, extrusionWidth, lineSpacing * 2,
                       infillOverlap, rotation);
    generateLineInfill(in_outline, result, extrusionWidth, lineSpacing * 2,
                       infillOverlap, rotation + 90);
}

int compare_int64_t(const void* a, const void* b)
{
    int64_t n = (*(int64_t*)a) - (*(int64_t*)b);
    if (n < 0) return -1;
    if (n > 0) return 1;
    return 0;
}

void generateLineInfill(const Polygons& in_outline, Polygons& result, int extrusionWidth, int lineSpacing, int infillOverlap, double rotation)
{
    Polygons outline = in_outline.offset(extrusionWidth * infillOverlap / 100);
    PointMatrix matrix(rotation);

    outline.applyMatrix(matrix);

    AABB boundary(outline);

    boundary.min.X = ((boundary.min.X / lineSpacing) - 1) * lineSpacing;
    int lineCount = (boundary.max.X - boundary.min.X + (lineSpacing - 1)) / lineSpacing;
    vector<vector<int64_t> > cutList;
    for(int n=0; n<lineCount; n++)
        cutList.push_back(vector<int64_t>());

    for(unsigned int polyNr=0; polyNr < outline.size(); polyNr++)
    {
        Point p1 = outline[polyNr][outline[polyNr].size()-1];
        for(unsigned int i=0; i < outline[polyNr].size(); i++)
        {
            Point p0 = outline[polyNr][i];
            int idx0 = (p0.X - boundary.min.X) / lineSpacing;
            int idx1 = (p1.X - boundary.min.X) / lineSpacing;
            int64_t xMin = p0.X, xMax = p1.X;
            if (p0.X > p1.X) { xMin = p1.X; xMax = p0.X; }
            if (idx0 > idx1) { int tmp = idx0; idx0 = idx1; idx1 = tmp; }
            for(int idx = idx0; idx<=idx1; idx++)
            {
                int x = (idx * lineSpacing) + boundary.min.X + lineSpacing / 2;
                if (x < xMin) continue;
                if (x >= xMax) continue;
                int y = p0.Y + (p1.Y - p0.Y) * (x - p0.X) / (p1.X - p0.X);
                cutList[idx].push_back(y);
            }
            p1 = p0;
        }
    }

    int idx = 0;
    for(int64_t x = boundary.min.X + lineSpacing / 2; x < boundary.max.X; x += lineSpacing)
    {
        qsort(cutList[idx].data(), cutList[idx].size(), sizeof(int64_t), compare_int64_t);
        for(unsigned int i = 0; i + 1 < cutList[idx].size(); i+=2)
        {
            if (cutList[idx][i+1] - cutList[idx][i] < extrusionWidth / 5)
                continue;
            PolygonRef p = result.newPoly();
            p.add(matrix.unapply(Point(x, cutList[idx][i])));
            p.add(matrix.unapply(Point(x, cutList[idx][i+1])));
        }
        idx += 1;
    }
}

}//namespace cura
<|endoftext|>


<commit_before>#include <netdb.h>
#include <unistd.h>
#include <sys/fcntl.h>

#include "client.h"
#include "duckchat.h"
#include "raw.h"

// Client connects, logs in, and joins “Common”.
// Client reads lines from the user and parses commands.
// Client correctly sends Say message.
// Client uses select() to wait for input from the user and the server.
// Client correctly sends Join, Leave, Login, and Logout and TODO handles Switch.
// TODO Client correctly sends List and Who.
// TODO Server can accept connections.
// TODO Server handles Login and Logout from users, and keeps records of which users are logged in.
// TODO Server handles Join and Leave from users, keeps records of which channels a user belongs to,
// and keeps records of which users are in a channel.
// TODO Server handles the Say message.
// TODO Server correctly handles List and Who.
// TODO Create copies of your client and server source. Modify them to send invalid packets to your good client
// and server, to see if you can make your client or server crash. Fix any bugs you find.

// Variables
struct sockaddr_in client_addr;
struct sockaddr_in server_addr;
int client_socket;
struct addrinfo *server_info;
std::string current_channel;
std::vector<std::string> channels;

// Prints an error message and exits the program.
void Error(const char *msg) {
  std::cerr << msg << std::endl;
  exit(1);
}

void PrintPrompt() {
  std::cout << "> " << std::flush;
}

// Splits strings around spaces.
std::vector<std::string> StringSplit(std::string input) {
  std::istringstream iss(input);
  std::vector<std::string> result{std::istream_iterator<std::string>{iss}, std::istream_iterator<std::string>{}};

  return result;
}

// Splits strings around spaces.
std::vector<std::string> SplitString(char *input, char delimiter) {
  std::vector<std::string> result;
  std::string word = "";

  size_t input_size = strlen(input);
  for (size_t i = 0; i < input_size; i++) {
    if (input[i] != delimiter) {
      word += input[i];
    } else {
      result.push_back(word);
      word = "";
    }
  }
  result.push_back(word);

  return result;
}

void StripChar(char *input, char c) {
  size_t size = strlen(input);
  for (size_t i = 0; i < size; i++) {
    if (input[i] == c) {
      input[i] = '\0';
    }
  }
}

// Gets the address info of the server at a the given port and creates the client's socket.
void CreateSocket(char *domain, const char *port) {
  std::cout << "Connecting to " << domain << std::endl;

  struct addrinfo hints;
  struct addrinfo *server_info_tmp;
  int status;

  memset(&hints, 0, sizeof(hints));
  hints.ai_family = AF_UNSPEC;
  hints.ai_socktype = SOCK_DGRAM;
  hints.ai_protocol = 0;

  if ((status = getaddrinfo(domain, port, &hints, &server_info_tmp)) != 0) {
    std::cerr << "client: unable to resolve address: " << gai_strerror(status) << std::endl;
    exit(1);
  }

  // getaddrinfo() returns a list of address structures into server_info_tmp.
  // Tries each address until a successful connect().
  // If socket() (or connect()) fails, closes the socket and tries the next address.

  for (server_info = server_info_tmp; server_info != NULL; server_info = server_info->ai_next) {
    if ((client_socket = socket(server_info->ai_family, server_info->ai_socktype, server_info->ai_protocol)) < 0) {
      continue;
    }
    if (connect(client_socket, server_info->ai_addr, server_info->ai_addrlen) != -1) {
      fcntl(client_socket, F_SETFL, O_NONBLOCK);
      break; // Success
    }
    close(client_socket);
  }

  if (server_info == NULL) {
    Error("client: all sockets failed to connect");
  }
}

// Sends a message to all users in on the active channel.
int SendSay(std::string message) {
  struct request_say say;
  memset(&say, 0, sizeof(say));
  say.req_type = REQ_SAY;
  strncpy(say.req_text, message.c_str(), SAY_MAX);
  strncpy(say.req_channel, current_channel.c_str(), CHANNEL_MAX);

  if (sendto(client_socket, &say, sizeof(say), 0, server_info->ai_addr, server_info->ai_addrlen) < 0) {
    Error("client: failed to send message\n");
  }

  return 0;
}

// Sends login requests to the server.
int SendLogin(char *username) {
  struct request_login login;
  memset(&login, 0, sizeof(login));
  login.req_type = REQ_LOGIN;
  strncpy(login.req_username, username, USERNAME_MAX);

  size_t message_size = sizeof(struct request_login);

  if (sendto(client_socket, &login, message_size, 0, server_info->ai_addr, server_info->ai_addrlen) < 0) {
    Error("client: failed to request login\n");
  }

  return 0;
}

// Sends logout requests to the server.
int SendLogout() {
  struct request_logout logout;
  memset((char *) &logout, 0, sizeof(logout));
  logout.req_type = REQ_LOGOUT;

  size_t message_size = sizeof(struct request_logout);

  if (sendto(client_socket, &logout, message_size, 0, server_info->ai_addr, server_info->ai_addrlen) < 0) {
    Error("client: failed to request logout\n");
  }

  return 0;
}

int SendList(){
  struct request_list list;
  list.req_type = REQ_LIST;
  size_t list_size = sizeof(struct request_list);

  if (sendto(client_socket, &list, list_size, 0, server_info->ai_addr, server_info->ai_addrlen) < 0) {
    Error("client: failed to request list \n");
  }

  return 0;
}

// Sends join requests to the server.
int SendJoin(std::string channel) {
  bool contains_channel = false;
  for (std::vector<std::string>::iterator it = channels.begin(); it != channels.end(); ++it) {
    if (*it == channel) {
      contains_channel = true;
      break;
    }
  }

  if (!contains_channel) {
    channels.push_back(channel);

    struct request_join join;
    memset((char *) &join, 0, sizeof(join));
    join.req_type = REQ_JOIN;
    strncpy(join.req_channel, channel.c_str(), CHANNEL_MAX);

    size_t message_size = sizeof(struct request_join);

    if (sendto(client_socket, &join, message_size, 0, server_info->ai_addr, server_info->ai_addrlen) < 0) {
      Error("client: failed to request join\n");
    }
  }

  return 0;
}

// Switches to a channel the user has already joined.
int SwitchChannel(std::string channel) {
  bool isSubscribed = false;

  if (channels.size() > 0) {
    for (auto c: channels) {
      if (channel == c) {
        current_channel = channel;
        isSubscribed = true;
      }
    }
  }

  if (!isSubscribed) {
    std::cout << "You have not subscribed to channel " << channel << std::endl;
  }

  return 0;
}

void HandleTextList(char *receive_buffer, char *output) {
  struct text_list list;
  memcpy(&list, receive_buffer, sizeof(struct text_list));

  std::string backspaces = "";
  for (int i = 0; i < SAY_MAX; i++) {
    backspaces.append("\b");
  }
  std::cout << backspaces;

  std::cout << "Existing channels:" << std::endl;
  for(int i = 2; i < list.txt_nchannels; i++){
    std::cout << " " << list.txt_channels[i].ch_channel << std::endl;
  }

  PrintPrompt();
  std::cout << output << std::flush;
}

// Handles TXT-SAY server messages.
void HandleTextSay(char *receive_buffer, char *output) {
  struct text_say say;
  memcpy(&say, receive_buffer, sizeof(struct text_say));

  std::string backspaces = "";
  for (int i = 0; i < SAY_MAX; i++) {
    backspaces.append("\b");
  }
  std::cout << backspaces;
  std::cout << "[" << say.txt_channel << "]" << "[" << say.txt_username << "]: " << say.txt_text << std::endl;
  PrintPrompt();
  std::cout << output << std::flush;
}

// Processes the input string to decide what type of command it is.
bool ProcessInput(std::string input) {
  std::vector<std::string> inputs = StringSplit(input);

  if (inputs[0] == "/exit") {
    SendLogout();
    cooked_mode();
    return false;
  } else if (inputs[0] == "/list") {
    SendList();
  } else if (inputs[0] == "/join" && inputs.size() > 1) {
    SendJoin(inputs[1].c_str());
  } else if (inputs[0] == "/leave") {

  } else if (inputs[0] == "/who") {

  } else if (inputs[0] == "/switch" && inputs.size() > 1) {
    SwitchChannel(inputs[1].c_str());
  } else {
    std::cout << "*Unknown command" << std::endl;
  }

  PrintPrompt();
  return true;
}

int main(int argc, char *argv[]) {
  char *domain;
  char *port_str;
  int port_num;
  char *username;
  std::string input;
  char *output = (char *) "";
  fd_set read_set;
  int result;

  char stdin_buffer[SAY_MAX + 1];
  char *stdin_buffer_pointer = stdin_buffer;

  char receive_buffer[kBufferSize];
  memset(&receive_buffer, 0, kBufferSize);

  if (argc < 4) {
    Error("usage: client [server name] [port] [username]");
  }

  domain = argv[1];
  port_str = argv[2];
  port_num = atoi(argv[2]);
  username = argv[3];

  if (strlen(domain) > UNIX_PATH_MAX) {
    Error("client: server name must be less than 108 characters");
  }

  if (port_num < 0 || port_num > 65535) {
    Error("client: port number must be between 0 and 65535");
  }

  if (strlen(username) > USERNAME_MAX) {
    Error("client: username must be less than 32 characters");
  }

  CreateSocket(domain, port_str);

  SendLogin(username);

  current_channel = "Common";
  SendJoin(current_channel);

  if (raw_mode() != 0){
    Error("client: error using raw mode");
  }

  PrintPrompt();

  while (1) {
    FD_ZERO(&read_set);
    FD_SET(client_socket, &read_set);
    FD_SET(STDIN_FILENO, &read_set);

    if ((result = select(client_socket + 1, &read_set, NULL, NULL, NULL)) < 0) {
      Error("client: problem using select");
    }

    if (result > 0) {
      if (FD_ISSET(STDIN_FILENO, &read_set)) {
        // User entered a char.
        char c = (char) getchar();
        if (c == '\n') {
          // Increments pointer and adds NULL char.
          *stdin_buffer_pointer++ = '\0';

          // Resets stdin_buffer_pointer to the start of stdin_buffer.
          stdin_buffer_pointer = stdin_buffer;

          std::cout << "\n" << std::flush;

          // Prevents output from printing on the new prompt after a newline char.
          output = (char *) "";

          input.assign(stdin_buffer, stdin_buffer + strlen(stdin_buffer));

          if (input[0] == '/') {
            if (!ProcessInput(input)) {
              break;
            }
          } else {
            // Sends chat messages.
            SendSay(input);
          }
        } else if (stdin_buffer_pointer != stdin_buffer + SAY_MAX) {
          // Increments pointer and adds char c.
          *stdin_buffer_pointer++ = c;

          std::cout << c << std::flush;

          // Copies pointer into output.
          output = stdin_buffer_pointer;
          // Increments and sets NULL char.
          *output++ = '\0';
          // Copies stdin_buffer into part of output before NULL char.
          output = stdin_buffer;
        }
      } else if (FD_ISSET(client_socket, &read_set)) {
        // Socket has data.
        ssize_t read_size = read(client_socket, receive_buffer, kBufferSize);

        if (read_size != 0) {
          struct text message;
          memcpy(&message, receive_buffer, sizeof(struct text));
          text_t text_type = message.txt_type;

          switch (text_type) {
            case TXT_SAY:
              HandleTextSay(receive_buffer, output);
              break;
            case TXT_LIST:
              HandleTextList(receive_buffer, output);
              break;
            default:
              break;
          }
        }

        memset(&receive_buffer, 0, SAY_MAX);
      } // end of if client_socket

    } // end of if result

  } // end of while

  return 0;
}<commit_msg>Index change pt.2<commit_after>#include <netdb.h>
#include <unistd.h>
#include <sys/fcntl.h>

#include "client.h"
#include "duckchat.h"
#include "raw.h"

// Client connects, logs in, and joins “Common”.
// Client reads lines from the user and parses commands.
// Client correctly sends Say message.
// Client uses select() to wait for input from the user and the server.
// Client correctly sends Join, Leave, Login, and Logout and TODO handles Switch.
// TODO Client correctly sends List and Who.
// TODO Server can accept connections.
// TODO Server handles Login and Logout from users, and keeps records of which users are logged in.
// TODO Server handles Join and Leave from users, keeps records of which channels a user belongs to,
// and keeps records of which users are in a channel.
// TODO Server handles the Say message.
// TODO Server correctly handles List and Who.
// TODO Create copies of your client and server source. Modify them to send invalid packets to your good client
// and server, to see if you can make your client or server crash. Fix any bugs you find.

// Variables
struct sockaddr_in client_addr;
struct sockaddr_in server_addr;
int client_socket;
struct addrinfo *server_info;
std::string current_channel;
std::vector<std::string> channels;

// Prints an error message and exits the program.
void Error(const char *msg) {
  std::cerr << msg << std::endl;
  exit(1);
}

void PrintPrompt() {
  std::cout << "> " << std::flush;
}

// Splits strings around spaces.
std::vector<std::string> StringSplit(std::string input) {
  std::istringstream iss(input);
  std::vector<std::string> result{std::istream_iterator<std::string>{iss}, std::istream_iterator<std::string>{}};

  return result;
}

// Splits strings around spaces.
std::vector<std::string> SplitString(char *input, char delimiter) {
  std::vector<std::string> result;
  std::string word = "";

  size_t input_size = strlen(input);
  for (size_t i = 0; i < input_size; i++) {
    if (input[i] != delimiter) {
      word += input[i];
    } else {
      result.push_back(word);
      word = "";
    }
  }
  result.push_back(word);

  return result;
}

void StripChar(char *input, char c) {
  size_t size = strlen(input);
  for (size_t i = 0; i < size; i++) {
    if (input[i] == c) {
      input[i] = '\0';
    }
  }
}

// Gets the address info of the server at a the given port and creates the client's socket.
void CreateSocket(char *domain, const char *port) {
  std::cout << "Connecting to " << domain << std::endl;

  struct addrinfo hints;
  struct addrinfo *server_info_tmp;
  int status;

  memset(&hints, 0, sizeof(hints));
  hints.ai_family = AF_UNSPEC;
  hints.ai_socktype = SOCK_DGRAM;
  hints.ai_protocol = 0;

  if ((status = getaddrinfo(domain, port, &hints, &server_info_tmp)) != 0) {
    std::cerr << "client: unable to resolve address: " << gai_strerror(status) << std::endl;
    exit(1);
  }

  // getaddrinfo() returns a list of address structures into server_info_tmp.
  // Tries each address until a successful connect().
  // If socket() (or connect()) fails, closes the socket and tries the next address.

  for (server_info = server_info_tmp; server_info != NULL; server_info = server_info->ai_next) {
    if ((client_socket = socket(server_info->ai_family, server_info->ai_socktype, server_info->ai_protocol)) < 0) {
      continue;
    }
    if (connect(client_socket, server_info->ai_addr, server_info->ai_addrlen) != -1) {
      fcntl(client_socket, F_SETFL, O_NONBLOCK);
      break; // Success
    }
    close(client_socket);
  }

  if (server_info == NULL) {
    Error("client: all sockets failed to connect");
  }
}

// Sends a message to all users in on the active channel.
int SendSay(std::string message) {
  struct request_say say;
  memset(&say, 0, sizeof(say));
  say.req_type = REQ_SAY;
  strncpy(say.req_text, message.c_str(), SAY_MAX);
  strncpy(say.req_channel, current_channel.c_str(), CHANNEL_MAX);

  if (sendto(client_socket, &say, sizeof(say), 0, server_info->ai_addr, server_info->ai_addrlen) < 0) {
    Error("client: failed to send message\n");
  }

  return 0;
}

// Sends login requests to the server.
int SendLogin(char *username) {
  struct request_login login;
  memset(&login, 0, sizeof(login));
  login.req_type = REQ_LOGIN;
  strncpy(login.req_username, username, USERNAME_MAX);

  size_t message_size = sizeof(struct request_login);

  if (sendto(client_socket, &login, message_size, 0, server_info->ai_addr, server_info->ai_addrlen) < 0) {
    Error("client: failed to request login\n");
  }

  return 0;
}

// Sends logout requests to the server.
int SendLogout() {
  struct request_logout logout;
  memset((char *) &logout, 0, sizeof(logout));
  logout.req_type = REQ_LOGOUT;

  size_t message_size = sizeof(struct request_logout);

  if (sendto(client_socket, &logout, message_size, 0, server_info->ai_addr, server_info->ai_addrlen) < 0) {
    Error("client: failed to request logout\n");
  }

  return 0;
}

int SendList(){
  struct request_list list;
  list.req_type = REQ_LIST;
  size_t list_size = sizeof(struct request_list);

  if (sendto(client_socket, &list, list_size, 0, server_info->ai_addr, server_info->ai_addrlen) < 0) {
    Error("client: failed to request list \n");
  }

  return 0;
}

// Sends join requests to the server.
int SendJoin(std::string channel) {
  bool contains_channel = false;
  for (std::vector<std::string>::iterator it = channels.begin(); it != channels.end(); ++it) {
    if (*it == channel) {
      contains_channel = true;
      break;
    }
  }

  if (!contains_channel) {
    channels.push_back(channel);

    struct request_join join;
    memset((char *) &join, 0, sizeof(join));
    join.req_type = REQ_JOIN;
    strncpy(join.req_channel, channel.c_str(), CHANNEL_MAX);

    size_t message_size = sizeof(struct request_join);

    if (sendto(client_socket, &join, message_size, 0, server_info->ai_addr, server_info->ai_addrlen) < 0) {
      Error("client: failed to request join\n");
    }
  }

  return 0;
}

// Switches to a channel the user has already joined.
int SwitchChannel(std::string channel) {
  bool isSubscribed = false;

  if (channels.size() > 0) {
    for (auto c: channels) {
      if (channel == c) {
        current_channel = channel;
        isSubscribed = true;
      }
    }
  }

  if (!isSubscribed) {
    std::cout << "You have not subscribed to channel " << channel << std::endl;
  }

  return 0;
}

void HandleTextList(char *receive_buffer, char *output) {
  struct text_list list;
  memcpy(&list, receive_buffer, sizeof(struct text_list));

  std::string backspaces = "";
  for (int i = 0; i < SAY_MAX; i++) {
    backspaces.append("\b");
  }
  std::cout << backspaces;

  std::cout << "Existing channels:" << std::endl;
  for(int i = 2; i < list.txt_nchannels + 2; i++){
    std::cout << " " << list.txt_channels[i].ch_channel << std::endl;
  }

  PrintPrompt();
  std::cout << output << std::flush;
}

// Handles TXT-SAY server messages.
void HandleTextSay(char *receive_buffer, char *output) {
  struct text_say say;
  memcpy(&say, receive_buffer, sizeof(struct text_say));

  std::string backspaces = "";
  for (int i = 0; i < SAY_MAX; i++) {
    backspaces.append("\b");
  }
  std::cout << backspaces;
  std::cout << "[" << say.txt_channel << "]" << "[" << say.txt_username << "]: " << say.txt_text << std::endl;
  PrintPrompt();
  std::cout << output << std::flush;
}

// Processes the input string to decide what type of command it is.
bool ProcessInput(std::string input) {
  std::vector<std::string> inputs = StringSplit(input);

  if (inputs[0] == "/exit") {
    SendLogout();
    cooked_mode();
    return false;
  } else if (inputs[0] == "/list") {
    SendList();
  } else if (inputs[0] == "/join" && inputs.size() > 1) {
    SendJoin(inputs[1].c_str());
  } else if (inputs[0] == "/leave") {

  } else if (inputs[0] == "/who") {

  } else if (inputs[0] == "/switch" && inputs.size() > 1) {
    SwitchChannel(inputs[1].c_str());
  } else {
    std::cout << "*Unknown command" << std::endl;
  }

  PrintPrompt();
  return true;
}

int main(int argc, char *argv[]) {
  char *domain;
  char *port_str;
  int port_num;
  char *username;
  std::string input;
  char *output = (char *) "";
  fd_set read_set;
  int result;

  char stdin_buffer[SAY_MAX + 1];
  char *stdin_buffer_pointer = stdin_buffer;

  char receive_buffer[kBufferSize];
  memset(&receive_buffer, 0, kBufferSize);

  if (argc < 4) {
    Error("usage: client [server name] [port] [username]");
  }

  domain = argv[1];
  port_str = argv[2];
  port_num = atoi(argv[2]);
  username = argv[3];

  if (strlen(domain) > UNIX_PATH_MAX) {
    Error("client: server name must be less than 108 characters");
  }

  if (port_num < 0 || port_num > 65535) {
    Error("client: port number must be between 0 and 65535");
  }

  if (strlen(username) > USERNAME_MAX) {
    Error("client: username must be less than 32 characters");
  }

  CreateSocket(domain, port_str);

  SendLogin(username);

  current_channel = "Common";
  SendJoin(current_channel);

  if (raw_mode() != 0){
    Error("client: error using raw mode");
  }

  PrintPrompt();

  while (1) {
    FD_ZERO(&read_set);
    FD_SET(client_socket, &read_set);
    FD_SET(STDIN_FILENO, &read_set);

    if ((result = select(client_socket + 1, &read_set, NULL, NULL, NULL)) < 0) {
      Error("client: problem using select");
    }

    if (result > 0) {
      if (FD_ISSET(STDIN_FILENO, &read_set)) {
        // User entered a char.
        char c = (char) getchar();
        if (c == '\n') {
          // Increments pointer and adds NULL char.
          *stdin_buffer_pointer++ = '\0';

          // Resets stdin_buffer_pointer to the start of stdin_buffer.
          stdin_buffer_pointer = stdin_buffer;

          std::cout << "\n" << std::flush;

          // Prevents output from printing on the new prompt after a newline char.
          output = (char *) "";

          input.assign(stdin_buffer, stdin_buffer + strlen(stdin_buffer));

          if (input[0] == '/') {
            if (!ProcessInput(input)) {
              break;
            }
          } else {
            // Sends chat messages.
            SendSay(input);
          }
        } else if (stdin_buffer_pointer != stdin_buffer + SAY_MAX) {
          // Increments pointer and adds char c.
          *stdin_buffer_pointer++ = c;

          std::cout << c << std::flush;

          // Copies pointer into output.
          output = stdin_buffer_pointer;
          // Increments and sets NULL char.
          *output++ = '\0';
          // Copies stdin_buffer into part of output before NULL char.
          output = stdin_buffer;
        }
      } else if (FD_ISSET(client_socket, &read_set)) {
        // Socket has data.
        ssize_t read_size = read(client_socket, receive_buffer, kBufferSize);

        if (read_size != 0) {
          struct text message;
          memcpy(&message, receive_buffer, sizeof(struct text));
          text_t text_type = message.txt_type;

          switch (text_type) {
            case TXT_SAY:
              HandleTextSay(receive_buffer, output);
              break;
            case TXT_LIST:
              HandleTextList(receive_buffer, output);
              break;
            default:
              break;
          }
        }

        memset(&receive_buffer, 0, SAY_MAX);
      } // end of if client_socket

    } // end of if result

  } // end of while

  return 0;
}<|endoftext|>