<commit_before>/*************************************************************************
*    UrBackup - Client/Server backup system
*    Copyright (C) 2011-2016 Martin Raiber
*
*    This program is free software: you can redistribute it and/or modify
*    it under the terms of the GNU Affero General Public License as published by
*    the Free Software Foundation, either version 3 of the License, or
*    (at your option) any later version.
*
*    This program is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*    GNU Affero General Public License for more details.
*
*    You should have received a copy of the GNU Affero General Public License
*    along with this program.  If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/

#define _FILE_OFFSET_BITS 64
#define _LARGEFILE_SOURCE
#define _LARGEFILE64_SOURCE
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif

#include "Server.h"
#include "file.h"
#include "types.h"
#include "stringtools.h"

#ifdef MODE_LIN
#include "config.h"
#include <errno.h>
#include <stdint.h>
#include <sys/types.h>
#include <unistd.h>

#include <fcntl.h>
#include <sys/ioctl.h>

#ifndef FALLOC_FL_KEEP_SIZE
#define FALLOC_FL_KEEP_SIZE    0x1
#endif
#ifndef FALLOC_FL_PUNCH_HOLE
#define FALLOC_FL_PUNCH_HOLE   0x2
#endif

#ifndef SEEK_DATA
#define SEEK_DATA 3
#endif
#ifndef SEEK_HOLE
#define SEEK_HOLE 4
#endif

#if defined(__FreeBSD__) || defined(__APPLE__)
#define open64 open
#define off64_t off_t
#define lseek64 lseek
#define O_LARGEFILE 0
#define stat64 stat
#define fstat64 fstat
#define ftruncate64 ftruncate
#define fallocate64 fallocate
#define pwrite64 pwrite
#define pread64 pread
#else
#include <linux/fs.h>

#if !defined(BLKGETSIZE64) && defined(__i386__) && defined(__x86_64__)
#define BLKGETSIZE64 _IOR(0x12,114,size_t)
#endif

#endif

File::File()
	: fd(-1), last_hole_end(0), last_sparse_pos(0)
{

}

bool File::Open(std::string pfn, int mode)
{
	if (mode == MODE_RW_RESTORE)
	{
		mode = MODE_RW;
	}
	if (mode == MODE_RW_CREATE_RESTORE)
	{
		mode = MODE_RW_CREATE;
	}
	if (mode == MODE_RW_CREATE_DEVICE)
	{
		mode = MODE_RW_CREATE;
	}
	if (mode == MODE_READ_DEVICE_OVERLAPPED)
	{
		mode = MODE_READ_DEVICE;
	}

	fn=pfn;
	int flags=0;
	mode_t imode=S_IRWXU|S_IRWXG;
	if( mode==MODE_READ
		|| mode==MODE_READ_DEVICE
		|| mode==MODE_READ_SEQUENTIAL
		|| mode==MODE_READ_SEQUENTIAL_BACKUP)
	{
		flags=O_RDONLY;
	}
	else if( mode==MODE_WRITE )
	{
		DeleteFileInt(pfn);
		flags=O_WRONLY|O_CREAT;
	}
	else if( mode==MODE_APPEND )
	{
		flags=O_RDWR | O_APPEND;
	}
	else if( mode==MODE_RW
		|| mode==MODE_RW_SEQUENTIAL
		|| mode==MODE_RW_CREATE
		|| mode==MODE_RW_READNONE
		|| mode==MODE_RW_DEVICE
		|| mode==MODE_RW_DIRECT
		|| mode==MODE_RW_CREATE_DIRECT)
	{
		flags=O_RDWR;
		if( mode==MODE_RW_CREATE
			|| mode==MODE_RW_CREATE_DIRECT )
		{
			flags|=O_CREAT;
		}
	}

	if( mode==MODE_RW_CREATE_DIRECT
		|| mode==MODE_RW_DIRECT )
	{
		flags|=O_DIRECT;
	}

	struct stat buf;
	if(stat((fn).c_str(), &buf)==0)
	{
		if(S_ISDIR(buf.st_mode) )
			return false;
	}

#if defined(O_CLOEXEC)
	flags |= O_CLOEXEC;
#endif

	fd=open64((fn).c_str(), flags|O_LARGEFILE, imode);

#ifdef __linux__
	if(mode==MODE_READ_SEQUENTIAL
		|| mode==MODE_READ_SEQUENTIAL_BACKUP
		|| mode==MODE_RW_SEQUENTIAL)
	{
		posix_fadvise64(fd, 0, 0, POSIX_FADV_SEQUENTIAL);
	}

	if( mode==MODE_RW_READNONE )
	{
		posix_fadvise64(fd, 0, 0, POSIX_FADV_DONTNEED);
	}
#endif

	if( fd!=-1 )
	{
		return true;
	}
	else
		return false;
}

bool File::OpenTemporaryFile(const std::string &dir, bool first_try)
{
	char *tmpdir=getenv("TMPDIR");
	std::string stmpdir;
	if(tmpdir==NULL )
		stmpdir="/tmp";
	else
	    stmpdir=tmpdir;

	stmpdir=stmpdir+"/cps.XXXXXX";

	mode_t cur_umask = umask(S_IRWXO | S_IRWXG);
	fd=mkstemp((char*)stmpdir.c_str());
	umask(cur_umask);

	fn=(stmpdir);
	if( fd==-1 )
		return false;
	else
		return true;
}

bool File::Open(void *handle, const std::string& pFilename)
{
	fd=(int)((intptr_t)handle);
	fn = pFilename;
	return true;
}

std::string File::Read(_u32 tr, bool *has_error)
{
	std::string ret;
	ret.resize(tr);
	_u32 gc=Read((char*)ret.c_str(), tr, has_error);
	if( gc<tr )
		ret.resize( gc );

	return ret;
}

std::string File::Read(int64 spos, _u32 tr, bool *has_error)
{
	std::string ret;
	ret.resize(tr);
	_u32 gc=Read(spos, (char*)ret.c_str(), tr, has_error);
	if( gc<tr )
		ret.resize( gc );

	return ret;
}

_u32 File::Read(char* buffer, _u32 bsize, bool *has_error)
{
	ssize_t r=read(fd, buffer, bsize);
	if( r<0 )
	{
		if(has_error) *has_error=true;
		r=0;
	}

	return (_u32)r;
}

_u32 File::Read(int64 spos, char* buffer, _u32 bsize, bool *has_error)
{
	ssize_t r=pread64(fd, buffer, bsize, spos);
	if (r < 0)
	{
		if (has_error) *has_error = true;
		r = 0;
	}

	return (_u32)r;
}

_u32 File::Write(const std::string &tw, bool *has_error)
{
	return Write( tw.c_str(), (_u32)tw.size(), has_error);
}

_u32 File::Write(int64 spos, const std::string &tw, bool *has_error)
{
	return Write(spos, tw.c_str(), (_u32)tw.size(), has_error);
}

_u32 File::Write(const char* buffer, _u32 bsize, bool *has_error)
{
	ssize_t w=write(fd, buffer, bsize);
	if( w<0 )
	{
		Server->Log("Write failed. errno="+convert(errno), LL_DEBUG);
		if (has_error) *has_error = true;
		w=0;
	}
	return (_u32)w;
}

_u32 File::Write(int64 spos, const char* buffer, _u32 bsize, bool *has_error)
{
	ssize_t w=pwrite64(fd, buffer, bsize, spos);
	if( w<0 )
	{
		Server->Log("Write failed. errno="+convert(errno), LL_DEBUG);
		if(has_error) *has_error=true;
		w=0;
	}
	return (_u32)w;
}

bool File::Seek(_i64 spos)
{
	off64_t ot=lseek64(fd, spos, SEEK_SET);
	if( ot==(off64_t)-1 )
	{
		return false;
	}
	else
	{
		return true;
	}
}

_i64 File::Size(void)
{
	struct stat64 stat_buf;
	int rc = fstat64(fd, &stat_buf);

	if(rc==0)
	{
#if defined(BLKGETSIZE64)
		if(S_ISBLK(stat_buf.st_mode))
		{
			_i64 ret;
			rc = ioctl(fd, BLKGETSIZE64, &ret);
			if(rc==0)
			{
				return ret;
			}
		}
#endif

		return stat_buf.st_size;
	}
	else
	{
		return -1;
	}
}

_i64 File::RealSize(void)
{
	struct stat64 stat_buf;
	fstat64(fd, &stat_buf);

	return stat_buf.st_blocks*512;
}

void File::Close()
{
	if( fd!=-1 )
	{
		close( fd );
		fd=-1;
	}
}

bool File::PunchHole(_i64 spos, _i64 size)
{
#ifdef __APPLE__
	return false;
#elif __FreeBSD__
	/* Does not exist yet...
	struct flock64 s;
	s.l_whence = SEEK_SET;
	s.l_start = spos;
	s.l_len = size;
	int rc = fcntl(fd, F_FREESP64, &s);
	return rc == 0;*/
	return false;
#elif defined(HAVE_FALLOCATE64)
	int rc = fallocate64(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, spos, size);

	return rc == 0;
#else
	return false;
#endif
}

bool File::Sync()
{
	return fsync(fd)==0;
}

bool File::Resize(int64 new_size, bool set_sparse)
{
	return ftruncate64(fd, new_size) == 0;
}

void File::resetSparseExtentIter()
{
	last_hole_end = 0;
}

namespace
{
	class ResetCur
	{
	public:
		ResetCur(int fd, off64_t pos)
			: fd(fd), pos(pos)
		{}

		~ResetCur()
		{
			lseek64(fd, pos, SEEK_SET);
		}

	private:
		int fd;
		off64_t pos;
	};
}

IFsFile::SSparseExtent File::nextSparseExtent()
{
	if (last_sparse_pos == -1)
	{
		return SSparseExtent();
	}

	off64_t curr_pos = lseek64(fd, 0, SEEK_CUR);

	if (curr_pos == -1)
	{
		return SSparseExtent();
	}

	ResetCur reset_cur(fd, curr_pos);

	off64_t next_hole_start = lseek64(fd, last_sparse_pos, SEEK_HOLE);

	if (next_hole_start == -1)
	{
		last_sparse_pos = -1;
		return SSparseExtent();
	}

	_i64 fsize = Size();

	if (next_hole_start == fsize)
	{
		last_sparse_pos = -1;
		return SSparseExtent();
	}

	last_sparse_pos = lseek64(fd, next_hole_start, SEEK_DATA);

	if (last_sparse_pos == -1)
	{
		return SSparseExtent(next_hole_start, fsize - next_hole_start);
	}

	return SSparseExtent(next_hole_start, last_sparse_pos - next_hole_start);
}

std::vector<IFsFile::SFileExtent> File::getFileExtents(int64 starting_offset, int64 block_size, bool& more_data)
{
	//TODO: Implement using FIEMAP?
	return std::vector<SFileExtent>();
}

void* File::getOsHandle()
{
	return reinterpret_cast<void*>(fd);
}
#endif
<commit_msg>Fix build issue<commit_after>/*************************************************************************
*    UrBackup - Client/Server backup system
*    Copyright (C) 2011-2016 Martin Raiber
*
*    This program is free software: you can redistribute it and/or modify
*    it under the terms of the GNU Affero General Public License as published by
*    the Free Software Foundation, either version 3 of the License, or
*    (at your option) any later version.
*
*    This program is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*    GNU Affero General Public License for more details.
*
*    You should have received a copy of the GNU Affero General Public License
*    along with this program.  If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/

#define _FILE_OFFSET_BITS 64
#define _LARGEFILE_SOURCE
#define _LARGEFILE64_SOURCE
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif

#include "Server.h"
#include "file.h"
#include "types.h"
#include "stringtools.h"

#ifdef MODE_LIN
#include "config.h"
#include <errno.h>
#include <stdint.h>
#include <sys/types.h>
#include <unistd.h>

#include <fcntl.h>
#include <sys/ioctl.h>

#ifndef FALLOC_FL_KEEP_SIZE
#define FALLOC_FL_KEEP_SIZE    0x1
#endif
#ifndef FALLOC_FL_PUNCH_HOLE
#define FALLOC_FL_PUNCH_HOLE   0x2
#endif

#ifndef SEEK_DATA
#define SEEK_DATA 3
#endif
#ifndef SEEK_HOLE
#define SEEK_HOLE 4
#endif

#if defined(__FreeBSD__) || defined(__APPLE__)
#define open64 open
#define off64_t off_t
#define lseek64 lseek
#define O_LARGEFILE 0
#define stat64 stat
#define fstat64 fstat
#define ftruncate64 ftruncate
#define fallocate64 fallocate
#define pwrite64 pwrite
#define pread64 pread
#else
#include <linux/fs.h>

#if !defined(BLKGETSIZE64) && defined(__i386__) && defined(__x86_64__)
#define BLKGETSIZE64 _IOR(0x12,114,size_t)
#endif

#endif

File::File()
	: fd(-1), last_hole_end(0), last_sparse_pos(0)
{

}

bool File::Open(std::string pfn, int mode)
{
	if (mode == MODE_RW_RESTORE)
	{
		mode = MODE_RW;
	}
	if (mode == MODE_RW_CREATE_RESTORE)
	{
		mode = MODE_RW_CREATE;
	}
	if (mode == MODE_RW_CREATE_DEVICE)
	{
		mode = MODE_RW_CREATE;
	}
	if (mode == MODE_READ_DEVICE_OVERLAPPED)
	{
		mode = MODE_READ_DEVICE;
	}

	fn=pfn;
	int flags=0;
	mode_t imode=S_IRWXU|S_IRWXG;
	if( mode==MODE_READ
		|| mode==MODE_READ_DEVICE
		|| mode==MODE_READ_SEQUENTIAL
		|| mode==MODE_READ_SEQUENTIAL_BACKUP)
	{
		flags=O_RDONLY;
	}
	else if( mode==MODE_WRITE )
	{
		DeleteFileInt(pfn);
		flags=O_WRONLY|O_CREAT;
	}
	else if( mode==MODE_APPEND )
	{
		flags=O_RDWR | O_APPEND;
	}
	else if( mode==MODE_RW
		|| mode==MODE_RW_SEQUENTIAL
		|| mode==MODE_RW_CREATE
		|| mode==MODE_RW_READNONE
		|| mode==MODE_RW_DEVICE
		|| mode==MODE_RW_DIRECT
		|| mode==MODE_RW_CREATE_DIRECT)
	{
		flags=O_RDWR;
		if( mode==MODE_RW_CREATE
			|| mode==MODE_RW_CREATE_DIRECT )
		{
			flags|=O_CREAT;
		}
	}

#ifdef __linux__
	if( mode==MODE_RW_CREATE_DIRECT
		|| mode==MODE_RW_DIRECT )
	{
		flags|=O_DIRECT;
	}
#endif

	struct stat buf;
	if(stat((fn).c_str(), &buf)==0)
	{
		if(S_ISDIR(buf.st_mode) )
			return false;
	}

#if defined(O_CLOEXEC)
	flags |= O_CLOEXEC;
#endif

	fd=open64((fn).c_str(), flags|O_LARGEFILE, imode);

#ifdef __linux__
	if(mode==MODE_READ_SEQUENTIAL
		|| mode==MODE_READ_SEQUENTIAL_BACKUP
		|| mode==MODE_RW_SEQUENTIAL)
	{
		posix_fadvise64(fd, 0, 0, POSIX_FADV_SEQUENTIAL);
	}

	if( mode==MODE_RW_READNONE )
	{
		posix_fadvise64(fd, 0, 0, POSIX_FADV_DONTNEED);
	}
#endif

	if( fd!=-1 )
	{
		return true;
	}
	else
		return false;
}

bool File::OpenTemporaryFile(const std::string &dir, bool first_try)
{
	char *tmpdir=getenv("TMPDIR");
	std::string stmpdir;
	if(tmpdir==NULL )
		stmpdir="/tmp";
	else
	    stmpdir=tmpdir;

	stmpdir=stmpdir+"/cps.XXXXXX";

	mode_t cur_umask = umask(S_IRWXO | S_IRWXG);
	fd=mkstemp((char*)stmpdir.c_str());
	umask(cur_umask);

	fn=(stmpdir);
	if( fd==-1 )
		return false;
	else
		return true;
}

bool File::Open(void *handle, const std::string& pFilename)
{
	fd=(int)((intptr_t)handle);
	fn = pFilename;
	return true;
}

std::string File::Read(_u32 tr, bool *has_error)
{
	std::string ret;
	ret.resize(tr);
	_u32 gc=Read((char*)ret.c_str(), tr, has_error);
	if( gc<tr )
		ret.resize( gc );

	return ret;
}

std::string File::Read(int64 spos, _u32 tr, bool *has_error)
{
	std::string ret;
	ret.resize(tr);
	_u32 gc=Read(spos, (char*)ret.c_str(), tr, has_error);
	if( gc<tr )
		ret.resize( gc );

	return ret;
}

_u32 File::Read(char* buffer, _u32 bsize, bool *has_error)
{
	ssize_t r=read(fd, buffer, bsize);
	if( r<0 )
	{
		if(has_error) *has_error=true;
		r=0;
	}

	return (_u32)r;
}

_u32 File::Read(int64 spos, char* buffer, _u32 bsize, bool *has_error)
{
	ssize_t r=pread64(fd, buffer, bsize, spos);
	if (r < 0)
	{
		if (has_error) *has_error = true;
		r = 0;
	}

	return (_u32)r;
}

_u32 File::Write(const std::string &tw, bool *has_error)
{
	return Write( tw.c_str(), (_u32)tw.size(), has_error);
}

_u32 File::Write(int64 spos, const std::string &tw, bool *has_error)
{
	return Write(spos, tw.c_str(), (_u32)tw.size(), has_error);
}

_u32 File::Write(const char* buffer, _u32 bsize, bool *has_error)
{
	ssize_t w=write(fd, buffer, bsize);
	if( w<0 )
	{
		Server->Log("Write failed. errno="+convert(errno), LL_DEBUG);
		if (has_error) *has_error = true;
		w=0;
	}
	return (_u32)w;
}

_u32 File::Write(int64 spos, const char* buffer, _u32 bsize, bool *has_error)
{
	ssize_t w=pwrite64(fd, buffer, bsize, spos);
	if( w<0 )
	{
		Server->Log("Write failed. errno="+convert(errno), LL_DEBUG);
		if(has_error) *has_error=true;
		w=0;
	}
	return (_u32)w;
}

bool File::Seek(_i64 spos)
{
	off64_t ot=lseek64(fd, spos, SEEK_SET);
	if( ot==(off64_t)-1 )
	{
		return false;
	}
	else
	{
		return true;
	}
}

_i64 File::Size(void)
{
	struct stat64 stat_buf;
	int rc = fstat64(fd, &stat_buf);

	if(rc==0)
	{
#if defined(BLKGETSIZE64)
		if(S_ISBLK(stat_buf.st_mode))
		{
			_i64 ret;
			rc = ioctl(fd, BLKGETSIZE64, &ret);
			if(rc==0)
			{
				return ret;
			}
		}
#endif

		return stat_buf.st_size;
	}
	else
	{
		return -1;
	}
}

_i64 File::RealSize(void)
{
	struct stat64 stat_buf;
	fstat64(fd, &stat_buf);

	return stat_buf.st_blocks*512;
}

void File::Close()
{
	if( fd!=-1 )
	{
		close( fd );
		fd=-1;
	}
}

bool File::PunchHole(_i64 spos, _i64 size)
{
#ifdef __APPLE__
	return false;
#elif __FreeBSD__
	/* Does not exist yet...
	struct flock64 s;
	s.l_whence = SEEK_SET;
	s.l_start = spos;
	s.l_len = size;
	int rc = fcntl(fd, F_FREESP64, &s);
	return rc == 0;*/
	return false;
#elif defined(HAVE_FALLOCATE64)
	int rc = fallocate64(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, spos, size);

	return rc == 0;
#else
	return false;
#endif
}

bool File::Sync()
{
	return fsync(fd)==0;
}

bool File::Resize(int64 new_size, bool set_sparse)
{
	return ftruncate64(fd, new_size) == 0;
}

void File::resetSparseExtentIter()
{
	last_hole_end = 0;
}

namespace
{
	class ResetCur
	{
	public:
		ResetCur(int fd, off64_t pos)
			: fd(fd), pos(pos)
		{}

		~ResetCur()
		{
			lseek64(fd, pos, SEEK_SET);
		}

	private:
		int fd;
		off64_t pos;
	};
}

IFsFile::SSparseExtent File::nextSparseExtent()
{
	if (last_sparse_pos == -1)
	{
		return SSparseExtent();
	}

	off64_t curr_pos = lseek64(fd, 0, SEEK_CUR);

	if (curr_pos == -1)
	{
		return SSparseExtent();
	}

	ResetCur reset_cur(fd, curr_pos);

	off64_t next_hole_start = lseek64(fd, last_sparse_pos, SEEK_HOLE);

	if (next_hole_start == -1)
	{
		last_sparse_pos = -1;
		return SSparseExtent();
	}

	_i64 fsize = Size();

	if (next_hole_start == fsize)
	{
		last_sparse_pos = -1;
		return SSparseExtent();
	}

	last_sparse_pos = lseek64(fd, next_hole_start, SEEK_DATA);

	if (last_sparse_pos == -1)
	{
		return SSparseExtent(next_hole_start, fsize - next_hole_start);
	}

	return SSparseExtent(next_hole_start, last_sparse_pos - next_hole_start);
}

std::vector<IFsFile::SFileExtent> File::getFileExtents(int64 starting_offset, int64 block_size, bool& more_data)
{
	//TODO: Implement using FIEMAP?
	return std::vector<SFileExtent>();
}

void* File::getOsHandle()
{
	return reinterpret_cast<void*>(fd);
}
#endif
<|endoftext|>


<commit_before>/*************************************************************************
*    UrBackup - Client/Server backup system
*    Copyright (C) 2011  Martin Raiber
*
*    This program is free software: you can redistribute it and/or modify
*    it under the terms of the GNU General Public License as published by
*    the Free Software Foundation, either version 3 of the License, or
*    (at your option) any later version.
*
*    This program is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*    GNU General Public License for more details.
*
*    You should have received a copy of the GNU General Public License
*    along with this program.  If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/

#define _FILE_OFFSET_BITS 64
#define _LARGEFILE_SOURCE
#define _LARGEFILE64_SOURCE

#if defined(__FreeBSD__)
#define open64 open
#define off64_t off_t
#define lseek64 lseek
#define O_LARGEFILE 0
#define stat64 stat
#define fstat64 fstat
#endif

#include "Server.h"
#include "file.h"
#include "types.h"
#include "stringtools.h"

#ifdef MODE_LIN

#include <errno.h>
#include <stdint.h>

#include <sys/fcntl.h>

File::File()
	: fd(-1)
{

}

bool File::Open(std::wstring pfn, int mode)
{
	fn=pfn;
	int flags=0;
	mode_t imode=S_IRWXU|S_IRWXG;
	if( mode==MODE_READ
		|| mode==MODE_READ_DEVICE
		|| mode==MODE_READ_SEQUENTIAL
		|| mode==MODE_READ_SEQUENTIAL_BACKUP)
	{
		flags=O_RDONLY;
	}
	else if( mode==MODE_WRITE )
	{
		DeleteFileInt(pfn);
		flags=O_WRONLY|O_CREAT;
	}
	else if( mode==MODE_APPEND )
	{
		flags=O_RDWR | O_APPEND;
	}
	else if( mode==MODE_RW
		|| mode==MODE_RW_SEQUENTIAL
		|| mode==MODE_RW_CREATE
		|| mode==MODE_RW_READNONE )
	{
		flags=O_RDWR;
		if( mode==MODE_RW_CREATE )
		{
			flags|=O_CREAT;
		}
	}

	struct stat buf;
	if(stat(Server->ConvertToUTF8(fn).c_str(), &buf)==0)
	{
		if(S_ISDIR(buf.st_mode) )
			return false;
	}

	fd=open64(Server->ConvertToUTF8(fn).c_str(), flags|O_LARGEFILE, imode);

	if(mode==MODE_READ_SEQUENTIAL
		|| mode==MODE_READ_SEQUENTIAL_BACKUP
		|| mode==MODE_RW_SEQUENTIAL)
	{
		posix_fadvise64(fd, 0, 0, POSIX_FADV_SEQUENTIAL);
	}

	if( mode==MODE_RW_READNONE )
	{
		posix_fadvise64(fd, 0, 0, POSIX_FADV_DONTNEED);
	}

	if( fd!=-1 )
	{
		return true;
	}
	else
		return false;
}

bool File::OpenTemporaryFile(const std::wstring &dir)
{
	char *tmpdir=getenv("TMPDIR");
	std::string stmpdir;
	if(tmpdir==NULL )
		stmpdir="/tmp";
	else
	    stmpdir=tmpdir;

	stmpdir=stmpdir+"/cps.XXXXXX";

	mode_t cur_umask = umask(S_IRWXO | S_IRWXG);
	fd=mkstemp((char*)stmpdir.c_str());
	umask(cur_umask);

	fn=Server->ConvertToUnicode(stmpdir);
	if( fd==-1 )
		return false;
	else
		return true;
}

bool File::Open(void *handle)
{
	fd=(int)((intptr_t)handle);
	return true;
}

std::string File::Read(_u32 tr)
{
	std::string ret;
	ret.resize(tr);
	_u32 gc=Read((char*)ret.c_str(), tr);
	if( gc<tr )
		ret.resize( gc );

	return ret;
}

_u32 File::Read(char* buffer, _u32 bsize)
{
	ssize_t r=read(fd, buffer, bsize);
	if( r<0 )
		r=0;

	return (_u32)r;
}

_u32 File::Write(const std::string &tw)
{
	return Write( tw.c_str(), (_u32)tw.size() );
}

_u32 File::Write(const char* buffer, _u32 bsize)
{
	ssize_t w=write(fd, buffer, bsize);
	if( w<0 )
	{
		Server->Log("Write failed. errno="+nconvert(errno), LL_DEBUG);
		w=0;
	}
	return (_u32)w;
}

bool File::Seek(_i64 spos)
{
	off64_t ot=lseek64(fd, spos, SEEK_SET);
	if( ot==(off64_t)-1 )
	{
		return false;
	}
	else
	{
		return true;
	}
}

_i64 File::Size(void)
{
	struct stat64 stat_buf;
	fstat64(fd, &stat_buf);

	return stat_buf.st_size;
}

void File::Close()
{
	if( fd!=-1 )
	{
		close( fd );
		fd=-1;
	}
}

#endif
<commit_msg>Build fix for kFreeBSD<commit_after>/*************************************************************************
*    UrBackup - Client/Server backup system
*    Copyright (C) 2011  Martin Raiber
*
*    This program is free software: you can redistribute it and/or modify
*    it under the terms of the GNU General Public License as published by
*    the Free Software Foundation, either version 3 of the License, or
*    (at your option) any later version.
*
*    This program is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*    GNU General Public License for more details.
*
*    You should have received a copy of the GNU General Public License
*    along with this program.  If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/

#define _FILE_OFFSET_BITS 64
#define _LARGEFILE_SOURCE
#define _LARGEFILE64_SOURCE

#if defined(__FreeBSD__)
#define open64 open
#define off64_t off_t
#define lseek64 lseek
#define O_LARGEFILE 0
#define stat64 stat
#define fstat64 fstat
#endif

#include "Server.h"
#include "file.h"
#include "types.h"
#include "stringtools.h"

#ifdef MODE_LIN

#include <errno.h>
#include <stdint.h>

#include <sys/fcntl.h>

File::File()
	: fd(-1)
{

}

bool File::Open(std::wstring pfn, int mode)
{
	fn=pfn;
	int flags=0;
	mode_t imode=S_IRWXU|S_IRWXG;
	if( mode==MODE_READ
		|| mode==MODE_READ_DEVICE
		|| mode==MODE_READ_SEQUENTIAL
		|| mode==MODE_READ_SEQUENTIAL_BACKUP)
	{
		flags=O_RDONLY;
	}
	else if( mode==MODE_WRITE )
	{
		DeleteFileInt(pfn);
		flags=O_WRONLY|O_CREAT;
	}
	else if( mode==MODE_APPEND )
	{
		flags=O_RDWR | O_APPEND;
	}
	else if( mode==MODE_RW
		|| mode==MODE_RW_SEQUENTIAL
		|| mode==MODE_RW_CREATE
		|| mode==MODE_RW_READNONE )
	{
		flags=O_RDWR;
		if( mode==MODE_RW_CREATE )
		{
			flags|=O_CREAT;
		}
	}

	struct stat buf;
	if(stat(Server->ConvertToUTF8(fn).c_str(), &buf)==0)
	{
		if(S_ISDIR(buf.st_mode) )
			return false;
	}

	fd=open64(Server->ConvertToUTF8(fn).c_str(), flags|O_LARGEFILE, imode);

#ifdef __linux__
	if(mode==MODE_READ_SEQUENTIAL
		|| mode==MODE_READ_SEQUENTIAL_BACKUP
		|| mode==MODE_RW_SEQUENTIAL)
	{
		posix_fadvise64(fd, 0, 0, POSIX_FADV_SEQUENTIAL);
	}

	if( mode==MODE_RW_READNONE )
	{
		posix_fadvise64(fd, 0, 0, POSIX_FADV_DONTNEED);
	}
#endif

	if( fd!=-1 )
	{
		return true;
	}
	else
		return false;
}

bool File::OpenTemporaryFile(const std::wstring &dir)
{
	char *tmpdir=getenv("TMPDIR");
	std::string stmpdir;
	if(tmpdir==NULL )
		stmpdir="/tmp";
	else
	    stmpdir=tmpdir;

	stmpdir=stmpdir+"/cps.XXXXXX";

	mode_t cur_umask = umask(S_IRWXO | S_IRWXG);
	fd=mkstemp((char*)stmpdir.c_str());
	umask(cur_umask);

	fn=Server->ConvertToUnicode(stmpdir);
	if( fd==-1 )
		return false;
	else
		return true;
}

bool File::Open(void *handle)
{
	fd=(int)((intptr_t)handle);
	return true;
}

std::string File::Read(_u32 tr)
{
	std::string ret;
	ret.resize(tr);
	_u32 gc=Read((char*)ret.c_str(), tr);
	if( gc<tr )
		ret.resize( gc );

	return ret;
}

_u32 File::Read(char* buffer, _u32 bsize)
{
	ssize_t r=read(fd, buffer, bsize);
	if( r<0 )
		r=0;

	return (_u32)r;
}

_u32 File::Write(const std::string &tw)
{
	return Write( tw.c_str(), (_u32)tw.size() );
}

_u32 File::Write(const char* buffer, _u32 bsize)
{
	ssize_t w=write(fd, buffer, bsize);
	if( w<0 )
	{
		Server->Log("Write failed. errno="+nconvert(errno), LL_DEBUG);
		w=0;
	}
	return (_u32)w;
}

bool File::Seek(_i64 spos)
{
	off64_t ot=lseek64(fd, spos, SEEK_SET);
	if( ot==(off64_t)-1 )
	{
		return false;
	}
	else
	{
		return true;
	}
}

_i64 File::Size(void)
{
	struct stat64 stat_buf;
	fstat64(fd, &stat_buf);

	return stat_buf.st_size;
}

void File::Close()
{
	if( fd!=-1 )
	{
		close( fd );
		fd=-1;
	}
}

#endif
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2017 ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla 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 Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#include <unordered_map>
#include <vector>
#include <seastar/core/shared_future.hh>
#include <seastar/core/future.hh>

namespace sstables {

using index_list = std::vector<index_entry>;

// Associative cache of summary index -> index_list
// Entries stay around as long as there is any live external reference (list_ptr) to them.
// Supports asynchronous insertion, ensures that only one entry will be loaded.
class shared_index_lists {
public:
    using key_type = uint64_t;
    struct stats {
        uint64_t hits = 0; // Number of times entry was found ready
        uint64_t misses = 0; // Number of times entry was not found
        uint64_t blocks = 0; // Number of times entry was not ready (>= misses)
    };
private:
    class entry : public enable_lw_shared_from_this<entry> {
    public:
        key_type key;
        index_list list;
        shared_promise<> loaded;
        shared_index_lists& parent;

        entry(shared_index_lists& parent, key_type key)
            : key(key), parent(parent)
        { }
        ~entry() {
            parent._lists.erase(key);
        }
        bool operator==(const entry& e) const { return key == e.key; }
        bool operator!=(const entry& e) const { return key != e.key; }
    };
    std::unordered_map<key_type, entry*> _lists;
    static thread_local stats _shard_stats;
public:
    // Pointer to index_list
    class list_ptr {
        lw_shared_ptr<entry> _e;
    public:
        using element_type = index_list;
        list_ptr() = default;
        explicit list_ptr(lw_shared_ptr<entry> e) : _e(std::move(e)) {}
        explicit operator bool() const { return static_cast<bool>(_e); }
        index_list& operator*() { return _e->list; }
        const index_list& operator*() const { return _e->list; }
        index_list* operator->() { return &_e->list; }
        const index_list* operator->() const { return &_e->list; }

        index_list release() {
            auto res = _e.owned() ? index_list(std::move(_e->list)) : index_list(_e->list);
            _e = {};
            return std::move(res);
        }
    };

    shared_index_lists() = default;
    shared_index_lists(shared_index_lists&&) = delete;
    shared_index_lists(const shared_index_lists&) = delete;

    // Returns a future which resolves with a shared pointer to index_list for given key.
    // Always returns a valid pointer if succeeds. The pointer is never invalidated externally.
    //
    // If entry is missing, the loader is invoked. If list is already loading, this invocation
    // will wait for prior loading to complete and use its result when it's done.
    //
    // The loader object does not survive deferring, so the caller must deal with its liveness.
    template<typename Loader>
    future<list_ptr> get_or_load(key_type key, Loader&& loader) {
        auto i = _lists.find(key);
        lw_shared_ptr<entry> e;
        auto f = [&] {
            if (i != _lists.end()) {
                e = i->second->shared_from_this();
                return e->loaded.get_shared_future();
            } else {
                ++_shard_stats.misses;
                e = make_lw_shared<entry>(*this, key);
                auto f = e->loaded.get_shared_future();
                auto res = _lists.emplace(key, e.get());
                assert(res.second);
                futurize_apply(loader, key).then_wrapped([e](future<index_list>&& f) mutable {
                    if (f.failed()) {
                        e->loaded.set_exception(f.get_exception());
                    } else {
                        e->list = f.get0();
                        e->loaded.set_value();
                    }
                });
                return f;
            }
        }();
        if (!f.available()) {
            ++_shard_stats.blocks;
            return f.then([e]() mutable {
                return list_ptr(std::move(e));
            });
        } else if (f.failed()) {
            return make_exception_future<list_ptr>(std::move(f).get_exception());
        } else {
            ++_shard_stats.hits;
            return make_ready_future<list_ptr>(list_ptr(std::move(e)));
        }
    }

    static const stats& shard_stats() { return _shard_stats; }
};

}
<commit_msg>shared_index_lists.hh: add missing include<commit_after>/*
 * Copyright (C) 2017 ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla 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 Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#include "types.hh"
#include <unordered_map>
#include <vector>
#include <seastar/core/shared_future.hh>
#include <seastar/core/future.hh>

namespace sstables {

using index_list = std::vector<index_entry>;

// Associative cache of summary index -> index_list
// Entries stay around as long as there is any live external reference (list_ptr) to them.
// Supports asynchronous insertion, ensures that only one entry will be loaded.
class shared_index_lists {
public:
    using key_type = uint64_t;
    struct stats {
        uint64_t hits = 0; // Number of times entry was found ready
        uint64_t misses = 0; // Number of times entry was not found
        uint64_t blocks = 0; // Number of times entry was not ready (>= misses)
    };
private:
    class entry : public enable_lw_shared_from_this<entry> {
    public:
        key_type key;
        index_list list;
        shared_promise<> loaded;
        shared_index_lists& parent;

        entry(shared_index_lists& parent, key_type key)
            : key(key), parent(parent)
        { }
        ~entry() {
            parent._lists.erase(key);
        }
        bool operator==(const entry& e) const { return key == e.key; }
        bool operator!=(const entry& e) const { return key != e.key; }
    };
    std::unordered_map<key_type, entry*> _lists;
    static thread_local stats _shard_stats;
public:
    // Pointer to index_list
    class list_ptr {
        lw_shared_ptr<entry> _e;
    public:
        using element_type = index_list;
        list_ptr() = default;
        explicit list_ptr(lw_shared_ptr<entry> e) : _e(std::move(e)) {}
        explicit operator bool() const { return static_cast<bool>(_e); }
        index_list& operator*() { return _e->list; }
        const index_list& operator*() const { return _e->list; }
        index_list* operator->() { return &_e->list; }
        const index_list* operator->() const { return &_e->list; }

        index_list release() {
            auto res = _e.owned() ? index_list(std::move(_e->list)) : index_list(_e->list);
            _e = {};
            return std::move(res);
        }
    };

    shared_index_lists() = default;
    shared_index_lists(shared_index_lists&&) = delete;
    shared_index_lists(const shared_index_lists&) = delete;

    // Returns a future which resolves with a shared pointer to index_list for given key.
    // Always returns a valid pointer if succeeds. The pointer is never invalidated externally.
    //
    // If entry is missing, the loader is invoked. If list is already loading, this invocation
    // will wait for prior loading to complete and use its result when it's done.
    //
    // The loader object does not survive deferring, so the caller must deal with its liveness.
    template<typename Loader>
    future<list_ptr> get_or_load(key_type key, Loader&& loader) {
        auto i = _lists.find(key);
        lw_shared_ptr<entry> e;
        auto f = [&] {
            if (i != _lists.end()) {
                e = i->second->shared_from_this();
                return e->loaded.get_shared_future();
            } else {
                ++_shard_stats.misses;
                e = make_lw_shared<entry>(*this, key);
                auto f = e->loaded.get_shared_future();
                auto res = _lists.emplace(key, e.get());
                assert(res.second);
                futurize_apply(loader, key).then_wrapped([e](future<index_list>&& f) mutable {
                    if (f.failed()) {
                        e->loaded.set_exception(f.get_exception());
                    } else {
                        e->list = f.get0();
                        e->loaded.set_value();
                    }
                });
                return f;
            }
        }();
        if (!f.available()) {
            ++_shard_stats.blocks;
            return f.then([e]() mutable {
                return list_ptr(std::move(e));
            });
        } else if (f.failed()) {
            return make_exception_future<list_ptr>(std::move(f).get_exception());
        } else {
            ++_shard_stats.hits;
            return make_ready_future<list_ptr>(list_ptr(std::move(e)));
        }
    }

    static const stats& shard_stats() { return _shard_stats; }
};

}
<|endoftext|>


<commit_before>// This file is part of the dune-stuff project:
//   https://github.com/wwu-numerik/dune-stuff
// Copyright holders: Rene Milk, Felix Schindler
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)
//
// Contributors: Sven Kaulmann

#ifndef DUNE_STUFF_COMMON_MATRIX_HH
#define DUNE_STUFF_COMMON_MATRIX_HH

// dune-common
#include <dune/stuff/common/disable_warnings.hh>
# include <dune/common/densematrix.hh>
#include <dune/stuff/common/reenable_warnings.hh>

#include <dune/stuff/common/debug.hh>
#include <dune/stuff/common/math.hh>

#if HAVE_DUNE_ISTL && HAVE_DUNE_FEM
  // for dune-istl
# if defined(HAVE_BOOST)
#   undef HAVE_BOOST
#   define HAVE_BOOST 1
# endif
# include <dune/stuff/common/disable_warnings.hh>
#   include <dune/fem/operator/matrix/spmatrix.hh>
#   include <dune/istl/operators.hh>
#   include <dune/fem/operator/matrix/istlmatrix.hh>
#   include <dune/fem/operator/matrix/preconditionerwrapper.hh>
# include <dune/stuff/common/reenable_warnings.hh>
#endif // if HAVE_DUNE_ISTL && HAVE_DUNE_FEM

namespace Dune {
namespace Stuff {
namespace Common {

/** \brief get the diagonal of a fieldMatrix into a fieldvector
   * \note While in principle this might do for SparseRowMatrix as well, don't do it! SparseRowMatrix has specialised
   *functions for this (putting the diagonal into DiscreteFunctions tho
   **/
template< class FieldMatrixType >
class MatrixDiagonal
  : public FieldVector< typename FieldMatrixType::field_type,
                        FieldMatrixType::rows >
{
public:
  MatrixDiagonal(const FieldMatrixType& matrix) {
    static_assert(FieldMatrixType::rows == FieldMatrixType::cols, "Matrix must be square!");
    // CompileTimeChecker< FieldMatrixType::rows == FieldMatrixType::cols > matrix_must_be_square;

    for (size_t i = 0; i < FieldMatrixType::rows; i++)
      (*this)[i] = matrix[i][i];
  }
}; // class MatrixDiagonal

//! returns Sum of matrix' diagonal entries
template< class FieldMatrixType >
typename FieldMatrixType::field_type matrixTrace(const FieldMatrixType& matrix) {
  MatrixDiagonal< FieldMatrixType > diag(matrix);
  typename FieldMatrixType::field_type trace = typename FieldMatrixType::field_type(0);
  for (size_t i = 0; i < FieldMatrixType::rows; i++)
    trace += diag[i];
  return trace;
} // typename FieldMatrixType::field_type matrixTrace(const FieldMatrixType& matrix)

//! produces a NxN Identity matrix compatible with parent type
template< class MatrixType >
class IdentityMatrix
  : public MatrixType
{
public:
  IdentityMatrix(size_t N)
    : MatrixType(N, N, 1) {
    for (size_t i = 1; i < N; ++i)
      MatrixType::set(i, i, 1.0);
  }

  const MatrixType& matrix() const { return *this; }
}; // class IdentityMatrix

//! produces a NxN Identity matrix object compatible with parent type
template< class MatrixObjectType >
class DUNE_DEPRECATED_MSG("deprecated dune-fem util, use stuff/la instead")
IdentityMatrixObject
  : public MatrixObjectType
{
public:
  IdentityMatrixObject(const typename MatrixObjectType::DomainSpaceType& domain_space,
                       const typename MatrixObjectType::RangeSpaceType& range_space)
    : MatrixObjectType(domain_space, range_space) {
    MatrixObjectType::reserve();
    for (int i = 0; i < MatrixObjectType::matrix().rows(); ++i)
      MatrixObjectType::matrix().set(i, i, 1.0);
  }
};

//! adds the missing setDiag function to SparseRowMatrix
template< class DiscFuncType, class MatrixType >
void setMatrixDiag(MatrixType& matrix, DiscFuncType& diag) {
  typedef typename DiscFuncType::DofIteratorType DofIteratorType;

  //! we assume that the dimension of the functionspace of f is the same as
  //! the size of the matrix
  DofIteratorType it = diag.dbegin();

  for (int row = 0; row < matrix.rows(); row++)
  {
    if (*it != 0.0)
      matrix.set(row, row, *it);
    ++it;
  }
  return;
} // setMatrixDiag

//! return false if
abs( a(row,col) - b(col,row) ) > tolerance
 for any col,row
template< class MatrixType >
bool areTransposed(const MatrixType& a, const MatrixType& b, const double tolerance = 1e-8) {
  if ( ( a.rows() != b.cols() ) || ( b.rows() != a.cols() ) )
    return false;

  for (int row = 0; row < a.rows(); ++row)
  {
    for (int col = 0; col  tolerance)
        return false;
    }
  }
  return true;
} // areTransposed

//! extern matrix addition that ignore 0 entries
template< class MatrixType >
void addMatrix(MatrixType& dest, const MatrixType& arg, const double eps = 1e-14) {
  for (int i = 0; i < arg.rows(); ++i)
    for (int j = 0; j < arg.cols(); ++j)
    {
      const double value = arg(i, j);
      if (std::fabs(value) > eps)
        dest.add(i, j, value);
    }

} // addMatrix

/** @brief Write sparse matrix to given output stream
   *
   *  @param[in]  matrix The matrix to be written
   *  @param[in] out    The outgoing stream
   */
template< class SparseMatrixImpl, class Output >
void writeSparseMatrix(const SparseMatrixImpl& matrix,
                       Output& out) {
  const unsigned int nRows = matrix.rows();
  const unsigned int nCols = matrix.cols();

  for (int i = 0; i != nRows; ++i)
  {
    for (int j = 0; j != nCols; ++j)
    {
      if ( matrix.find(i, j) )
      {
        out << i << "," << j << ",";
        out.precision(12);
        out.setf(std::ios::scientific);
        out << matrix(i, j) << std::endl;
      }
    }
  }
  return;
} // writeSparseMatrix

/** @brief Read sparse matrix from given inputstream
   *
   *  @param[out] matrix The matrix to be read
   *  @param[in]  in     The ingoing stream
   */
template< class SparseMatrixImpl, class Input >
void readSparseMatrix(SparseMatrixImpl& matrix,
                      Input& in) {
  matrix.clear();
  std::string row;
  while ( std::getline(in, row) )
  {
    size_t last_found = 0;
    size_t found = row.find_first_of(",");
    double temp;
    std::vector< double > entryLine;
    do {
      if (found == std::string::npos)
        found = row.size();
      std::string subs = row.substr(last_found, found - last_found);
      last_found = found + 1;
      std::istringstream in_str(subs);
      if (entryLine.size() == 2)
      {
        in_str.precision(12);
        in_str.setf(std::ios::scientific);
      } else {
        in_str.precision(10);
        in_str.setf(std::ios::fixed);
      }
      in_str >> temp;
      entryLine.push_back(temp);
      found = row.find_first_of(",", last_found);
    } while (last_found != row.size() + 1);
    assert(entryLine.size() == 3);
    matrix.add(entryLine[0], entryLine[1], entryLine[2]);
  }
} // readSparseMatrix

/**
   *  \brief  multiplies rows of arg2 with arg1
   *  \todo   doc
   **/
template< class FieldMatrixImp >
FieldMatrixImp rowWiseMatrixMultiplication(const FieldMatrixImp& arg1,
                                           const FieldMatrixImp& arg2) {
  typedef FieldMatrixImp
  FieldMatrixType;
  typedef typename FieldMatrixType::row_type
  RowType;
  typedef typename FieldMatrixType::ConstRowIterator
  ConstRowIteratorType;
  typedef typename FieldMatrixType::RowIterator
  RowIteratorType;

  assert( arg2.rowdim() == arg1.coldim() );

  FieldMatrixType ret(0.0);

  ConstRowIteratorType arg2RowItEnd = arg2.end();
  RowIteratorType retRowItEnd = ret.end();
  RowIteratorType retRowIt = ret.begin();
  for (ConstRowIteratorType arg2RowIt = arg2.begin();
       arg2RowIt != arg2RowItEnd, retRowIt != retRowItEnd;
       ++arg2RowIt, ++retRowIt)
  {
    RowType row(0.0);
    arg1.mv(*arg2RowIt, row);
    *retRowIt = row;
  }
  return ret;
} // rowWiseMatrixMultiplication

//! prints actual memusage of matrix in kB
template< class MatrixType >
void printMemUsage(const MatrixType& matrix, std::ostream& stream, std::string name = "") {
  long size = matrix.numberOfValues() * sizeof(typename MatrixType::Ttype) / 1024.f;

  stream << "matrix size " << name << "\t\t" << size << std::endl;
}

//! prints actual memusage of matrixobject in kB
template< class MatrixObjectType>
void printMemUsageObject(const MatrixObjectType& matrix_object, std::ostream& stream, std::string name = "") {
  printMemUsage(matrix_object.matrix(), stream, name);
}

template< class M >
void forceTranspose(const M& arg, M& dest) {
  assert( arg.cols() == dest.rows() );
  assert( dest.cols() == arg.rows() );
// dest.clear();
  for (int i = 0; i < arg.cols(); ++i)
    for (int j = 0; j < arg.rows(); ++j)
      dest.set( j, i, arg(i, j) );
} // forceTranspose

} // namespace Common
} // namespace Stuff
} // namespace Dune

#endif // DUNE_STUFF_COMMON_MATRIX_HH
<commit_msg>[common] remove deprecated IdentityMatrixObject<commit_after>// This file is part of the dune-stuff project:
//   https://github.com/wwu-numerik/dune-stuff
// Copyright holders: Rene Milk, Felix Schindler
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)
//
// Contributors: Sven Kaulmann

#ifndef DUNE_STUFF_COMMON_MATRIX_HH
#define DUNE_STUFF_COMMON_MATRIX_HH

// dune-common
#include <dune/stuff/common/disable_warnings.hh>
# include <dune/common/densematrix.hh>
#include <dune/stuff/common/reenable_warnings.hh>

#include <dune/stuff/common/debug.hh>
#include <dune/stuff/common/math.hh>

#if HAVE_DUNE_ISTL && HAVE_DUNE_FEM
  // for dune-istl
# if defined(HAVE_BOOST)
#   undef HAVE_BOOST
#   define HAVE_BOOST 1
# endif
# include <dune/stuff/common/disable_warnings.hh>
#   include <dune/fem/operator/matrix/spmatrix.hh>
#   include <dune/istl/operators.hh>
#   include <dune/fem/operator/matrix/istlmatrix.hh>
#   include <dune/fem/operator/matrix/preconditionerwrapper.hh>
# include <dune/stuff/common/reenable_warnings.hh>
#endif // if HAVE_DUNE_ISTL && HAVE_DUNE_FEM

namespace Dune {
namespace Stuff {
namespace Common {

/** \brief get the diagonal of a fieldMatrix into a fieldvector
   * \note While in principle this might do for SparseRowMatrix as well, don't do it! SparseRowMatrix has specialised
   *functions for this (putting the diagonal into DiscreteFunctions tho
   **/
template< class FieldMatrixType >
class MatrixDiagonal
  : public FieldVector< typename FieldMatrixType::field_type,
                        FieldMatrixType::rows >
{
public:
  MatrixDiagonal(const FieldMatrixType& matrix) {
    static_assert(FieldMatrixType::rows == FieldMatrixType::cols, "Matrix must be square!");
    // CompileTimeChecker< FieldMatrixType::rows == FieldMatrixType::cols > matrix_must_be_square;

    for (size_t i = 0; i < FieldMatrixType::rows; i++)
      (*this)[i] = matrix[i][i];
  }
}; // class MatrixDiagonal

//! returns Sum of matrix' diagonal entries
template< class FieldMatrixType >
typename FieldMatrixType::field_type matrixTrace(const FieldMatrixType& matrix) {
  MatrixDiagonal< FieldMatrixType > diag(matrix);
  typename FieldMatrixType::field_type trace = typename FieldMatrixType::field_type(0);
  for (size_t i = 0; i < FieldMatrixType::rows; i++)
    trace += diag[i];
  return trace;
} // typename FieldMatrixType::field_type matrixTrace(const FieldMatrixType& matrix)

//! produces a NxN Identity matrix compatible with parent type
template< class MatrixType >
class IdentityMatrix
  : public MatrixType
{
public:
  IdentityMatrix(size_t N)
    : MatrixType(N, N, 1) {
    for (size_t i = 1; i < N; ++i)
      MatrixType::set(i, i, 1.0);
  }

  const MatrixType& matrix() const { return *this; }
}; // class IdentityMatrix

//! adds the missing setDiag function to SparseRowMatrix
template< class DiscFuncType, class MatrixType >
void setMatrixDiag(MatrixType& matrix, DiscFuncType& diag) {
  typedef typename DiscFuncType::DofIteratorType DofIteratorType;

  //! we assume that the dimension of the functionspace of f is the same as
  //! the size of the matrix
  DofIteratorType it = diag.dbegin();

  for (int row = 0; row < matrix.rows(); row++)
  {
    if (*it != 0.0)
      matrix.set(row, row, *it);
    ++it;
  }
  return;
} // setMatrixDiag

//! return false if
abs( a(row,col) - b(col,row) ) > tolerance
 for any col,row
template< class MatrixType >
bool areTransposed(const MatrixType& a, const MatrixType& b, const double tolerance = 1e-8) {
  if ( ( a.rows() != b.cols() ) || ( b.rows() != a.cols() ) )
    return false;

  for (int row = 0; row < a.rows(); ++row)
  {
    for (int col = 0; col  tolerance)
        return false;
    }
  }
  return true;
} // areTransposed

//! extern matrix addition that ignore 0 entries
template< class MatrixType >
void addMatrix(MatrixType& dest, const MatrixType& arg, const double eps = 1e-14) {
  for (int i = 0; i < arg.rows(); ++i)
    for (int j = 0; j < arg.cols(); ++j)
    {
      const double value = arg(i, j);
      if (std::fabs(value) > eps)
        dest.add(i, j, value);
    }

} // addMatrix

/** @brief Write sparse matrix to given output stream
   *
   *  @param[in]  matrix The matrix to be written
   *  @param[in] out    The outgoing stream
   */
template< class SparseMatrixImpl, class Output >
void writeSparseMatrix(const SparseMatrixImpl& matrix,
                       Output& out) {
  const unsigned int nRows = matrix.rows();
  const unsigned int nCols = matrix.cols();

  for (int i = 0; i != nRows; ++i)
  {
    for (int j = 0; j != nCols; ++j)
    {
      if ( matrix.find(i, j) )
      {
        out << i << "," << j << ",";
        out.precision(12);
        out.setf(std::ios::scientific);
        out << matrix(i, j) << std::endl;
      }
    }
  }
  return;
} // writeSparseMatrix

/** @brief Read sparse matrix from given inputstream
   *
   *  @param[out] matrix The matrix to be read
   *  @param[in]  in     The ingoing stream
   */
template< class SparseMatrixImpl, class Input >
void readSparseMatrix(SparseMatrixImpl& matrix,
                      Input& in) {
  matrix.clear();
  std::string row;
  while ( std::getline(in, row) )
  {
    size_t last_found = 0;
    size_t found = row.find_first_of(",");
    double temp;
    std::vector< double > entryLine;
    do {
      if (found == std::string::npos)
        found = row.size();
      std::string subs = row.substr(last_found, found - last_found);
      last_found = found + 1;
      std::istringstream in_str(subs);
      if (entryLine.size() == 2)
      {
        in_str.precision(12);
        in_str.setf(std::ios::scientific);
      } else {
        in_str.precision(10);
        in_str.setf(std::ios::fixed);
      }
      in_str >> temp;
      entryLine.push_back(temp);
      found = row.find_first_of(",", last_found);
    } while (last_found != row.size() + 1);
    assert(entryLine.size() == 3);
    matrix.add(entryLine[0], entryLine[1], entryLine[2]);
  }
} // readSparseMatrix

/**
   *  \brief  multiplies rows of arg2 with arg1
   *  \todo   doc
   **/
template< class FieldMatrixImp >
FieldMatrixImp rowWiseMatrixMultiplication(const FieldMatrixImp& arg1,
                                           const FieldMatrixImp& arg2) {
  typedef FieldMatrixImp
  FieldMatrixType;
  typedef typename FieldMatrixType::row_type
  RowType;
  typedef typename FieldMatrixType::ConstRowIterator
  ConstRowIteratorType;
  typedef typename FieldMatrixType::RowIterator
  RowIteratorType;

  assert( arg2.rowdim() == arg1.coldim() );

  FieldMatrixType ret(0.0);

  ConstRowIteratorType arg2RowItEnd = arg2.end();
  RowIteratorType retRowItEnd = ret.end();
  RowIteratorType retRowIt = ret.begin();
  for (ConstRowIteratorType arg2RowIt = arg2.begin();
       arg2RowIt != arg2RowItEnd, retRowIt != retRowItEnd;
       ++arg2RowIt, ++retRowIt)
  {
    RowType row(0.0);
    arg1.mv(*arg2RowIt, row);
    *retRowIt = row;
  }
  return ret;
} // rowWiseMatrixMultiplication

//! prints actual memusage of matrix in kB
template< class MatrixType >
void printMemUsage(const MatrixType& matrix, std::ostream& stream, std::string name = "") {
  long size = matrix.numberOfValues() * sizeof(typename MatrixType::Ttype) / 1024.f;

  stream << "matrix size " << name << "\t\t" << size << std::endl;
}

//! prints actual memusage of matrixobject in kB
template< class MatrixObjectType>
void printMemUsageObject(const MatrixObjectType& matrix_object, std::ostream& stream, std::string name = "") {
  printMemUsage(matrix_object.matrix(), stream, name);
}

template< class M >
void forceTranspose(const M& arg, M& dest) {
  assert( arg.cols() == dest.rows() );
  assert( dest.cols() == arg.rows() );
// dest.clear();
  for (int i = 0; i < arg.cols(); ++i)
    for (int j = 0; j < arg.rows(); ++j)
      dest.set( j, i, arg(i, j) );
} // forceTranspose

} // namespace Common
} // namespace Stuff
} // namespace Dune

#endif // DUNE_STUFF_COMMON_MATRIX_HH
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2013 midnightBITS
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use, copy,
 * modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include "pch.h"
#include <ssdp.hpp>
#include <thread>
#include <http.hpp>
#include <http_parser.hpp>

namespace net
{
	namespace ssdp
	{
		const boost::asio::ip::address & ipv4_multicast()
		{
			using boost::asio::ip::address;
			using boost::asio::ip::address_v4;

			// 239.255.255.250
			static address multicast_address { address_v4 { 0xEFFFFFFA } };
			return multicast_address;
		}

		const boost::asio::ip::udp::endpoint & ipv4_multicast_endpoint()
		{
			static boost::asio::ip::udp::endpoint multicast_endpoint { ipv4_multicast(), PORT };
			return multicast_endpoint;
		}

		static void print_debug(bool ignoring, const net::http::http_request& header)
		{
			std::string ssdp_ST = header.ssdp_ST();

			if (ssdp_ST == "urn:schemas-upnp-org:device:InternetGatewayDevice:1")
				return;

			std::ostringstream o;
			if (ignoring)
				o << "[...] ";
			else
				o << "[SSDP] ";
			o << header.m_method << " " << header.m_resource << " " << header.m_protocol << " [" << to_string(header.m_remote_address) << ":" << header.m_remote_port << "]";

			if (!ssdp_ST.empty())
				o << " [" << ssdp_ST << "]";

			auto ssdp_MAN = header.ssdp_MAN();
			if (!ssdp_MAN.empty())
				o << " [" << ssdp_MAN << "]";

			auto ssdp_NTS = header.quoted("nts");
			if (!ssdp_NTS.empty())
			{
				auto location = header.simple("location");
				if (ssdp_NTS == "ssdp:alive" && !location.empty())
					o << " [" << location << "]";
				else
					o << " [" << ssdp_NTS << "]";
			}

			auto ssdp_NT = header.quoted("nt");
			if (!ssdp_NT.empty())
				o << " [" << ssdp_NT << "]";

			o << "\n";

			if (ssdp_ST.empty() && ssdp_MAN.empty() && ssdp_NT.empty() && ssdp_NTS.empty())
				o << header;

			std::cout << o.str();
		}

		ticker::ticker(boost::asio::io_service& io_service, const device_ptr& device, long seconds, net::ushort port)
			: m_service(io_service)
			, m_device(device)
			, m_timer(io_service, boost::posix_time::seconds(seconds / 3))
			, m_interval(seconds)
			, m_local(net::iface::get_default_interface())
			, m_port(port)
		{
		}

		void ticker::start()
		{
			notify(ALIVE);

			m_timer.async_wait([this](boost::system::error_code ec)
			{
				if (!ec)
					stillAlive();
			});
		}

		void ticker::stop()
		{
			m_timer.cancel();
			notify(BYEBYE);
		}

		std::string ticker::build_msg(const std::string& nt, notification_type nts) const
		{
			http::http_request req { "NOTIFY", "*" };
			req.append("host")->out() << net::to_string(ipv4_multicast()) << ":" << PORT;
			req.append("nt", nt);
			req.append("nts")->out() << nts;

			auto && usn = m_device->usn();
			if (nt == usn)
				req.append("usn", usn);
			else
				req.append("usn")->out() << usn << "::" << nt;

			if (nts == ALIVE)
			{
				req.append("location")->out() << "http://" << net::to_string(m_local) << ":" << m_port << "/config/device.xml";
				req.append("cache-control")->out() << "max-age=" << m_interval;
				req.append("server")->out() << http::get_ssdp_server_version(m_device->server());
			}

			std::ostringstream os;
			os << req;
			return os.str();
		}

		void ticker::notify(notification_type nts) const
		{
			auto socket = std::make_shared<udp::multicast_socket>(m_service, ipv4_multicast_endpoint());

			printf("Sending %s...\n", nts == ALIVE ? "ALIVE" : "BYEBYE"); fflush(stdout);

			socket->send(build_msg("upnp:rootdevice", nts));
			socket->send(build_msg(m_device->usn(), nts));
			socket->send(build_msg("urn:schemas-upnp-org:device:MediaServer:1", nts));
			socket->send(build_msg("urn:schemas-upnp-org:service:ContentDirectory:1", nts));
			socket->send(build_msg("urn:schemas-upnp-org:service:ContentManager:1", nts));
		}

		void ticker::stillAlive()
		{
			notify(ALIVE);
			m_timer.expires_at(m_timer.expires_at() + boost::posix_time::seconds(m_interval));
			m_timer.async_wait([this](boost::system::error_code ec)
			{
				if (!ec)
					stillAlive();
			});
		}

		receiver::receiver(boost::asio::io_service& io_service, const device_ptr& device, net::ushort port)
			: m_impl(io_service, boost::asio::ip::udp::endpoint(ipv4_multicast(), PORT))
			, m_device(device)
			, m_service(io_service)
			, m_local(net::iface::get_default_interface())
			, m_port(port)
		{
		}

		namespace mcast = boost::asio::ip::multicast;
		void receiver::start()
		{
			m_impl.start([this]
			{
				net::http::header_parser<net::http::http_request> parser;

				const char* data = m_impl.data();

				if (parser.parse(data, data + m_impl.received()) == net::http::parser::finished)
				{
					auto && header = parser.header();
					header.remote_endpoint(m_impl.remote());

					bool printed = false;

					if (header.m_method == "M-SEARCH")
					{
						std::string st = header.ssdp_ST();
						std::string man = header.ssdp_MAN();
						if (!st.empty())
						{
							if (st == "urn:schemas-upnp-org:service:ContentManager:1" ||
								st == "urn:schemas-upnp-org:service:ContentDirectory:1" ||
								st == "urn:schemas-upnp-org:device:MediaServer:1" ||
								st == "upnp:rootdevice" ||
								st == "ssdp:all" ||
								st == m_device->usn())
							{
								print_debug(false, header);
								printed = true;

								if (st == "ssdp:all")
									st = "urn:schemas-upnp-org:device:MediaServer:1";

								discovery(st);
							}
						}
					}

					if (!printed)
					{
						print_debug(true, header);
					}
				}
				else
				{
					std::cout << "[ " << m_impl.remote().address() << ":" << m_impl.remote().port() << " ]\n";
					std::cout.write(m_impl.data(), m_impl.received());
					std::cout << "\n";
				}

				return true;
			});
		}

		void receiver::stop()
		{
			m_impl.stop();
		}

		void receiver::discovery(const std::string& st)
		{
			auto datagram = std::make_shared<udp::unicast_socket>(m_service, m_impl.remote());
			datagram->send(build_discovery_msg(st));
		}

		std::string receiver::build_discovery_msg(const std::string& st) const
		{
			http::http_response resp {};
			resp.append("date")->out() << net::to_string(net::time::now());
			resp.append("location")->out() << "http://" << net::to_string(m_local) << ":" << m_port << "/config/device.xml";
			resp.append("cache-control")->out() << "max-age=1800";
			resp.append("server")->out() << http::get_ssdp_server_version(m_device->server());
			resp.append("st", st);
			resp.append("ext");

			auto && usn = m_device->usn();
			if (st == usn)
				resp.append("usn", usn);
			else
				resp.append("usn")->out() << usn << "::" << st;

			resp.append("content-length", "0");

			std::ostringstream os;
			os << resp;
			return os.str();
		}

	}
}
<commit_msg>Limiting builtin types to "ssdp:rootdevice" and "ssdp:all" - others are queried from the device and services objects.<commit_after>/*
 * Copyright (C) 2013 midnightBITS
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use, copy,
 * modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include "pch.h"
#include <ssdp.hpp>
#include <thread>
#include <http.hpp>
#include <http_parser.hpp>

namespace net
{
	namespace ssdp
	{
		const boost::asio::ip::address & ipv4_multicast()
		{
			using boost::asio::ip::address;
			using boost::asio::ip::address_v4;

			// 239.255.255.250
			static address multicast_address { address_v4 { 0xEFFFFFFA } };
			return multicast_address;
		}

		const boost::asio::ip::udp::endpoint & ipv4_multicast_endpoint()
		{
			static boost::asio::ip::udp::endpoint multicast_endpoint { ipv4_multicast(), PORT };
			return multicast_endpoint;
		}

		static void print_debug(bool ignoring, const net::http::http_request& header)
		{
			std::string ssdp_ST = header.ssdp_ST();

			if (ssdp_ST == "urn:schemas-upnp-org:device:InternetGatewayDevice:1")
				return;

			std::ostringstream o;
			if (ignoring)
				o << "[...] ";
			else
				o << "[SSDP] ";
			o << header.m_method << " " << header.m_resource << " " << header.m_protocol << " [" << to_string(header.m_remote_address) << ":" << header.m_remote_port << "]";

			if (!ssdp_ST.empty())
				o << " [" << ssdp_ST << "]";

			auto ssdp_MAN = header.ssdp_MAN();
			if (!ssdp_MAN.empty())
				o << " [" << ssdp_MAN << "]";

			auto ssdp_NTS = header.quoted("nts");
			if (!ssdp_NTS.empty())
			{
				auto location = header.simple("location");
				if (ssdp_NTS == "ssdp:alive" && !location.empty())
					o << " [" << location << "]";
				else
					o << " [" << ssdp_NTS << "]";
			}

			auto ssdp_NT = header.quoted("nt");
			if (!ssdp_NT.empty())
				o << " [" << ssdp_NT << "]";

			o << "\n";

			if (ssdp_ST.empty() && ssdp_MAN.empty() && ssdp_NT.empty() && ssdp_NTS.empty())
				o << header;

			std::cout << o.str();
		}

		ticker::ticker(boost::asio::io_service& io_service, const device_ptr& device, long seconds, net::ushort port)
			: m_service(io_service)
			, m_device(device)
			, m_timer(io_service, boost::posix_time::seconds(seconds / 3))
			, m_interval(seconds)
			, m_local(net::iface::get_default_interface())
			, m_port(port)
		{
		}

		void ticker::start()
		{
			notify(ALIVE);

			m_timer.async_wait([this](boost::system::error_code ec)
			{
				if (!ec)
					stillAlive();
			});
		}

		void ticker::stop()
		{
			m_timer.cancel();
			notify(BYEBYE);
		}

		std::string ticker::build_msg(const std::string& nt, notification_type nts) const
		{
			http::http_request req { "NOTIFY", "*" };
			req.append("host")->out() << net::to_string(ipv4_multicast()) << ":" << PORT;
			req.append("nt", nt);
			req.append("nts")->out() << nts;

			auto&& usn = m_device->usn();
			if (nt == usn)
				req.append("usn", usn);
			else
				req.append("usn")->out() << usn << "::" << nt;

			if (nts == ALIVE)
			{
				req.append("location")->out() << "http://" << net::to_string(m_local) << ":" << m_port << "/config/device.xml";
				req.append("cache-control")->out() << "max-age=" << m_interval;
				req.append("server")->out() << http::get_ssdp_server_version(m_device->server());
			}

			std::ostringstream os;
			os << req;
			return os.str();
		}

		void ticker::notify(notification_type nts) const
		{
			auto socket = std::make_shared<udp::multicast_socket>(m_service, ipv4_multicast_endpoint());

			printf("Sending %s...\n", nts == ALIVE ? "ALIVE" : "BYEBYE"); fflush(stdout);

			socket->send(build_msg("upnp:rootdevice", nts));
			socket->send(build_msg(m_device->usn(), nts));
			socket->send(build_msg(m_device->get_type(), nts));
			for (auto&& service : services(m_device))
				socket->send(build_msg(service->get_type(), nts));
		}

		void ticker::stillAlive()
		{
			notify(ALIVE);
			m_timer.expires_at(m_timer.expires_at() + boost::posix_time::seconds(m_interval));
			m_timer.async_wait([this](boost::system::error_code ec)
			{
				if (!ec)
					stillAlive();
			});
		}

		receiver::receiver(boost::asio::io_service& io_service, const device_ptr& device, net::ushort port)
			: m_impl(io_service, boost::asio::ip::udp::endpoint(ipv4_multicast(), PORT))
			, m_device(device)
			, m_service(io_service)
			, m_local(net::iface::get_default_interface())
			, m_port(port)
		{
		}

		namespace mcast = boost::asio::ip::multicast;
		void receiver::start()
		{
			m_impl.start([this]
			{
				net::http::header_parser<net::http::http_request> parser;

				const char* data = m_impl.data();

				if (parser.parse(data, data + m_impl.received()) == net::http::parser::finished)
				{
					auto&& header = parser.header();
					header.remote_endpoint(m_impl.remote());

					bool printed = false;

					if (header.m_method == "M-SEARCH")
					{
						std::string st = header.ssdp_ST();
						std::string man = header.ssdp_MAN();
						if (!st.empty())
						{
							bool interesting = false;
							if (!interesting) interesting = st == "ssdp:all";
							if (!interesting) interesting = st == "ssdp:rootdevice";
							if (!interesting) interesting = st == m_device->usn();
							if (!interesting) interesting = st == m_device->get_type();
							if (!interesting)
								for (auto&& service : ssdp::services(m_device))
									if ((interesting = (st == service->get_type())) == true)
										break;

							if (interesting)
							{
								print_debug(false, header);
								printed = true;

								if (st == "ssdp:all")
									st = m_device->get_type();

								discovery(st);
							}
						}
					}

					if (!printed)
					{
						print_debug(true, header);
					}
				}
				else
				{
					std::cout << "[ " << m_impl.remote().address() << ":" << m_impl.remote().port() << " ]\n";
					std::cout.write(m_impl.data(), m_impl.received());
					std::cout << "\n";
				}

				return true;
			});
		}

		void receiver::stop()
		{
			m_impl.stop();
		}

		void receiver::discovery(const std::string& st)
		{
			auto datagram = std::make_shared<udp::unicast_socket>(m_service, m_impl.remote());
			datagram->send(build_discovery_msg(st));
		}

		std::string receiver::build_discovery_msg(const std::string& st) const
		{
			http::http_response resp {};
			resp.append("date")->out() << net::to_string(net::time::now());
			resp.append("location")->out() << "http://" << net::to_string(m_local) << ":" << m_port << "/config/device.xml";
			resp.append("cache-control")->out() << "max-age=1800";
			resp.append("server")->out() << http::get_ssdp_server_version(m_device->server());
			resp.append("st", st);
			resp.append("ext");

			auto&& usn = m_device->usn();
			if (st == usn)
				resp.append("usn", usn);
			else
				resp.append("usn")->out() << usn << "::" << st;

			resp.append("content-length", "0");

			std::ostringstream os;
			os << resp;
			return os.str();
		}

	}
}
<|endoftext|>


<commit_before>// Copyright (C) 2017 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., University of Heidelberg, and University of
// of Connecticut School of Medicine.
// All rights reserved.

// Copyright (C) 2010 - 2016 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., University of Heidelberg, and The University
// of Manchester.
// All rights reserved.

/*
 * CQModelWidget.cpp
 *
 *  Created on: Aug 13, 2010
 *      Author: shoops
 */
#include <QUndoStack>

#include "CQModelWidget.h"
#include "qtUtilities.h"
#include "copasiui3window.h"
#include "CQCopasiApplication.h"
#include "CQValidatorUnit.h"

#include "resourcesUI/CQIconResource.h"

#include "model/CModel.h"
#include "utilities/CUnit.h"
#include "report/CCopasiRootContainer.h"

#include "undoFramework/ModelChangeCommand.h"

CQModelWidget::CQModelWidget(QWidget* parent, const char* name) :
  CopasiWidget(parent, name),
  mpModel(NULL)
{
  setupUi(this);

  CQValidatorUnit * pValidator = new CQValidatorUnit(mpEditTimeUnit);
  pValidator->setConstraint("s");
  mpEditTimeUnit->setValidator(pValidator);

  pValidator = new CQValidatorUnit(mpEditQuantityUnit);
  pValidator->setConstraint("#");
  mpEditQuantityUnit->setValidator(pValidator);

  pValidator = new CQValidatorUnit(mpEditVolumeUnit);
  pValidator->setConstraint("m^3");
  mpEditVolumeUnit->setValidator(pValidator);

  pValidator = new CQValidatorUnit(mpEditAreaUnit);
  pValidator->setConstraint("m^2");
  mpEditAreaUnit->setValidator(pValidator);

  pValidator = new CQValidatorUnit(mpEditLengthUnit);
  pValidator->setConstraint("m");
  mpEditLengthUnit->setValidator(pValidator);

  mpUndoStack = NULL;

#ifndef COPASI_EXTUNIT
  mpLblAreaUnit->hide();
  mpComboAreaUnit->hide();

  mpLblLengthUnit->hide();
  mpComboLengthUnit->hide();
#endif
}

CQModelWidget::~CQModelWidget()
{}

void CQModelWidget::load()
{
  if (mpModel == NULL)
    return;

  mpEditTimeUnit->setText(FROM_UTF8(mpModel->getTimeUnitName()));
  static_cast< const CQValidatorUnit * >(mpEditTimeUnit->validator())->saved();

  mpEditQuantityUnit->setText(FROM_UTF8(mpModel->getQuantityUnitName()));
  static_cast< const CQValidatorUnit * >(mpEditQuantityUnit->validator())->saved();

  mpEditVolumeUnit->setText(FROM_UTF8(mpModel->getVolumeUnitName()));
  static_cast< const CQValidatorUnit * >(mpEditVolumeUnit->validator())->saved();

  mpEditAreaUnit->setText(FROM_UTF8(mpModel->getAreaUnitName()));
  static_cast< const CQValidatorUnit * >(mpEditAreaUnit->validator())->saved();

  mpEditLengthUnit->setText(FROM_UTF8(mpModel->getLengthUnitName()));
  static_cast< const CQValidatorUnit * >(mpEditLengthUnit->validator())->saved();

#ifndef COPASI_EXTUNIT
  mpEditAreaUnit->hide();
  mpEditLengthUnit->hide();
#endif

  mpEditInitialTime->setReadOnly(mpModel->isAutonomous());
  mpEditInitialTime->setText(QString::number(mpModel->getInitialTime(), 'g', 10));
  mpEditCurrentTime->setText(QString::number(mpModel->getTime(), 'g', 10));

  mpCheckStochasticCorrection->setChecked(mpModel->getModelType() == CModel::deterministic);

  slotUnitChanged();

  return;
}

void CQModelWidget::save()
{
  if (mpModel == NULL)
    return;

  bool changed = false;

  mIgnoreUpdates = true;

  if (mpUndoStack == NULL)
    {
      mpUndoStack = static_cast<CQCopasiApplication*>(qApp)
                    ->getMainWindow()->getUndoStack();
    }

  if (mpEditTimeUnit->text() != FROM_UTF8(mpModel->getTimeUnitName()))
    {
      mpUndoStack->push(
        new ModelChangeCommand(CCopasiUndoCommand::MODEL_TIME_UNIT_CHANGE,
                               FROM_UTF8(mpModel->getTimeUnitName()),
                               mpEditTimeUnit->text(),
                               this));
      changed = true;
    }

  if (mpEditVolumeUnit->text() != FROM_UTF8(mpModel->getVolumeUnitName()))
    {
      mpUndoStack->push(
        new ModelChangeCommand(CCopasiUndoCommand::MODEL_VOLUME_UNIT_CHANGE,
                               FROM_UTF8(mpModel->getVolumeUnitName()),
                               mpEditVolumeUnit->text(),
                               this));
      changed = true;
    }

  if (mpEditAreaUnit->text() != FROM_UTF8(mpModel->getAreaUnitName()))
    {
      mpUndoStack->push(
        new ModelChangeCommand(CCopasiUndoCommand::MODEL_AREA_UNIT_CHANGE,
                               FROM_UTF8(mpModel->getAreaUnitName()),
                               mpEditAreaUnit->text(),
                               this));
      changed = true;
    }

  if (mpEditLengthUnit->text() != FROM_UTF8(mpModel->getLengthUnitName()))
    {
      mpUndoStack->push(
        new ModelChangeCommand(CCopasiUndoCommand::MODEL_LENGTH_UNIT_CHANGE,
                               FROM_UTF8(mpModel->getLengthUnitName()),
                               mpEditLengthUnit->text(),
                               this));
      changed = true;
    }

  if (mpEditQuantityUnit->text() != FROM_UTF8(mpModel->getQuantityUnitName()))
    {
      QList< QVariant > OldValues, NewValues;

      OldValues.append(FROM_UTF8(mpModel->getQuantityUnitName()));
      NewValues.append(mpEditQuantityUnit->text());
      OldValues.append(mFramework);
      NewValues.append(mFramework);

      mpUndoStack->push(
        new ModelChangeCommand(CCopasiUndoCommand::MODEL_QUANTITY_UNIT_CHANGE,
                               FROM_UTF8(mpModel->getQuantityUnitName()),
                               mpEditQuantityUnit->text(),
                               this));
      changed = true;
    }

  if (mpCheckStochasticCorrection->isChecked() != (mpModel->getModelType() == CModel::deterministic))
    {
      mpUndoStack->push(
        new ModelChangeCommand(CCopasiUndoCommand::MODEL_STOCHASTIC_CORRECTION_CHANGE,
                               mpModel->getModelType() == CModel::deterministic,
                               mpCheckStochasticCorrection->isChecked(),
                               this));
      changed = true;
    }

  if (mpEditInitialTime->text() != QString::number(mpModel->getInitialTime()))
    {
      mpUndoStack->push(
        new ModelChangeCommand(CCopasiUndoCommand::MODEL_INITIAL_TIME_CHANGE,
                               mpModel->getInitialTime(),
                               mpEditInitialTime->text().toDouble(),
                               this));
      changed = true;
    }

  mIgnoreUpdates = false;

  if (changed)
    {
      if (mpDataModel != NULL)
        {
          mpDataModel->changed();
        }

      protectedNotify(ListViews::MODEL, ListViews::CHANGE, mKey);

      load();
    }

  return;
}

void CQModelWidget::slotBtnRevertClicked()
{
  load();
}

void CQModelWidget::slotBtnOKClicked()
{
  save();
  load();
}

bool CQModelWidget::update(ListViews::ObjectType objectType,
                           ListViews::Action C_UNUSED(action), const std::string & key)
{
  if (mIgnoreUpdates) return true;

  switch (objectType)
    {
      case ListViews::MODEL:
        enter(key);
        break;

      default:
        break;
    }

  return true;
}

bool CQModelWidget::leave()
{
  save();

  mpNotes->leave();

  return true;
}

bool CQModelWidget::enterProtected()
{
  if (mpObject != NULL)
    mpModel = dynamic_cast< CModel * >(mpObject);
  else
    mpModel = NULL;

  load();

  mpNotes->enter(mKey);

  return true;
}

bool
CQModelWidget::changeValue(CCopasiUndoCommand::Type type, const QVariant& newValue)
{
  mpListView->switchToOtherWidget(C_INVALID_INDEX, mKey);

  if (mpModel == NULL)
    {
      GET_MODEL_OR(pModel, return false);
      mpModel = pModel;
    }

  if (type == CCopasiUndoCommand::MODEL_TIME_UNIT_CHANGE)
    {
      mpModel->setTimeUnit(TO_UTF8(newValue.toString()));
    }
  else if (type == CCopasiUndoCommand::MODEL_QUANTITY_UNIT_CHANGE)
    {
      mpModel->setQuantityUnit(TO_UTF8(newValue.toString()), (CModelParameter::Framework) mFramework);
    }
  else if (type == CCopasiUndoCommand::MODEL_VOLUME_UNIT_CHANGE)
    {
      mpModel->setVolumeUnit(TO_UTF8(newValue.toString()));
    }
  else if (type == CCopasiUndoCommand::MODEL_AREA_UNIT_CHANGE)
    {
      mpModel->setAreaUnit(TO_UTF8(newValue.toString()));
    }
  else if (type == CCopasiUndoCommand::MODEL_LENGTH_UNIT_CHANGE)
    {
      mpModel->setLengthUnit(TO_UTF8(newValue.toString()));
    }
  else if (type == CCopasiUndoCommand::MODEL_INITIAL_TIME_CHANGE)
    {
      mpModel->setInitialTime(newValue.toDouble());
    }
  else if (type == CCopasiUndoCommand::MODEL_STOCHASTIC_CORRECTION_CHANGE)
    {
      if (newValue.toBool())
        {
          mpModel->setModelType(CModel::deterministic);
        }
      else
        {
          mpModel->setModelType(CModel::stochastic);
        }
    }
  else
    {
      return false;
    }

  if (mIgnoreUpdates) return true;

  if (mpDataModel != NULL)
    {
      mpDataModel->changed();
    }

  protectedNotify(ListViews::MODEL, ListViews::CHANGE, mKey);

  load();

  return true;
}

// virtual
void CQModelWidget::slotUnitChanged()
{
  QString Unit = FROM_UTF8(CUnit::prettyPrint(TO_UTF8(mpEditTimeUnit->text())));
  mpEditTimeUnit->setText(Unit);

  mpLblInitialTime->setText("Initial Time [" + Unit + "]");
  mpLblCurrentTime->setText("Time [" + Unit + "]");

  Unit = FROM_UTF8(CUnit::prettyPrint(TO_UTF8(mpEditQuantityUnit->text())));
  mpEditQuantityUnit->setText(Unit);

  Unit = FROM_UTF8(CUnit::prettyPrint(TO_UTF8(mpEditVolumeUnit->text())));
  mpEditVolumeUnit->setText(Unit);

  Unit = FROM_UTF8(CUnit::prettyPrint(TO_UTF8(mpEditAreaUnit->text())));
  mpEditAreaUnit->setText(Unit);

  Unit = FROM_UTF8(CUnit::prettyPrint(TO_UTF8(mpEditLengthUnit->text())));
  mpEditLengthUnit->setText(Unit);
}
<commit_msg>Fixed to compile for release.<commit_after>// Copyright (C) 2017 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., University of Heidelberg, and University of
// of Connecticut School of Medicine.
// All rights reserved.

// Copyright (C) 2010 - 2016 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., University of Heidelberg, and The University
// of Manchester.
// All rights reserved.

/*
 * CQModelWidget.cpp
 *
 *  Created on: Aug 13, 2010
 *      Author: shoops
 */
#include <QUndoStack>

#include "CQModelWidget.h"
#include "qtUtilities.h"
#include "copasiui3window.h"
#include "CQCopasiApplication.h"
#include "CQValidatorUnit.h"

#include "resourcesUI/CQIconResource.h"

#include "model/CModel.h"
#include "utilities/CUnit.h"
#include "report/CCopasiRootContainer.h"

#include "undoFramework/ModelChangeCommand.h"

CQModelWidget::CQModelWidget(QWidget* parent, const char* name) :
  CopasiWidget(parent, name),
  mpModel(NULL)
{
  setupUi(this);

  CQValidatorUnit * pValidator = new CQValidatorUnit(mpEditTimeUnit);
  pValidator->setConstraint("s");
  mpEditTimeUnit->setValidator(pValidator);

  pValidator = new CQValidatorUnit(mpEditQuantityUnit);
  pValidator->setConstraint("#");
  mpEditQuantityUnit->setValidator(pValidator);

  pValidator = new CQValidatorUnit(mpEditVolumeUnit);
  pValidator->setConstraint("m^3");
  mpEditVolumeUnit->setValidator(pValidator);

  pValidator = new CQValidatorUnit(mpEditAreaUnit);
  pValidator->setConstraint("m^2");
  mpEditAreaUnit->setValidator(pValidator);

  pValidator = new CQValidatorUnit(mpEditLengthUnit);
  pValidator->setConstraint("m");
  mpEditLengthUnit->setValidator(pValidator);

  mpUndoStack = NULL;

#ifndef COPASI_EXTUNIT
  mpLblAreaUnit->hide();
  mpEditAreaUnit->hide();

  mpLblLengthUnit->hide();
  mpEditLengthUnit->hide();
#endif
}

CQModelWidget::~CQModelWidget()
{}

void CQModelWidget::load()
{
  if (mpModel == NULL)
    return;

  mpEditTimeUnit->setText(FROM_UTF8(mpModel->getTimeUnitName()));
  static_cast< const CQValidatorUnit * >(mpEditTimeUnit->validator())->saved();

  mpEditQuantityUnit->setText(FROM_UTF8(mpModel->getQuantityUnitName()));
  static_cast< const CQValidatorUnit * >(mpEditQuantityUnit->validator())->saved();

  mpEditVolumeUnit->setText(FROM_UTF8(mpModel->getVolumeUnitName()));
  static_cast< const CQValidatorUnit * >(mpEditVolumeUnit->validator())->saved();

  mpEditAreaUnit->setText(FROM_UTF8(mpModel->getAreaUnitName()));
  static_cast< const CQValidatorUnit * >(mpEditAreaUnit->validator())->saved();

  mpEditLengthUnit->setText(FROM_UTF8(mpModel->getLengthUnitName()));
  static_cast< const CQValidatorUnit * >(mpEditLengthUnit->validator())->saved();

#ifndef COPASI_EXTUNIT
  mpEditAreaUnit->hide();
  mpEditLengthUnit->hide();
#endif

  mpEditInitialTime->setReadOnly(mpModel->isAutonomous());
  mpEditInitialTime->setText(QString::number(mpModel->getInitialTime(), 'g', 10));
  mpEditCurrentTime->setText(QString::number(mpModel->getTime(), 'g', 10));

  mpCheckStochasticCorrection->setChecked(mpModel->getModelType() == CModel::deterministic);

  slotUnitChanged();

  return;
}

void CQModelWidget::save()
{
  if (mpModel == NULL)
    return;

  bool changed = false;

  mIgnoreUpdates = true;

  if (mpUndoStack == NULL)
    {
      mpUndoStack = static_cast<CQCopasiApplication*>(qApp)
                    ->getMainWindow()->getUndoStack();
    }

  if (mpEditTimeUnit->text() != FROM_UTF8(mpModel->getTimeUnitName()))
    {
      mpUndoStack->push(
        new ModelChangeCommand(CCopasiUndoCommand::MODEL_TIME_UNIT_CHANGE,
                               FROM_UTF8(mpModel->getTimeUnitName()),
                               mpEditTimeUnit->text(),
                               this));
      changed = true;
    }

  if (mpEditVolumeUnit->text() != FROM_UTF8(mpModel->getVolumeUnitName()))
    {
      mpUndoStack->push(
        new ModelChangeCommand(CCopasiUndoCommand::MODEL_VOLUME_UNIT_CHANGE,
                               FROM_UTF8(mpModel->getVolumeUnitName()),
                               mpEditVolumeUnit->text(),
                               this));
      changed = true;
    }

  if (mpEditAreaUnit->text() != FROM_UTF8(mpModel->getAreaUnitName()))
    {
      mpUndoStack->push(
        new ModelChangeCommand(CCopasiUndoCommand::MODEL_AREA_UNIT_CHANGE,
                               FROM_UTF8(mpModel->getAreaUnitName()),
                               mpEditAreaUnit->text(),
                               this));
      changed = true;
    }

  if (mpEditLengthUnit->text() != FROM_UTF8(mpModel->getLengthUnitName()))
    {
      mpUndoStack->push(
        new ModelChangeCommand(CCopasiUndoCommand::MODEL_LENGTH_UNIT_CHANGE,
                               FROM_UTF8(mpModel->getLengthUnitName()),
                               mpEditLengthUnit->text(),
                               this));
      changed = true;
    }

  if (mpEditQuantityUnit->text() != FROM_UTF8(mpModel->getQuantityUnitName()))
    {
      QList< QVariant > OldValues, NewValues;

      OldValues.append(FROM_UTF8(mpModel->getQuantityUnitName()));
      NewValues.append(mpEditQuantityUnit->text());
      OldValues.append(mFramework);
      NewValues.append(mFramework);

      mpUndoStack->push(
        new ModelChangeCommand(CCopasiUndoCommand::MODEL_QUANTITY_UNIT_CHANGE,
                               FROM_UTF8(mpModel->getQuantityUnitName()),
                               mpEditQuantityUnit->text(),
                               this));
      changed = true;
    }

  if (mpCheckStochasticCorrection->isChecked() != (mpModel->getModelType() == CModel::deterministic))
    {
      mpUndoStack->push(
        new ModelChangeCommand(CCopasiUndoCommand::MODEL_STOCHASTIC_CORRECTION_CHANGE,
                               mpModel->getModelType() == CModel::deterministic,
                               mpCheckStochasticCorrection->isChecked(),
                               this));
      changed = true;
    }

  if (mpEditInitialTime->text() != QString::number(mpModel->getInitialTime()))
    {
      mpUndoStack->push(
        new ModelChangeCommand(CCopasiUndoCommand::MODEL_INITIAL_TIME_CHANGE,
                               mpModel->getInitialTime(),
                               mpEditInitialTime->text().toDouble(),
                               this));
      changed = true;
    }

  mIgnoreUpdates = false;

  if (changed)
    {
      if (mpDataModel != NULL)
        {
          mpDataModel->changed();
        }

      protectedNotify(ListViews::MODEL, ListViews::CHANGE, mKey);

      load();
    }

  return;
}

void CQModelWidget::slotBtnRevertClicked()
{
  load();
}

void CQModelWidget::slotBtnOKClicked()
{
  save();
  load();
}

bool CQModelWidget::update(ListViews::ObjectType objectType,
                           ListViews::Action C_UNUSED(action), const std::string & key)
{
  if (mIgnoreUpdates) return true;

  switch (objectType)
    {
      case ListViews::MODEL:
        enter(key);
        break;

      default:
        break;
    }

  return true;
}

bool CQModelWidget::leave()
{
  save();

  mpNotes->leave();

  return true;
}

bool CQModelWidget::enterProtected()
{
  if (mpObject != NULL)
    mpModel = dynamic_cast< CModel * >(mpObject);
  else
    mpModel = NULL;

  load();

  mpNotes->enter(mKey);

  return true;
}

bool
CQModelWidget::changeValue(CCopasiUndoCommand::Type type, const QVariant& newValue)
{
  mpListView->switchToOtherWidget(C_INVALID_INDEX, mKey);

  if (mpModel == NULL)
    {
      GET_MODEL_OR(pModel, return false);
      mpModel = pModel;
    }

  if (type == CCopasiUndoCommand::MODEL_TIME_UNIT_CHANGE)
    {
      mpModel->setTimeUnit(TO_UTF8(newValue.toString()));
    }
  else if (type == CCopasiUndoCommand::MODEL_QUANTITY_UNIT_CHANGE)
    {
      mpModel->setQuantityUnit(TO_UTF8(newValue.toString()), (CModelParameter::Framework) mFramework);
    }
  else if (type == CCopasiUndoCommand::MODEL_VOLUME_UNIT_CHANGE)
    {
      mpModel->setVolumeUnit(TO_UTF8(newValue.toString()));
    }
  else if (type == CCopasiUndoCommand::MODEL_AREA_UNIT_CHANGE)
    {
      mpModel->setAreaUnit(TO_UTF8(newValue.toString()));
    }
  else if (type == CCopasiUndoCommand::MODEL_LENGTH_UNIT_CHANGE)
    {
      mpModel->setLengthUnit(TO_UTF8(newValue.toString()));
    }
  else if (type == CCopasiUndoCommand::MODEL_INITIAL_TIME_CHANGE)
    {
      mpModel->setInitialTime(newValue.toDouble());
    }
  else if (type == CCopasiUndoCommand::MODEL_STOCHASTIC_CORRECTION_CHANGE)
    {
      if (newValue.toBool())
        {
          mpModel->setModelType(CModel::deterministic);
        }
      else
        {
          mpModel->setModelType(CModel::stochastic);
        }
    }
  else
    {
      return false;
    }

  if (mIgnoreUpdates) return true;

  if (mpDataModel != NULL)
    {
      mpDataModel->changed();
    }

  protectedNotify(ListViews::MODEL, ListViews::CHANGE, mKey);

  load();

  return true;
}

// virtual
void CQModelWidget::slotUnitChanged()
{
  QString Unit = FROM_UTF8(CUnit::prettyPrint(TO_UTF8(mpEditTimeUnit->text())));
  mpEditTimeUnit->setText(Unit);

  mpLblInitialTime->setText("Initial Time [" + Unit + "]");
  mpLblCurrentTime->setText("Time [" + Unit + "]");

  Unit = FROM_UTF8(CUnit::prettyPrint(TO_UTF8(mpEditQuantityUnit->text())));
  mpEditQuantityUnit->setText(Unit);

  Unit = FROM_UTF8(CUnit::prettyPrint(TO_UTF8(mpEditVolumeUnit->text())));
  mpEditVolumeUnit->setText(Unit);

  Unit = FROM_UTF8(CUnit::prettyPrint(TO_UTF8(mpEditAreaUnit->text())));
  mpEditAreaUnit->setText(Unit);

  Unit = FROM_UTF8(CUnit::prettyPrint(TO_UTF8(mpEditLengthUnit->text())));
  mpEditLengthUnit->setText(Unit);
}
<|endoftext|>