<commit_before>#ifndef __Data__
#define __Data__

#include <iostream>
#include <sstream>
#include <fstream>
#include <vector>
#include <algorithm>    // has the for_each

using namespace std;

string tostring(int i) {
	ostringstream tmp;
	tmp << i;
	return tmp.str();
}

int stringToInt(string const& str) {
  istringstream i(str);
  int x;
  i >> x;
  return x;
}

float stringToFloat(string const& str) {
  istringstream i(str);
  float x;
  i >> x;
  return x;
}

vector<string> &split(const string &s, char delim, vector<string> &elems) {
    stringstream ss(s);
    string item;
    while (getline(ss, item, delim)) {
        elems.push_back(item);
    }
    return elems;
}

vector<string> split(const string &s, char delim) {
	// taken from http://stackoverflow.com/a/236803
    vector<string> elems;
    split(s, delim, elems);
    return elems;
}

string removeAllQuotes(string s) {
  s.erase(remove(s.begin(), s.end(), '\"'), s.end());
  return s;
}

enum GenEd {
	// Foundation Studies
	FYW,   // First-Year Writing
	WRI,   // Writing in Context
	FOL,   // Foreign Language
	ORC,   // Oral Communication
	AQR,   // Abstract and Quantitative Reasoning
	SPM,   // Studies in Physical Movement

	// Core Studies
	HWC,   // Historical Studies in Western Culture
	MCD,   // Multicultural Studies: Domestic
	MCG,   // Multicultural Studies: Global
	ALSA,  // Artistic and Literary Studies: Artistic Studies
	ALSL,  // Artistic and Literary Studies: Literary Studies
	BTSB,  // Biblical and Theological Studies: Bible
	BTST,  // Biblical and Theological Studies: Theology
	SED,   // Studies in Natural Science: Scientific Exploration and Discovery
	IST,   // Studies in Natural Science: Integrated Scientific Topics
	HBS,   // Studies in Human Behavior and Society

	// Integrative Studies
	EIN    // Ethical Issues and Normative Perspectives
};

struct Instructor {
	string name;
	string specialty;
};

struct Department {
	string name;
	string shorthand;
};

struct Major {
	string name;
	int difficulty;
};

struct Concentration {
	string name;
	int difficulty;
};

struct Conversation {
	string name;
	int difficulty;
};

class Course {
protected:
	string ID;
	int number;
	string title;
	string description;
	char section;

	vector<Major> majors;
	Department department;
	vector<Concentration> concentrations;
	vector<Conversation> conversations;
	vector<Instructor> professor;

	int half_semester;
	bool pass_fail;
	float credits;
	string location;

	bool lab;
	GenEd* geneds;

	bool days[7];
	float time[7];
public:
	Course(istream &is) {
		if (is == 0) return;
		string tmpLine;
		getline(is, tmpLine);
		vector<string> record = split(tmpLine, ',');
		for (vector<string>::iterator i=record.begin(); i != record.end(); ++i)
		  *i=removeAllQuotes(*i);

		// Ignore the first column;
		record.at(0);

		// Second column has the course ID,
		//number = stringToInt(record.at(1));
		ID = record.at(1);
		number = parseID(ID);

		// Third column has the section,
		section = record.at(2)[0];

		// Fourth holds the lab boolean,
		if (record.at(3).empty())
			lab = false;
		else
			lab = true;

		// while Fifth contains the title of the course;
		title = record.at(4);

		// Sixth hands over the length (half semester or not)
		// it's actually an int that tells us how many times the course is offered per semester.
		half_semester = stringToInt(record.at(5));

		// Seventh tells us the number of credits,
		credits = stringToFloat(record.at(6));

		// Eighth shows us if it can be taken pass/no-pass,
		if (record.at(7) == "Y")
			pass_fail = true;
		else
			pass_fail = false;

		// while Nine gives us the GEs of the course,
		// GEreqs = record.at(9);

		// and Ten spits out the days and times;
		// Times = record.at(10);

		// Eleven holds the location,
		location = record.at(11);

		// and Twelve knows who teaches.
		// Instructors = record.at(12);
	}
  /*void parseID(char* str) {
		string tmp = str;
		ID = tmp;
		// TODO: do this.
		}*/
        int parseID(string s) {
	   return stringToInt(s.substr(s.find(' ')+1,3));}

	void updateID() {
		ID = department.shorthand + tostring(number) + section;
	}
	string getID() {
		return ID;
	}

        ostream& getData(ostream &os) {
	        os << ID << section << " " << number << " ";
		os << title << "/";
		/*for (vector<Instructor>::iterator i = professor.begin(); i != professor.end(); ++i) {
			os << i->name << " ";
			}*/
		return os;
	}
	void display();
};

ostream &operator<<(ostream &os, Course &item) { return item.getData(os); }
void Course::display() { cout << *this << endl; }

void spit(Course n) {
	n.display();
}

class Student {
public:
	string name;
	vector<Course> takenCourses;
	vector<Major> majors;
	vector<Concentration> concentrations;
	vector<Conversation> conversations;
	vector<Instructor> favInstructors;

	string interests;
	double gradYear;

	ostream& getData(ostream &os) {
		os << name << " ";

		for (vector<Course>::iterator i = takenCourses.begin(); i != takenCourses.end(); ++i)
			os << i->getID() << " ";

		for (vector<Major>::iterator i = majors.begin(); i != majors.end(); ++i)
			os << i->name << " ";

		return os;
	}
	void display();
};

#endif

<commit_msg>Update error detection in Course(istream)<commit_after>#ifndef __Data__
#define __Data__

#include <iostream>
#include <sstream>
#include <fstream>
#include <vector>
#include <algorithm>    // has the for_each

using namespace std;

string tostring(int i) {
	ostringstream tmp;
	tmp << i;
	return tmp.str();
}

int stringToInt(string const& str) {
  istringstream i(str);
  int x;
  i >> x;
  return x;
}

float stringToFloat(string const& str) {
  istringstream i(str);
  float x;
  i >> x;
  return x;
}

vector<string> &split(const string &s, char delim, vector<string> &elems) {
    stringstream ss(s);
    string item;
    while (getline(ss, item, delim)) {
        elems.push_back(item);
    }
    return elems;
}

vector<string> split(const string &s, char delim) {
	// taken from http://stackoverflow.com/a/236803
    vector<string> elems;
    split(s, delim, elems);
    return elems;
}

string removeAllQuotes(string s) {
  s.erase(remove(s.begin(), s.end(), '\"'), s.end());
  return s;
}

enum GenEd {
	// Foundation Studies
	FYW,   // First-Year Writing
	WRI,   // Writing in Context
	FOL,   // Foreign Language
	ORC,   // Oral Communication
	AQR,   // Abstract and Quantitative Reasoning
	SPM,   // Studies in Physical Movement

	// Core Studies
	HWC,   // Historical Studies in Western Culture
	MCD,   // Multicultural Studies: Domestic
	MCG,   // Multicultural Studies: Global
	ALSA,  // Artistic and Literary Studies: Artistic Studies
	ALSL,  // Artistic and Literary Studies: Literary Studies
	BTSB,  // Biblical and Theological Studies: Bible
	BTST,  // Biblical and Theological Studies: Theology
	SED,   // Studies in Natural Science: Scientific Exploration and Discovery
	IST,   // Studies in Natural Science: Integrated Scientific Topics
	HBS,   // Studies in Human Behavior and Society

	// Integrative Studies
	EIN    // Ethical Issues and Normative Perspectives
};

struct Instructor {
	string name;
	string specialty;
};

struct Department {
	string name;
	string shorthand;
};

struct Major {
	string name;
	int difficulty;
};

struct Concentration {
	string name;
	int difficulty;
};

struct Conversation {
	string name;
	int difficulty;
};

class Course {
protected:
	string ID;
	int number;
	string title;
	string description;
	char section;

	vector<Major> majors;
	Department department;
	vector<Concentration> concentrations;
	vector<Conversation> conversations;
	vector<Instructor> professor;

	int half_semester;
	bool pass_fail;
	float credits;
	string location;

	bool lab;
	GenEd* geneds;

	bool days[7];
	float time[7];
public:
	Course(istream &is) {
		if (!is) return;
		string tmpLine;
		getline(is, tmpLine);
		vector<string> record = split(tmpLine, ',');
		for (vector<string>::iterator i=record.begin(); i != record.end(); ++i)
		  *i=removeAllQuotes(*i);

		// Ignore the first column;
		record.at(0);

		// Second column has the course ID,
		//number = stringToInt(record.at(1));
		ID = record.at(1);
		number = parseID(ID);

		// Third column has the section,
		section = record.at(2)[0];

		// Fourth holds the lab boolean,
		if (record.at(3).empty())
			lab = false;
		else
			lab = true;

		// while Fifth contains the title of the course;
		title = record.at(4);

		// Sixth hands over the length (half semester or not)
		// it's actually an int that tells us how many times the course is offered per semester.
		half_semester = stringToInt(record.at(5));

		// Seventh tells us the number of credits,
		credits = stringToFloat(record.at(6));

		// Eighth shows us if it can be taken pass/no-pass,
		if (record.at(7) == "Y")
			pass_fail = true;
		else
			pass_fail = false;

		// while Nine gives us the GEs of the course,
		// GEreqs = record.at(9);

		// and Ten spits out the days and times;
		// Times = record.at(10);

		// Eleven holds the location,
		location = record.at(11);

		// and Twelve knows who teaches.
		// Instructors = record.at(12);
	}
  /*void parseID(char* str) {
		string tmp = str;
		ID = tmp;
		// TODO: do this.
		}*/
        int parseID(string s) {
	   return stringToInt(s.substr(s.find(' ')+1,3));}

	void updateID() {
		ID = department.shorthand + tostring(number) + section;
	}
	string getID() {
		return ID;
	}

        ostream& getData(ostream &os) {
	        os << ID << section << " " << number << " ";
		os << title << "/";
		/*for (vector<Instructor>::iterator i = professor.begin(); i != professor.end(); ++i) {
			os << i->name << " ";
			}*/
		return os;
	}
	void display();
};

ostream &operator<<(ostream &os, Course &item) { return item.getData(os); }
void Course::display() { cout << *this << endl; }

void spit(Course n) {
	n.display();
}

class Student {
public:
	string name;
	vector<Course> takenCourses;
	vector<Major> majors;
	vector<Concentration> concentrations;
	vector<Conversation> conversations;
	vector<Instructor> favInstructors;

	string interests;
	double gradYear;

	ostream& getData(ostream &os) {
		os << name << " ";

		for (vector<Course>::iterator i = takenCourses.begin(); i != takenCourses.end(); ++i)
			os << i->getID() << " ";

		for (vector<Major>::iterator i = majors.begin(); i != majors.end(); ++i)
			os << i->name << " ";

		return os;
	}
	void display();
};

#endif

<|endoftext|>


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

#include "stdafx.hpp"
#include "tray_icon.hpp"
#include "znc_tray.hpp"
#include "resource.h"

using namespace ZNCTray;

CTrayIcon::CTrayIcon(HWND a_hwndMainWin, const wchar_t* a_szAppTitle) :
	m_hwndMainWin(a_hwndMainWin),
	m_szAppTitle(a_szAppTitle),
	m_iconColor(0),
	m_hIcon(0),
	m_addedToTna(false)
{
}

bool CTrayIcon::Add(char a_color)
{
	if(m_addedToTna)
	{
		return this->UpdateColor(a_color);
	}

	NOTIFYICONDATA l_nid;
	this->_InitNotifyIconData(&l_nid);

	l_nid.uFlags |= NIF_MESSAGE | NIF_ICON | NIF_TIP;

	l_nid.uCallbackMessage = WM_TRAYICONEVENT;

	// set icon
	this->LoadIconForColor(a_color);
	l_nid.hIcon = m_hIcon;

	// add tooltip/title:
	wcscpy_s(l_nid.szTip, 128, m_szAppTitle);

	// go (retry some times because of known windows weirdness, at least on XP):
	for(int retry = 0; retry < 10; retry++)
	{
		m_addedToTna = (::Shell_NotifyIcon(NIM_ADD, &l_nid) != FALSE);

		if(m_addedToTna)
		{
			break;
		}

		::Sleep(100);
	}

	if(m_addedToTna)
	{
		// use most current available feature set...

		this->_InitNotifyIconData(&l_nid);

		l_nid.uVersion = (CWinUtils::WinVerAtLeast(6, 0) ? NOTIFYICON_VERSION_4 : NOTIFYICON_VERSION);

		::Shell_NotifyIcon(NIM_SETVERSION, &l_nid);
	}

	return m_addedToTna;
}

bool CTrayIcon::Remove()
{
	if(!m_addedToTna)
	{
		// already removed
		return true;
	}

	NOTIFYICONDATA l_nid;
	this->_InitNotifyIconData(&l_nid);

	m_addedToTna = false;

	return (::Shell_NotifyIcon(NIM_DELETE, &l_nid) != FALSE);
}

bool CTrayIcon::UpdateColor(char a_color)
{
	if(!m_addedToTna)
	{
		return false;
	}

	if(a_color != m_iconColor)
	{
		NOTIFYICONDATA l_nid;
		this->_InitNotifyIconData(&l_nid);

		this->LoadIconForColor(a_color);

		l_nid.hIcon = m_hIcon;
		l_nid.uFlags |= NIF_ICON;

		bool success;

		// retry some times because of known windows weirdness, at least on XP:
		for(int retry = 0; retry < 10; retry++)
		{
			success = (::Shell_NotifyIcon(NIM_MODIFY, &l_nid) != FALSE);

			if(success)
			{
				break;
			}

			::Sleep(100);
		}

		return success;
	}

	return true;
}

void CTrayIcon::OnWmTaskbarCreated()
{
	// re-add after explorer.exe restarts e.g.
	if(m_addedToTna)
	{
		m_addedToTna = false;
		this->Add(m_iconColor);
	}
}

void CTrayIcon::LoadIconForColor(char a_color)
{
	if(m_hIcon == 0 || a_color != m_iconColor)
	{
		if(m_hIcon) ::DestroyIcon(m_hIcon);

		m_hIcon = ::LoadIcon(g_hInstance, MAKEINTRESOURCE(
			(a_color == 'R' ? IDI_ICONZRED :
			(a_color == 'G' ? IDI_ICONZGREEN :
			IDI_ICONZBLUE))));

		m_iconColor = a_color;
	}
}

void CTrayIcon::_InitNotifyIconData(PNOTIFYICONDATA nid)
{
	// find target structure size by checking OS version...
	// the actually officially recommended way would be using DllGetVersion from Shell32.dll...
	// ...but that would require an assload of code, so we take a shortcut.

	RtlZeroMemory(nid, sizeof(NOTIFYICONDATA));

	if(CWinUtils::WinVerAtLeast(6, 0))
	{
		nid->cbSize = sizeof(NOTIFYICONDATA);
	}
	else
	{
		nid->cbSize = NOTIFYICONDATA_V3_SIZE;
	}

	nid->hWnd = m_hwndMainWin;

#if 0 /* actually don't do this, because once someone decides to move the .exe file,
	the icon will stop working ...
	ref: http://msdn.microsoft.com/en-us/library/windows/desktop/bb773352%28v=vs.85%29.aspx */

	if(CWinUtils::WinVerAtLeast(6, 1)) // identify icon by GUID on Windows 7
	{
		static const GUID ls_iconGuid = // {C28F9A28-C95E-4E99-ADFD-9A7EFA8530DF}
			{ 0xc28f9a28, 0xc95e, 0x4e99, { 0xad, 0xfd, 0x9a, 0x7e, 0xfa, 0x85, 0x30, 0xdf } };

		nid->uFlags = NIF_GUID;
		nid->guidItem = ls_iconGuid;
	}
	else // regular boring ID on XP, Vista
#endif
	{
		nid->uID = 0x962;
	}
}

void CTrayIcon::OnWmTrayIconEvent(WPARAM wParam, LPARAM lParam)
{
	UINT uMsg;
	POINT pt;

	// ref: http://msdn.microsoft.com/en-us/library/windows/desktop/bb773352%28v=vs.85%29.aspx

	if(CWinUtils::WinVerAtLeast(6, 0)) // NOTIFYICON_VERSION_4
	{
		uMsg = LOWORD(lParam);

		pt.x = GET_X_LPARAM(wParam);
		pt.y = GET_Y_LPARAM(wParam);
	}
	else // NOTIFYICON_VERSION
	{
		uMsg = static_cast<UINT>(lParam);

		::GetCursorPos(&pt);
	}

	switch(uMsg)
	{
	case WM_CONTEXTMENU:
		this->ShowContextMenu(&pt);
		break;

	case WM_LBUTTONDBLCLK:
		// send WMC_SHOW_CONTROL_WIN:
		::PostMessage(m_hwndMainWin, WM_COMMAND, MAKEWPARAM(WMC_SHOW_CONTROL_WIN, 0), 0);
		break;
	}
}

#define _APPENDMENU(FLAG, CMD, TXT) InsertMenu(hMenu, -1, MF_BYPOSITION | FLAG, CMD, TXT);

void CTrayIcon::ShowContextMenu(LPPOINT pt)
{
	HMENU hMenu = ::CreatePopupMenu();

	// put together menu at runtime:

	::_APPENDMENU(0, WMC_SHOW_CONTROL_WIN, L"Show");

	::_APPENDMENU(MF_SEPARATOR, 0, NULL);
	::_APPENDMENU(0, WMC_CLOSE_TRAY, L"Quit");

	// as per MSDN recommendation:
	::SetForegroundWindow(m_hwndMainWin);

	// Display the menu (modally):
	::TrackPopupMenu(hMenu, TPM_BOTTOMALIGN, pt->x, pt->y, 0, m_hwndMainWin, NULL);

	// as per MSDN recommendation:
	::PostMessage(m_hwndMainWin, WM_NULL, 0, 0);

	// recursively free menu:
	::DestroyMenu(hMenu);
}

CTrayIcon::~CTrayIcon()
{
	Remove();
}
<commit_msg>remove superfluous semicolon :-)<commit_after>/*
* Copyright (C) 2012-2014 ZNC-MSVC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include "stdafx.hpp"
#include "tray_icon.hpp"
#include "znc_tray.hpp"
#include "resource.h"

using namespace ZNCTray;

CTrayIcon::CTrayIcon(HWND a_hwndMainWin, const wchar_t* a_szAppTitle) :
	m_hwndMainWin(a_hwndMainWin),
	m_szAppTitle(a_szAppTitle),
	m_iconColor(0),
	m_hIcon(0),
	m_addedToTna(false)
{
}

bool CTrayIcon::Add(char a_color)
{
	if(m_addedToTna)
	{
		return this->UpdateColor(a_color);
	}

	NOTIFYICONDATA l_nid;
	this->_InitNotifyIconData(&l_nid);

	l_nid.uFlags |= NIF_MESSAGE | NIF_ICON | NIF_TIP;

	l_nid.uCallbackMessage = WM_TRAYICONEVENT;

	// set icon
	this->LoadIconForColor(a_color);
	l_nid.hIcon = m_hIcon;

	// add tooltip/title:
	wcscpy_s(l_nid.szTip, 128, m_szAppTitle);

	// go (retry some times because of known windows weirdness, at least on XP):
	for(int retry = 0; retry < 10; retry++)
	{
		m_addedToTna = (::Shell_NotifyIcon(NIM_ADD, &l_nid) != FALSE);

		if(m_addedToTna)
		{
			break;
		}

		::Sleep(100);
	}

	if(m_addedToTna)
	{
		// use most current available feature set...

		this->_InitNotifyIconData(&l_nid);

		l_nid.uVersion = (CWinUtils::WinVerAtLeast(6, 0) ? NOTIFYICON_VERSION_4 : NOTIFYICON_VERSION);

		::Shell_NotifyIcon(NIM_SETVERSION, &l_nid);
	}

	return m_addedToTna;
}

bool CTrayIcon::Remove()
{
	if(!m_addedToTna)
	{
		// already removed
		return true;
	}

	NOTIFYICONDATA l_nid;
	this->_InitNotifyIconData(&l_nid);

	m_addedToTna = false;

	return (::Shell_NotifyIcon(NIM_DELETE, &l_nid) != FALSE);
}

bool CTrayIcon::UpdateColor(char a_color)
{
	if(!m_addedToTna)
	{
		return false;
	}

	if(a_color != m_iconColor)
	{
		NOTIFYICONDATA l_nid;
		this->_InitNotifyIconData(&l_nid);

		this->LoadIconForColor(a_color);

		l_nid.hIcon = m_hIcon;
		l_nid.uFlags |= NIF_ICON;

		bool success;

		// retry some times because of known windows weirdness, at least on XP:
		for(int retry = 0; retry < 10; retry++)
		{
			success = (::Shell_NotifyIcon(NIM_MODIFY, &l_nid) != FALSE);

			if(success)
			{
				break;
			}

			::Sleep(100);
		}

		return success;
	}

	return true;
}

void CTrayIcon::OnWmTaskbarCreated()
{
	// re-add after explorer.exe restarts e.g.
	if(m_addedToTna)
	{
		m_addedToTna = false;
		this->Add(m_iconColor);
	}
}

void CTrayIcon::LoadIconForColor(char a_color)
{
	if(m_hIcon == 0 || a_color != m_iconColor)
	{
		if(m_hIcon) ::DestroyIcon(m_hIcon);

		m_hIcon = ::LoadIcon(g_hInstance, MAKEINTRESOURCE(
			(a_color == 'R' ? IDI_ICONZRED :
			(a_color == 'G' ? IDI_ICONZGREEN :
			IDI_ICONZBLUE))));

		m_iconColor = a_color;
	}
}

void CTrayIcon::_InitNotifyIconData(PNOTIFYICONDATA nid)
{
	// find target structure size by checking OS version...
	// the actually officially recommended way would be using DllGetVersion from Shell32.dll...
	// ...but that would require an assload of code, so we take a shortcut.

	RtlZeroMemory(nid, sizeof(NOTIFYICONDATA));

	if(CWinUtils::WinVerAtLeast(6, 0))
	{
		nid->cbSize = sizeof(NOTIFYICONDATA);
	}
	else
	{
		nid->cbSize = NOTIFYICONDATA_V3_SIZE;
	}

	nid->hWnd = m_hwndMainWin;

#if 0 /* actually don't do this, because once someone decides to move the .exe file,
	the icon will stop working ...
	ref: http://msdn.microsoft.com/en-us/library/windows/desktop/bb773352%28v=vs.85%29.aspx */

	if(CWinUtils::WinVerAtLeast(6, 1)) // identify icon by GUID on Windows 7
	{
		static const GUID ls_iconGuid = // {C28F9A28-C95E-4E99-ADFD-9A7EFA8530DF}
			{ 0xc28f9a28, 0xc95e, 0x4e99, { 0xad, 0xfd, 0x9a, 0x7e, 0xfa, 0x85, 0x30, 0xdf } };

		nid->uFlags = NIF_GUID;
		nid->guidItem = ls_iconGuid;
	}
	else // regular boring ID on XP, Vista
#endif
	{
		nid->uID = 0x962;
	}
}

void CTrayIcon::OnWmTrayIconEvent(WPARAM wParam, LPARAM lParam)
{
	UINT uMsg;
	POINT pt;

	// ref: http://msdn.microsoft.com/en-us/library/windows/desktop/bb773352%28v=vs.85%29.aspx

	if(CWinUtils::WinVerAtLeast(6, 0)) // NOTIFYICON_VERSION_4
	{
		uMsg = LOWORD(lParam);

		pt.x = GET_X_LPARAM(wParam);
		pt.y = GET_Y_LPARAM(wParam);
	}
	else // NOTIFYICON_VERSION
	{
		uMsg = static_cast<UINT>(lParam);

		::GetCursorPos(&pt);
	}

	switch(uMsg)
	{
	case WM_CONTEXTMENU:
		this->ShowContextMenu(&pt);
		break;

	case WM_LBUTTONDBLCLK:
		// send WMC_SHOW_CONTROL_WIN:
		::PostMessage(m_hwndMainWin, WM_COMMAND, MAKEWPARAM(WMC_SHOW_CONTROL_WIN, 0), 0);
		break;
	}
}

#define _APPENDMENU(FLAG, CMD, TXT) InsertMenu(hMenu, -1, MF_BYPOSITION | FLAG, CMD, TXT)

void CTrayIcon::ShowContextMenu(LPPOINT pt)
{
	HMENU hMenu = ::CreatePopupMenu();

	// put together menu at runtime:

	::_APPENDMENU(0, WMC_SHOW_CONTROL_WIN, L"Show");

	::_APPENDMENU(MF_SEPARATOR, 0, NULL);
	::_APPENDMENU(0, WMC_CLOSE_TRAY, L"Quit");

	// as per MSDN recommendation:
	::SetForegroundWindow(m_hwndMainWin);

	// Display the menu (modally):
	::TrackPopupMenu(hMenu, TPM_BOTTOMALIGN, pt->x, pt->y, 0, m_hwndMainWin, NULL);

	// as per MSDN recommendation:
	::PostMessage(m_hwndMainWin, WM_NULL, 0, 0);

	// recursively free menu:
	::DestroyMenu(hMenu);
}

CTrayIcon::~CTrayIcon()
{
	Remove();
}
<|endoftext|>


<commit_before>#include "n_code_widget.h"
#include "ui_n_code_widget.h"
#include "n_util.h"

#include <QFileSystemModel>
#include <QDebug>
#include <QTextEdit>
#include <QMenu>
#include <QInputDialog>
#include <QMessageBox>
#include <QFileSystemWatcher>

NCodeWidget::NCodeWidget(QWidget *parent) : QWidget(parent), ui(new Ui::NCodeWidget)
{
    ui->setupUi(this);
    mProjectDir = new QDir(QDir::homePath());

    mFileSysteMmodel = new QFileSystemModel;
    mFileSysteMmodel->setReadOnly(false);
    ui->codeTreeView->setModel(mFileSysteMmodel);
    ui->codeTreeView->hideColumn(1);
    ui->codeTreeView->hideColumn(2);
    ui->codeTreeView->hideColumn(3);
    ui->codeTreeView->hideColumn(4);
}

void NCodeWidget::setCurrentProject(QString dirPath) {
    mProjectDir->setPath(dirPath);
    mProjectName = mProjectDir->dirName();

    QString codeDirPath = mProjectDir->absoluteFilePath("code");
    mFileSysteMmodel->setRootPath(codeDirPath);
    //特定のディレクトリ以降のみを表示するための設定
    ui->codeTreeView->setRootIndex(mFileSysteMmodel->index(codeDirPath));

    ui->codeTabWidget->clear();
}

void NCodeWidget::saveCode() {
    /**
     * TODO: 現在は開いている全てのファイルをほぞんしているが、編集されたものだけを保存するようにすべき。
     * そのためにはファイルが編集されたら何らかの目印を付ける必要がある。
     * 例えばタブ名にアスタリスクをつけるなど.
     */

    int editingCodeNum = ui->codeTabWidget->count();
    for (int i = 0; i < editingCodeNum; i++) {
        QTextEdit *edit = (QTextEdit *)ui->codeTabWidget->widget(i);
        QString text = edit->toPlainText();
        QString filePath = edit->objectName();
        QFile file(filePath);
        if (!file.open(QFile::WriteOnly | QFile::Text)) {
            qDebug() << "fail file open. " + filePath;
            return;
        }
        file.write(text.toUtf8());
    }
}

void NCodeWidget::editCode(QModelIndex index) {
    QString filePath = ((QFileSystemModel *) ui->codeTreeView->model())->filePath(index);
    QList<int> tabIndexes = searchTabIndexesByPath(filePath, false);

    // already open tab for file path;
    if (tabIndexes.length() > 0) {
        ui->codeTabWidget->setCurrentIndex(tabIndexes[0]);
        return;
    }

    QFile file(filePath);
    QString fileName = QFileInfo(filePath).fileName();

    if(!file.open(QFile::ReadOnly | QFile::Text)){
        return;
    }

    QTextEdit *textEdit = new QTextEdit();
    textEdit->setObjectName(filePath);
    textEdit->setText(file.readAll());
    file.close();
    int tabIndex = ui->codeTabWidget->addTab(textEdit, fileName);
    ui->codeTabWidget->setCurrentIndex(tabIndex);

    connect(textEdit, SIGNAL(textChanged()), this, SLOT(updateTabForTextChanged()));
}
void NCodeWidget::updateTabForTextChanged() {
    int tabIndex = ui->codeTabWidget->currentIndex();
    QString tabText = ui->codeTabWidget->tabText(tabIndex);

    if (tabText[tabText.length() - 1] != '*') {
        ui->codeTabWidget->setTabText(tabIndex, tabText + "*");
    }
}

void NCodeWidget::updateTabForPath(const QString &oldPath, const QString &newPath) {
    QFileInfo newPathInfo(newPath);
    QList<int> indexes  = searchTabIndexesByPath(oldPath, newPathInfo.isDir());

    for (int i = 0; i < indexes.length(); i++) {
        int index = indexes[i];
        QTextEdit *edit = (QTextEdit *)ui->codeTabWidget->widget(index);
        QString filePath = edit->objectName();
        filePath = newPath + filePath.remove(0, oldPath.length());
        edit->setObjectName(filePath);

        ui->codeTabWidget->setTabText(index, QFileInfo(filePath).fileName());
    }
}

void NCodeWidget::updateTabForDropped(QString dropDirPath, QString selectedFilePath) {
    QString fileName = QFileInfo(selectedFilePath).fileName();
    QString newFilePath = QDir(dropDirPath).absoluteFilePath(fileName);

    updateTabForPath(selectedFilePath, newFilePath);
}

void NCodeWidget::deleteTabForPath(const QString &path, const bool &isDir) {
    QList<int> indexes = searchTabIndexesByPath(path, isDir);

    for (int i = 0; i < indexes.length(); i++) {
        ui->codeTabWidget->removeTab(indexes[i]);
    }
}

QList<int> NCodeWidget::searchTabIndexesByPath(const QString &path, const bool &isDir) {
    QList<int> indexes;

    if (isDir) {
        int tabNum = ui->codeTabWidget->count();
        for (int i = 0; i < tabNum; i++) {
            QTextEdit *edit = (QTextEdit *)ui->codeTabWidget->widget(i);
            QString filePath = edit->objectName();
            if (filePath.indexOf(path) == 0) {
                indexes.append(i);
            }
        }
    } else {
        int tabNum = ui->codeTabWidget->count();
        for (int i = 0; i < tabNum; i++) {
            QTextEdit *edit = (QTextEdit *)ui->codeTabWidget->widget(i);
            QString filePath = edit->objectName();
            if (QString::compare(path, filePath) == 0) {
                indexes.append(i);
            }
        }
    }

    return indexes;
}

void NCodeWidget::contextMenu() {
    QMenu menu(this);
    menu.addAction(tr("&New"), this, SLOT(newFile()));
    menu.addAction(tr("&Rename"), this, SLOT(renamePath()));
    menu.addAction(tr("&Copy"), this, SLOT(copyPath()));
    menu.addAction(tr("&Delete"), this, SLOT(deletePath()));
    menu.addSeparator();
    menu.addAction(tr("&New Directory"), this, SLOT(newDir()));
    menu.exec(QCursor::pos());
}

void NCodeWidget::newFile() {
    QString fileName = QInputDialog::getText(this, tr("New File"), tr("create new file"));
    QString parentPath = NUtil::selectedPath(ui->codeTreeView);
    NUtil::newFile(parentPath, fileName, "js");
}

void NCodeWidget::newDir() {
    QString dirName = QInputDialog::getText(this, tr("New Directory"), tr("create new directory"));
    QString parentPath = NUtil::selectedPath(ui->codeTreeView);
    NUtil::newDir(parentPath, dirName);
}

void NCodeWidget::deletePath() {
    QString path = NUtil::selectedPath(ui->codeTreeView);
    bool isDir = QFileInfo(path).isDir();
    bool ret = NUtil::deletePath(path);

    if (ret) {
        deleteTabForPath(path, isDir);
    }
}

void NCodeWidget::renamePath() {
    QString newName = QInputDialog::getText(this, tr("Rename File"), tr("enter new name"));
    QString srcPath = NUtil::selectedPath(ui->codeTreeView);
    QString newPath = NUtil::renamePath(srcPath, newName, "js");

    if (newPath.isEmpty()) {
        return;
    }

    updateTabForPath(srcPath, newPath);
}

void NCodeWidget::copyPath() {
    QString newName = QInputDialog::getText(this, tr("Copy File"), tr("enter copy name"));
    QString srcPath = NUtil::selectedPath(ui->codeTreeView);
    NUtil::copyPath(srcPath, newName, "js");
}

NCodeWidget::~NCodeWidget()
{
    delete ui;
}
<commit_msg>ファイル保存時にタブ名の*を取り除くようにした<commit_after>#include "n_code_widget.h"
#include "ui_n_code_widget.h"
#include "n_util.h"

#include <QFileSystemModel>
#include <QDebug>
#include <QTextEdit>
#include <QMenu>
#include <QInputDialog>
#include <QMessageBox>
#include <QFileSystemWatcher>

NCodeWidget::NCodeWidget(QWidget *parent) : QWidget(parent), ui(new Ui::NCodeWidget)
{
    ui->setupUi(this);
    mProjectDir = new QDir(QDir::homePath());

    mFileSysteMmodel = new QFileSystemModel;
    mFileSysteMmodel->setReadOnly(false);
    ui->codeTreeView->setModel(mFileSysteMmodel);
    ui->codeTreeView->hideColumn(1);
    ui->codeTreeView->hideColumn(2);
    ui->codeTreeView->hideColumn(3);
    ui->codeTreeView->hideColumn(4);
}

void NCodeWidget::setCurrentProject(QString dirPath) {
    mProjectDir->setPath(dirPath);
    mProjectName = mProjectDir->dirName();

    QString codeDirPath = mProjectDir->absoluteFilePath("code");
    mFileSysteMmodel->setRootPath(codeDirPath);
    //特定のディレクトリ以降のみを表示するための設定
    ui->codeTreeView->setRootIndex(mFileSysteMmodel->index(codeDirPath));

    ui->codeTabWidget->clear();
}

void NCodeWidget::saveCode() {
    int editingCodeNum = ui->codeTabWidget->count();
    for (int i = 0; i < editingCodeNum; i++) {
        // 内容が編集されたものだけファイルを保存する。内容が編集されているものはタブ名の末尾がアスタリスクとなる
        QString tabName = ui->codeTabWidget->tabText(i);
        if (tabName[tabName.length() - 1] != '*') {
            continue;
        }

        QTextEdit *edit = (QTextEdit *)ui->codeTabWidget->widget(i);
        QString text = edit->toPlainText();
        QString filePath = edit->objectName();
        QFile file(filePath);
        if (!file.open(QFile::WriteOnly | QFile::Text)) {
            qDebug() << "fail file open. " + filePath;
            return;
        }
        int ret = file.write(text.toUtf8());
        if (ret == -1) {
            QMessageBox::critical(this, tr("fail save file."), tr("fail save file.") + "\n" + filePath);
            return;
        }

        // 保存が完了したのでタブ名の*を取り除く
        ui->codeTabWidget->setTabText(i, tabName.remove(tabName.length() - 1, 1));
    }
}

void NCodeWidget::editCode(QModelIndex index) {
    QString filePath = ((QFileSystemModel *) ui->codeTreeView->model())->filePath(index);
    QList<int> tabIndexes = searchTabIndexesByPath(filePath, false);

    // already open tab for file path;
    if (tabIndexes.length() > 0) {
        ui->codeTabWidget->setCurrentIndex(tabIndexes[0]);
        return;
    }

    QFile file(filePath);
    QString fileName = QFileInfo(filePath).fileName();

    if(!file.open(QFile::ReadOnly | QFile::Text)){
        return;
    }

    QTextEdit *textEdit = new QTextEdit();
    textEdit->setObjectName(filePath);
    textEdit->setText(file.readAll());
    file.close();
    int tabIndex = ui->codeTabWidget->addTab(textEdit, fileName);
    ui->codeTabWidget->setCurrentIndex(tabIndex);

    connect(textEdit, SIGNAL(textChanged()), this, SLOT(updateTabForTextChanged()));
}
void NCodeWidget::updateTabForTextChanged() {
    int tabIndex = ui->codeTabWidget->currentIndex();
    QString tabText = ui->codeTabWidget->tabText(tabIndex);

    if (tabText[tabText.length() - 1] != '*') {
        ui->codeTabWidget->setTabText(tabIndex, tabText + "*");
    }
}

void NCodeWidget::updateTabForPath(const QString &oldPath, const QString &newPath) {
    QFileInfo newPathInfo(newPath);
    QList<int> indexes  = searchTabIndexesByPath(oldPath, newPathInfo.isDir());

    for (int i = 0; i < indexes.length(); i++) {
        int index = indexes[i];
        QTextEdit *edit = (QTextEdit *)ui->codeTabWidget->widget(index);
        QString filePath = edit->objectName();
        filePath = newPath + filePath.remove(0, oldPath.length());
        edit->setObjectName(filePath);

        ui->codeTabWidget->setTabText(index, QFileInfo(filePath).fileName());
    }
}

void NCodeWidget::updateTabForDropped(QString dropDirPath, QString selectedFilePath) {
    QString fileName = QFileInfo(selectedFilePath).fileName();
    QString newFilePath = QDir(dropDirPath).absoluteFilePath(fileName);

    updateTabForPath(selectedFilePath, newFilePath);
}

void NCodeWidget::deleteTabForPath(const QString &path, const bool &isDir) {
    QList<int> indexes = searchTabIndexesByPath(path, isDir);

    for (int i = 0; i < indexes.length(); i++) {
        ui->codeTabWidget->removeTab(indexes[i]);
    }
}

QList<int> NCodeWidget::searchTabIndexesByPath(const QString &path, const bool &isDir) {
    QList<int> indexes;

    if (isDir) {
        int tabNum = ui->codeTabWidget->count();
        for (int i = 0; i < tabNum; i++) {
            QTextEdit *edit = (QTextEdit *)ui->codeTabWidget->widget(i);
            QString filePath = edit->objectName();
            if (filePath.indexOf(path) == 0) {
                indexes.append(i);
            }
        }
    } else {
        int tabNum = ui->codeTabWidget->count();
        for (int i = 0; i < tabNum; i++) {
            QTextEdit *edit = (QTextEdit *)ui->codeTabWidget->widget(i);
            QString filePath = edit->objectName();
            if (QString::compare(path, filePath) == 0) {
                indexes.append(i);
            }
        }
    }

    return indexes;
}

void NCodeWidget::contextMenu() {
    QMenu menu(this);
    menu.addAction(tr("&New"), this, SLOT(newFile()));
    menu.addAction(tr("&Rename"), this, SLOT(renamePath()));
    menu.addAction(tr("&Copy"), this, SLOT(copyPath()));
    menu.addAction(tr("&Delete"), this, SLOT(deletePath()));
    menu.addSeparator();
    menu.addAction(tr("&New Directory"), this, SLOT(newDir()));
    menu.exec(QCursor::pos());
}

void NCodeWidget::newFile() {
    QString fileName = QInputDialog::getText(this, tr("New File"), tr("create new file"));
    QString parentPath = NUtil::selectedPath(ui->codeTreeView);
    NUtil::newFile(parentPath, fileName, "js");
}

void NCodeWidget::newDir() {
    QString dirName = QInputDialog::getText(this, tr("New Directory"), tr("create new directory"));
    QString parentPath = NUtil::selectedPath(ui->codeTreeView);
    NUtil::newDir(parentPath, dirName);
}

void NCodeWidget::deletePath() {
    QString path = NUtil::selectedPath(ui->codeTreeView);
    bool isDir = QFileInfo(path).isDir();
    bool ret = NUtil::deletePath(path);

    if (ret) {
        deleteTabForPath(path, isDir);
    }
}

void NCodeWidget::renamePath() {
    QString newName = QInputDialog::getText(this, tr("Rename File"), tr("enter new name"));
    QString srcPath = NUtil::selectedPath(ui->codeTreeView);
    QString newPath = NUtil::renamePath(srcPath, newName, "js");

    if (newPath.isEmpty()) {
        return;
    }

    updateTabForPath(srcPath, newPath);
}

void NCodeWidget::copyPath() {
    QString newName = QInputDialog::getText(this, tr("Copy File"), tr("enter copy name"));
    QString srcPath = NUtil::selectedPath(ui->codeTreeView);
    NUtil::copyPath(srcPath, newName, "js");
}

NCodeWidget::~NCodeWidget()
{
    delete ui;
}
<|endoftext|>


<commit_before>#include <type_traits>

template <typename... Lambdas>
struct overloaded : public Lambdas...
{
   using Lambdas::operator()...;

   overloaded(Lambdas&&... lambdas) : Lambdas(std::forward<Lambdas>(lambdas))... {}
};

template <typename... Lambdas>
auto overload(Lambdas&&... ls) -> overloaded<std::decay_t<Lambdas>...>
{
   return { std::forward<Lambdas>(ls)... };
};

template <typename... Lambdas>
struct selecta
{
   static constexpr bool all_noexcept = (noexcept(std::declval<Lambdas>()()) && ...);

   using ov_t = overloaded<Lambdas...>;
   ov_t  ov;

   selecta(Lambdas&&... lambdas) : ov{std::forward<Lambdas>(lambdas)...} {}

   using fn_ptr_t = void (*)(ov_t&) noexcept(all_noexcept);

   template <typename Lambda>
   static constexpr auto make_caller()
   {
      return [](ov_t& ov) noexcept(all_noexcept) { static_cast<Lambda>(ov)(); };
   }

   constexpr static fn_ptr_t  fn[] = { make_caller<Lambdas>()... };

   void operator()(size_t n) noexcept(all_noexcept) { fn[n](ov); }
};

#include <iostream>
#include <string>

int main()
{
   using namespace std;

   auto sel = selecta
   {  [x = 3]     { std::cout << "first: " << x << std::endl; }
   ,  [x = 3.14]  { std::cout << "second:" << x << std::endl; }
   };

   volatile int n = 0;
   sel(n);
   n = 1;
   sel(n);
}
<commit_msg>Renamed selecta to static_selecta.<commit_after>#include <type_traits>

template <typename... Lambdas>
struct overloaded : public Lambdas...
{
   using Lambdas::operator()...;

   overloaded(Lambdas&&... lambdas) : Lambdas(std::forward<Lambdas>(lambdas))... {}
};

template <typename... Lambdas>
auto overload(Lambdas&&... ls) -> overloaded<std::decay_t<Lambdas>...>
{
   return { std::forward<Lambdas>(ls)... };
};

template <typename... Lambdas>
struct static_selecta
{
   static constexpr bool all_noexcept = (noexcept(std::declval<Lambdas>()()) && ...);

   using ov_t = overloaded<Lambdas...>;
   ov_t  ov;

   static_selecta(Lambdas&&... lambdas) : ov{std::forward<Lambdas>(lambdas)...} {}

   using fn_ptr_t = void (*)(ov_t&) noexcept(all_noexcept);

   template <typename Lambda>
   static constexpr auto make_caller()
   {
      return [](ov_t& ov) noexcept(all_noexcept) { static_cast<Lambda>(ov)(); };
   }

   constexpr static fn_ptr_t  fn[] = { make_caller<Lambdas>()... };

   void operator()(size_t n) noexcept(all_noexcept) { fn[n](ov); }
};

#include <iostream>
#include <string>

int main()
{
   using namespace std;

   auto sel = static_selecta
   {  [x = 3]     { std::cout << "first: " << x << std::endl; }
   ,  [x = 3.14]  { std::cout << "second:" << x << std::endl; }
   };

   volatile int n = 0;
   sel(n);
   n = 1;
   sel(n);
}
<|endoftext|>


<commit_before>/*=========================================================================

 Program:   Medical Imaging & Interaction Toolkit
 Language:  C++
 Date:      $Date: 2010-03-31 16:40:27 +0200 (Mi, 31 Mrz 2010) $
 Version:   $Revision: 21975 $

 Copyright (c) German Cancer Research Center, Division of Medical and
 Biological Informatics. All rights reserved.
 See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

 This software is distributed WITHOUT ANY WARRANTY; without even
 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 PURPOSE.  See the above copyright notices for more information.

 =========================================================================*/

// Blueberry
#include <berryISelectionService.h>
#include <berryIWorkbenchWindow.h>

// Qmitk
#include "QmitkFiberBundleDeveloperView.h"
#include <QmitkStdMultiWidget.h>

// Qt
#include <QString>

const std::string QmitkFiberBundleDeveloperView::VIEW_ID = "org.mitk.views.fiberbundledeveloper";
const std::string id_DataManager = "org.mitk.views.datamanager";
using namespace berry;

QmitkFiberBundleDeveloperView::QmitkFiberBundleDeveloperView()
: QmitkFunctionality()
, m_Controls( 0 )
, m_MultiWidget( NULL )
{

}

// Destructor
QmitkFiberBundleDeveloperView::~QmitkFiberBundleDeveloperView()
{

}

void QmitkFiberBundleDeveloperView::CreateQtPartControl( QWidget *parent )
{
  // build up qt view, unless already done in QtDesigner, etc.
  if ( !m_Controls )
  {
    // create GUI widgets from the Qt Designer's .ui file
    m_Controls = new Ui::QmitkFiberBundleDeveloperViewControls;
    m_Controls->setupUi( parent );

    connect( m_Controls->buttonGenerateFibers, SIGNAL(clicked()), this, SLOT(DoGenerateFibers()) );

  }

  if ( m_DirectionRadios.empty() )
  {

//    feed the vector with directionRadioButtons
    m_DirectionRadios.insert(0, m_Controls->radioButton_directionRandom);
    m_DirectionRadios.insert(1, m_Controls->radioButton_directionX);
    m_DirectionRadios.insert(2, m_Controls->radioButton_directionY);
    m_DirectionRadios.insert(3, m_Controls->radioButton_directionZ);

  }
}

void QmitkFiberBundleDeveloperView::DoGenerateFibers()
{

// GET SELECTED FIBER DIRECTION
  QStringter fibDirection;
  QVector<QRadioButton*>::const_iterator i;
  for (i = m_DirectionRadios.begin(); i != m_DirectionRadios.end(); ++i) {

    QRadioButton* rdbtn = *i;
    if (rdbtn->isChecked()) {
      fibDirection = rdbtn->objectName();
      MITK_INFO << fibDirection.toStdString() << " is checked, safe it :-)" ;
    } else {
      MITK_INFO << fibDirection.toStdString() << " is NOT checked" ;
    }
  }

}

void QmitkFiberBundleDeveloperView::StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget)
{
  m_MultiWidget = &stdMultiWidget;
}

void QmitkFiberBundleDeveloperView::StdMultiWidgetNotAvailable()
{
  m_MultiWidget = NULL;
}

/* OnSelectionChanged is registered to SelectionService, therefore no need to
 implement SelectionService Listener explicitly */

void QmitkFiberBundleDeveloperView::OnSelectionChanged( std::vector<mitk::DataNode*> nodes )
{

}

void QmitkFiberBundleDeveloperView::Activated()
{

  MITK_INFO << "FB OPerations ACTIVATED()";

}

<commit_msg>fix spelling error of datatype<commit_after>/*=========================================================================

 Program:   Medical Imaging & Interaction Toolkit
 Language:  C++
 Date:      $Date: 2010-03-31 16:40:27 +0200 (Mi, 31 Mrz 2010) $
 Version:   $Revision: 21975 $

 Copyright (c) German Cancer Research Center, Division of Medical and
 Biological Informatics. All rights reserved.
 See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

 This software is distributed WITHOUT ANY WARRANTY; without even
 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 PURPOSE.  See the above copyright notices for more information.

 =========================================================================*/

// Blueberry
#include <berryISelectionService.h>
#include <berryIWorkbenchWindow.h>

// Qmitk
#include "QmitkFiberBundleDeveloperView.h"
#include <QmitkStdMultiWidget.h>

// Qt
#include <QString>

const std::string QmitkFiberBundleDeveloperView::VIEW_ID = "org.mitk.views.fiberbundledeveloper";
const std::string id_DataManager = "org.mitk.views.datamanager";
using namespace berry;

QmitkFiberBundleDeveloperView::QmitkFiberBundleDeveloperView()
: QmitkFunctionality()
, m_Controls( 0 )
, m_MultiWidget( NULL )
{

}

// Destructor
QmitkFiberBundleDeveloperView::~QmitkFiberBundleDeveloperView()
{

}

void QmitkFiberBundleDeveloperView::CreateQtPartControl( QWidget *parent )
{
  // build up qt view, unless already done in QtDesigner, etc.
  if ( !m_Controls )
  {
    // create GUI widgets from the Qt Designer's .ui file
    m_Controls = new Ui::QmitkFiberBundleDeveloperViewControls;
    m_Controls->setupUi( parent );

    connect( m_Controls->buttonGenerateFibers, SIGNAL(clicked()), this, SLOT(DoGenerateFibers()) );

  }

  if ( m_DirectionRadios.empty() )
  {

//    feed the vector with directionRadioButtons
    m_DirectionRadios.insert(0, m_Controls->radioButton_directionRandom);
    m_DirectionRadios.insert(1, m_Controls->radioButton_directionX);
    m_DirectionRadios.insert(2, m_Controls->radioButton_directionY);
    m_DirectionRadios.insert(3, m_Controls->radioButton_directionZ);

  }
}

void QmitkFiberBundleDeveloperView::DoGenerateFibers()
{

// GET SELECTED FIBER DIRECTION
  QString fibDirection;
  QVector<QRadioButton*>::const_iterator i;
  for (i = m_DirectionRadios.begin(); i != m_DirectionRadios.end(); ++i) {

    QRadioButton* rdbtn = *i;
    if (rdbtn->isChecked()) {
      fibDirection = rdbtn->objectName();
      MITK_INFO << fibDirection.toStdString() << " is checked, safe it :-)" ;
    } else {
      MITK_INFO << fibDirection.toStdString() << " is NOT checked" ;
    }
  }

}

void QmitkFiberBundleDeveloperView::StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget)
{
  m_MultiWidget = &stdMultiWidget;
}

void QmitkFiberBundleDeveloperView::StdMultiWidgetNotAvailable()
{
  m_MultiWidget = NULL;
}

/* OnSelectionChanged is registered to SelectionService, therefore no need to
 implement SelectionService Listener explicitly */

void QmitkFiberBundleDeveloperView::OnSelectionChanged( std::vector<mitk::DataNode*> nodes )
{

}

void QmitkFiberBundleDeveloperView::Activated()
{

  MITK_INFO << "FB OPerations ACTIVATED()";

}

<|endoftext|>


<commit_before>#include <string>
#include <iostream>
#include <functional>
#include <system_error>
#include <vector>
#include <map>
#include <stdexcept>

#include <cstring>

#include <filesystem>

#include <fcntl.h>
#include <sched.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <syscall.h>
#include <pwd.h>
#include <grp.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/mount.h>
#include <sys/wait.h>
#include <sys/resource.h>

#include <fmt/format.h>
#include <fmt/ostream.h>

#include "sandbox.h"
#include "utils.h"
#include "cgroup.h"
#include "semaphore.h"
#include "pipe.h"

namespace fs = std::filesystem;
using std::string;
using std::vector;
using fmt::format;

// Make sure fd 0,1,2 exists.
static void RedirectIO(const SandboxParameter &param, int nullfd)
{
    const string &std_input = param.stdinRedirection,
                 std_output = param.stdoutRedirection,
                 std_error = param.stderrRedirection;

    int inputfd, outputfd, errorfd;
    if (param.stdinRedirectionFileDescriptor == -1)
    {
        if (std_input != "")
        {
            inputfd = ENSURE(open(std_input.c_str(), O_RDONLY));
        }
        else
        {
            inputfd = nullfd;
        }
    }
    else
    {
        inputfd = param.stdinRedirectionFileDescriptor;
    }
    ENSURE(dup2(inputfd, STDIN_FILENO));

    if (param.stdoutRedirectionFileDescriptor == -1)
    {
        if (std_output != "")
        {
            outputfd = ENSURE(open(std_output.c_str(), O_WRONLY | O_TRUNC | O_CREAT,
                                   S_IWUSR | S_IRUSR | S_IRGRP | S_IWGRP));
        }
        else
        {
            outputfd = nullfd;
        }
    }
    else
    {
        outputfd = param.stdoutRedirectionFileDescriptor;
    }
    ENSURE(dup2(outputfd, STDOUT_FILENO));

    if (param.stderrRedirectionFileDescriptor == -1)
    {
        if (std_error != "")
        {
            if (std_error == std_output)
            {
                errorfd = outputfd;
            }
            else
            {
                errorfd = ENSURE(open(std_error.c_str(), O_WRONLY | O_TRUNC | O_CREAT,
                                      S_IWUSR | S_IRUSR | S_IRGRP | S_IWGRP));
            }
        }
        else
        {
            errorfd = nullfd;
        }
    }
    else
    {
        errorfd = param.stderrRedirectionFileDescriptor;
    }
    ENSURE(dup2(errorfd, STDERR_FILENO));
}

struct ExecutionParameter
{
    const SandboxParameter &parameter;

    PosixSemaphore semaphore1, semaphore2;
    // This pipe is used to forward error message from the child process to the parent.
    PosixPipe pipefd;

    ExecutionParameter(const SandboxParameter &param, int pipeOptions) : parameter(param),
                                                                         semaphore1(true, 0),
                                                                         semaphore2(true, 0),
                                                                         pipefd(pipeOptions)
    {
    }
};

static void EnsureDirectoryExistance(fs::path dir) {
    if (!fs::exists(dir))
    {
        throw std::runtime_error((format("The specified path {} does not exist.", dir)));
    }
    if (!fs::is_directory(dir))
    {
        throw std::runtime_error((format("The specified path {} exists, but is not a directory.", dir)));
    }
}

static int ChildProcess(void *param_ptr)
{
    ExecutionParameter &execParam = *reinterpret_cast<ExecutionParameter *>(param_ptr);
    // We obtain a full copy of parameters here. The arguments may be destoryed after some time.
    SandboxParameter parameter = execParam.parameter;

    try
    {
        ENSURE(close(execParam.pipefd[0]));
        passwd *newUser = nullptr;
        if (parameter.userName != "")
        {
            // Get the user info before chroot, or it will be unable to open /etc/passwd
            newUser = CHECKNULL(getpwnam(parameter.userName.c_str()));
        }

        int nullfd = ENSURE(open("/dev/null", O_RDWR));
        if (parameter.redirectBeforeChroot)
        {
            RedirectIO(parameter, nullfd);
        }

        ENSURE(mount("none", "/", NULL, MS_REC | MS_PRIVATE, NULL)); // Make root private

        EnsureDirectoryExistance(parameter.chrootDirectory);
        ENSURE(mount(parameter.chrootDirectory.string().c_str(),
                     parameter.chrootDirectory.string().c_str(), "", MS_BIND | MS_RDONLY | MS_REC, ""));
        ENSURE(mount("", parameter.chrootDirectory.string().c_str(), "", MS_BIND | MS_REMOUNT | MS_RDONLY | MS_REC, ""));

        for (MountInfo &info : parameter.mounts)
        {
            fs::path target = parameter.chrootDirectory / info.dst;

            EnsureDirectoryExistance(info.src);
            EnsureDirectoryExistance(target);
            ENSURE(mount(info.src.string().c_str(), target.string().c_str(), "", MS_BIND | MS_REC, ""));
            if (info.limit == 0)
            {
                ENSURE(mount("", target.string().c_str(), "", MS_BIND | MS_REMOUNT | MS_RDONLY | MS_REC, ""));
            }
            else if (info.limit != -1)
            {
                // TODO: implement.
            }
        }

        ENSURE(chroot(parameter.chrootDirectory.string().c_str()));
        ENSURE(chdir(parameter.workingDirectory.string().c_str()));

        if (parameter.mountProc)
        {
            ENSURE(mount("proc", "/proc", "proc", 0, NULL));
        }
        if (!parameter.redirectBeforeChroot)
        {
            RedirectIO(parameter, nullfd);
        }

        const char *newHostname = "BraveNewWorld";
        ENSURE(sethostname(newHostname, strlen(newHostname)));

        if (parameter.stackSize != -2)
        {
            rlimit rlim;
            rlim.rlim_max = rlim.rlim_cur = parameter.stackSize != -1 ? parameter.stackSize : RLIM_INFINITY;
            ENSURE(setrlimit(RLIMIT_STACK, &rlim));
        }

        if (newUser != nullptr)
        {
            gid_t groupList[1];
            groupList[0] = newUser->pw_gid;
            ENSURE(syscall(SYS_setgid, newUser->pw_gid));
            ENSURE(syscall(SYS_setgroups, 1, groupList));
            ENSURE(syscall(SYS_setuid, newUser->pw_uid));
        }

        vector<char *> params = StringToPtr(parameter.executableParameters),
                       envi = StringToPtr(parameter.environmentVariables);

        int temp = -1;
        // Inform the parent that no exception occurred.
        ENSURE(write(execParam.pipefd[1], &temp, sizeof(int)));

        // Inform our parent that we are ready to go.
        execParam.semaphore1.Post();
        // Wait for parent's reply.
        execParam.semaphore2.Wait();

        ENSURE(execve(parameter.executablePath.c_str(), &params[0], &envi[0]));

        // If execve returns, then we meet an error.
        raise(SIGABRT);
        return 255;
    }
    catch (std::exception &err)
    {
        // TODO: implement error handling
        // abort(); // This will cause segmentation fault.
        // throw;
        // return 222;

        const char *errMessage = err.what();
        int len = strlen(errMessage);
        try
        {
            ENSURE(write(execParam.pipefd[1], &len, sizeof(int)));
            ENSURE(write(execParam.pipefd[1], errMessage, len));
            ENSURE(close(execParam.pipefd[1]));
            execParam.semaphore1.Post();
            return 126;
        }
        catch (...)
        {
            return 125;
        }
    }
    catch (...)
    {
        return 125;
    }
}

// The child stack is only used before `execve`, so it does not need much space.
const int childStackSize = 1024 * 700;
pid_t StartSandbox(const SandboxParameter &parameter
                   /* ,std::function<void(pid_t)> reportPid*/) // Let's use some fancy C++11 feature.
{
    pid_t container_pid = -1;
    try
    {
        // char* childStack = new char[childStackSize];
        std::vector<char> childStack(childStackSize); // I don't want to call `delete`

        ExecutionParameter execParam(parameter, O_CLOEXEC | O_NONBLOCK);

        container_pid = ENSURE(clone(ChildProcess, &*childStack.end(),
                                     CLONE_NEWNET | CLONE_NEWUTS | CLONE_NEWPID | CLONE_NEWNS | SIGCHLD,
                                     const_cast<void *>(reinterpret_cast<const void *>(&execParam))));

        CgroupInfo memInfo("memory", parameter.cgroupName),
            cpuInfo("cpuacct", parameter.cgroupName),
            pidInfo("pids", parameter.cgroupName);

        vector<CgroupInfo *> infos = {&memInfo, &cpuInfo, &pidInfo};
        for (auto &item : infos)
        {
            CreateGroup(*item);
            KillGroupMembers(*item);
            WriteGroupProperty(*item, "tasks", container_pid);
        }

#define WRITE_WITH_CHECK(__where, __name, __value)                  \
    {                                                               \
        if ((__value) >= 0)                                         \
        {                                                           \
            WriteGroupProperty((__where), (__name), (__value));     \
        }                                                           \
        else                                                        \
        {                                                           \
            WriteGroupProperty((__where), (__name), string("max")); \
        }                                                           \
    }

        // Forcibly clear any memory usage by cache.
        // WriteGroupProperty(memInfo, "memory.force_empty", 0); // This is too slow!!!!
        WriteGroupProperty(memInfo, "memory.memsw.limit_in_bytes", -1);
        WriteGroupProperty(memInfo, "memory.limit_in_bytes", -1);
        WRITE_WITH_CHECK(memInfo, "memory.limit_in_bytes", parameter.memoryLimit);
        WRITE_WITH_CHECK(memInfo, "memory.memsw.limit_in_bytes", parameter.memoryLimit);
        WRITE_WITH_CHECK(pidInfo, "pids.max", parameter.processLimit);

        // Wait for at most 100ms. If the child process hasn't posted the semaphore,
        // We will assume that the child has already dead.
        bool waitResult = execParam.semaphore1.TimedWait(500);

        int errLen, bytesRead = read(execParam.pipefd[0], &errLen, sizeof(int));
        // Child will be killed once the error has been thrown.
        if (!waitResult || bytesRead == 0 || bytesRead == -1)
        {
            // No information available.
            throw std::runtime_error("The child process has exited unexpectedly.");
        }
        else if (errLen != -1) // -1 indicates OK.
        {
            vector<char> buf(errLen);
            ENSURE(read(execParam.pipefd[0], &*buf.begin(), errLen));
            string errstr(buf.begin(), buf.end());
            throw std::runtime_error((format("The child process has reported the following error: {}", errstr)));
        }

        // Clear usage stats.
        WriteGroupProperty(memInfo, "memory.memsw.max_usage_in_bytes", 0);
        WriteGroupProperty(cpuInfo, "cpuacct.usage", 0);

        // Continue the child.
        execParam.semaphore2.Post();

        // Wait for 1ms to prevent the child stack deallocated before execve.
        // TODO: Find a better way to handle this.
        usleep(1000);

        return container_pid;
    }
    catch (std::exception &ex)
    {
        // Do the cleanups; we don't care whether these operations are successful.
        if (container_pid != -1)
        {
            (void)kill(container_pid, SIGKILL);
            (void)waitpid(container_pid, NULL, WNOHANG);
        }
        throw;
    }
}

ExecutionResult
SBWaitForProcess(pid_t pid)
{
    ExecutionResult result;
    int status;
    ENSURE(waitpid(pid, &status, 0));
    if (WIFEXITED(status))
    {
        result.Status = EXITED;
        result.Code = WEXITSTATUS(status);
    }
    else if (WIFSIGNALED(status))
    {
        result.Status = SIGNALED;
        result.Code = WTERMSIG(status);
    }
    return result;
}
<commit_msg>Fix wrong mount path caused by the different behavior of boost and std filesystem<commit_after>#include <string>
#include <iostream>
#include <functional>
#include <system_error>
#include <vector>
#include <map>
#include <stdexcept>

#include <cstring>

#include <filesystem>

#include <fcntl.h>
#include <sched.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <syscall.h>
#include <pwd.h>
#include <grp.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/mount.h>
#include <sys/wait.h>
#include <sys/resource.h>

#include <fmt/format.h>
#include <fmt/ostream.h>

#include "sandbox.h"
#include "utils.h"
#include "cgroup.h"
#include "semaphore.h"
#include "pipe.h"

namespace fs = std::filesystem;
using std::string;
using std::vector;
using fmt::format;

// Make sure fd 0,1,2 exists.
static void RedirectIO(const SandboxParameter &param, int nullfd)
{
    const string &std_input = param.stdinRedirection,
                 std_output = param.stdoutRedirection,
                 std_error = param.stderrRedirection;

    int inputfd, outputfd, errorfd;
    if (param.stdinRedirectionFileDescriptor == -1)
    {
        if (std_input != "")
        {
            inputfd = ENSURE(open(std_input.c_str(), O_RDONLY));
        }
        else
        {
            inputfd = nullfd;
        }
    }
    else
    {
        inputfd = param.stdinRedirectionFileDescriptor;
    }
    ENSURE(dup2(inputfd, STDIN_FILENO));

    if (param.stdoutRedirectionFileDescriptor == -1)
    {
        if (std_output != "")
        {
            outputfd = ENSURE(open(std_output.c_str(), O_WRONLY | O_TRUNC | O_CREAT,
                                   S_IWUSR | S_IRUSR | S_IRGRP | S_IWGRP));
        }
        else
        {
            outputfd = nullfd;
        }
    }
    else
    {
        outputfd = param.stdoutRedirectionFileDescriptor;
    }
    ENSURE(dup2(outputfd, STDOUT_FILENO));

    if (param.stderrRedirectionFileDescriptor == -1)
    {
        if (std_error != "")
        {
            if (std_error == std_output)
            {
                errorfd = outputfd;
            }
            else
            {
                errorfd = ENSURE(open(std_error.c_str(), O_WRONLY | O_TRUNC | O_CREAT,
                                      S_IWUSR | S_IRUSR | S_IRGRP | S_IWGRP));
            }
        }
        else
        {
            errorfd = nullfd;
        }
    }
    else
    {
        errorfd = param.stderrRedirectionFileDescriptor;
    }
    ENSURE(dup2(errorfd, STDERR_FILENO));
}

struct ExecutionParameter
{
    const SandboxParameter &parameter;

    PosixSemaphore semaphore1, semaphore2;
    // This pipe is used to forward error message from the child process to the parent.
    PosixPipe pipefd;

    ExecutionParameter(const SandboxParameter &param, int pipeOptions) : parameter(param),
                                                                         semaphore1(true, 0),
                                                                         semaphore2(true, 0),
                                                                         pipefd(pipeOptions)
    {
    }
};

static void EnsureDirectoryExistance(fs::path dir) {
    if (!fs::exists(dir))
    {
        throw std::runtime_error((format("The specified path {} does not exist.", dir)));
    }
    if (!fs::is_directory(dir))
    {
        throw std::runtime_error((format("The specified path {} exists, but is not a directory.", dir)));
    }
}

static int ChildProcess(void *param_ptr)
{
    ExecutionParameter &execParam = *reinterpret_cast<ExecutionParameter *>(param_ptr);
    // We obtain a full copy of parameters here. The arguments may be destoryed after some time.
    SandboxParameter parameter = execParam.parameter;

    try
    {
        ENSURE(close(execParam.pipefd[0]));
        passwd *newUser = nullptr;
        if (parameter.userName != "")
        {
            // Get the user info before chroot, or it will be unable to open /etc/passwd
            newUser = CHECKNULL(getpwnam(parameter.userName.c_str()));
        }

        int nullfd = ENSURE(open("/dev/null", O_RDWR));
        if (parameter.redirectBeforeChroot)
        {
            RedirectIO(parameter, nullfd);
        }

        ENSURE(mount("none", "/", NULL, MS_REC | MS_PRIVATE, NULL)); // Make root private

        EnsureDirectoryExistance(parameter.chrootDirectory);
        ENSURE(mount(parameter.chrootDirectory.string().c_str(),
                     parameter.chrootDirectory.string().c_str(), "", MS_BIND | MS_RDONLY | MS_REC, ""));
        ENSURE(mount("", parameter.chrootDirectory.string().c_str(), "", MS_BIND | MS_REMOUNT | MS_RDONLY | MS_REC, ""));

        for (MountInfo &info : parameter.mounts)
        {
            if (!info.dst.is_absolute()) {
                throw std::invalid_argument(format("The dst path {} in mounts should be absolute.", info.dst));
            }

            fs::path target = parameter.chrootDirectory / std::filesystem::relative(info.dst, "/");

            EnsureDirectoryExistance(info.src);
            EnsureDirectoryExistance(target);
            ENSURE(mount(info.src.string().c_str(), target.string().c_str(), "", MS_BIND | MS_REC, ""));
            if (info.limit == 0)
            {
                ENSURE(mount("", target.string().c_str(), "", MS_BIND | MS_REMOUNT | MS_RDONLY | MS_REC, ""));
            }
            else if (info.limit != -1)
            {
                // TODO: implement.
            }
        }

        ENSURE(chroot(parameter.chrootDirectory.string().c_str()));
        ENSURE(chdir(parameter.workingDirectory.string().c_str()));

        if (parameter.mountProc)
        {
            ENSURE(mount("proc", "/proc", "proc", 0, NULL));
        }
        if (!parameter.redirectBeforeChroot)
        {
            RedirectIO(parameter, nullfd);
        }

        const char *newHostname = "BraveNewWorld";
        ENSURE(sethostname(newHostname, strlen(newHostname)));

        if (parameter.stackSize != -2)
        {
            rlimit rlim;
            rlim.rlim_max = rlim.rlim_cur = parameter.stackSize != -1 ? parameter.stackSize : RLIM_INFINITY;
            ENSURE(setrlimit(RLIMIT_STACK, &rlim));
        }

        if (newUser != nullptr)
        {
            gid_t groupList[1];
            groupList[0] = newUser->pw_gid;
            ENSURE(syscall(SYS_setgid, newUser->pw_gid));
            ENSURE(syscall(SYS_setgroups, 1, groupList));
            ENSURE(syscall(SYS_setuid, newUser->pw_uid));
        }

        vector<char *> params = StringToPtr(parameter.executableParameters),
                       envi = StringToPtr(parameter.environmentVariables);

        int temp = -1;
        // Inform the parent that no exception occurred.
        ENSURE(write(execParam.pipefd[1], &temp, sizeof(int)));

        // Inform our parent that we are ready to go.
        execParam.semaphore1.Post();
        // Wait for parent's reply.
        execParam.semaphore2.Wait();

        ENSURE(execve(parameter.executablePath.c_str(), &params[0], &envi[0]));

        // If execve returns, then we meet an error.
        raise(SIGABRT);
        return 255;
    }
    catch (std::exception &err)
    {
        // TODO: implement error handling
        // abort(); // This will cause segmentation fault.
        // throw;
        // return 222;

        const char *errMessage = err.what();
        int len = strlen(errMessage);
        try
        {
            ENSURE(write(execParam.pipefd[1], &len, sizeof(int)));
            ENSURE(write(execParam.pipefd[1], errMessage, len));
            ENSURE(close(execParam.pipefd[1]));
            execParam.semaphore1.Post();
            return 126;
        }
        catch (...)
        {
            return 125;
        }
    }
    catch (...)
    {
        return 125;
    }
}

// The child stack is only used before `execve`, so it does not need much space.
const int childStackSize = 1024 * 700;
pid_t StartSandbox(const SandboxParameter &parameter
                   /* ,std::function<void(pid_t)> reportPid*/) // Let's use some fancy C++11 feature.
{
    pid_t container_pid = -1;
    try
    {
        // char* childStack = new char[childStackSize];
        std::vector<char> childStack(childStackSize); // I don't want to call `delete`

        ExecutionParameter execParam(parameter, O_CLOEXEC | O_NONBLOCK);

        container_pid = ENSURE(clone(ChildProcess, &*childStack.end(),
                                     CLONE_NEWNET | CLONE_NEWUTS | CLONE_NEWPID | CLONE_NEWNS | SIGCHLD,
                                     const_cast<void *>(reinterpret_cast<const void *>(&execParam))));

        CgroupInfo memInfo("memory", parameter.cgroupName),
            cpuInfo("cpuacct", parameter.cgroupName),
            pidInfo("pids", parameter.cgroupName);

        vector<CgroupInfo *> infos = {&memInfo, &cpuInfo, &pidInfo};
        for (auto &item : infos)
        {
            CreateGroup(*item);
            KillGroupMembers(*item);
            WriteGroupProperty(*item, "tasks", container_pid);
        }

#define WRITE_WITH_CHECK(__where, __name, __value)                  \
    {                                                               \
        if ((__value) >= 0)                                         \
        {                                                           \
            WriteGroupProperty((__where), (__name), (__value));     \
        }                                                           \
        else                                                        \
        {                                                           \
            WriteGroupProperty((__where), (__name), string("max")); \
        }                                                           \
    }

        // Forcibly clear any memory usage by cache.
        // WriteGroupProperty(memInfo, "memory.force_empty", 0); // This is too slow!!!!
        WriteGroupProperty(memInfo, "memory.memsw.limit_in_bytes", -1);
        WriteGroupProperty(memInfo, "memory.limit_in_bytes", -1);
        WRITE_WITH_CHECK(memInfo, "memory.limit_in_bytes", parameter.memoryLimit);
        WRITE_WITH_CHECK(memInfo, "memory.memsw.limit_in_bytes", parameter.memoryLimit);
        WRITE_WITH_CHECK(pidInfo, "pids.max", parameter.processLimit);

        // Wait for at most 100ms. If the child process hasn't posted the semaphore,
        // We will assume that the child has already dead.
        bool waitResult = execParam.semaphore1.TimedWait(500);

        int errLen, bytesRead = read(execParam.pipefd[0], &errLen, sizeof(int));
        // Child will be killed once the error has been thrown.
        if (!waitResult || bytesRead == 0 || bytesRead == -1)
        {
            // No information available.
            throw std::runtime_error("The child process has exited unexpectedly.");
        }
        else if (errLen != -1) // -1 indicates OK.
        {
            vector<char> buf(errLen);
            ENSURE(read(execParam.pipefd[0], &*buf.begin(), errLen));
            string errstr(buf.begin(), buf.end());
            throw std::runtime_error((format("The child process has reported the following error: {}", errstr)));
        }

        // Clear usage stats.
        WriteGroupProperty(memInfo, "memory.memsw.max_usage_in_bytes", 0);
        WriteGroupProperty(cpuInfo, "cpuacct.usage", 0);

        // Continue the child.
        execParam.semaphore2.Post();

        // Wait for 1ms to prevent the child stack deallocated before execve.
        // TODO: Find a better way to handle this.
        usleep(1000);

        return container_pid;
    }
    catch (std::exception &ex)
    {
        // Do the cleanups; we don't care whether these operations are successful.
        if (container_pid != -1)
        {
            (void)kill(container_pid, SIGKILL);
            (void)waitpid(container_pid, NULL, WNOHANG);
        }
        throw;
    }
}

ExecutionResult
SBWaitForProcess(pid_t pid)
{
    ExecutionResult result;
    int status;
    ENSURE(waitpid(pid, &status, 0));
    if (WIFEXITED(status))
    {
        result.Status = EXITED;
        result.Code = WEXITSTATUS(status);
    }
    else if (WIFSIGNALED(status))
    {
        result.Status = SIGNALED;
        result.Code = WTERMSIG(status);
    }
    return result;
}
<|endoftext|>


<commit_before>#include <string>
#include <iostream>
#include <functional>
#include <system_error>
#include <vector>
#include <map>

#include <cstring>

#include <boost/filesystem.hpp>
#include <boost/format.hpp>

#include <fcntl.h>
#include <sched.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <syscall.h>
#include <pwd.h>
#include <grp.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/mount.h>
#include <sys/wait.h>
#include <sys/resource.h>

#include "sandbox.h"
#include "utils.h"
#include "cgroup.h"
#include "semaphore.h"
#include "pipe.h"

namespace fs = boost::filesystem;
using std::string;
using std::vector;
using boost::format;

// Make sure fd 0,1,2 exists.
static void RedirectIO(const SandboxParameter &param, int nullfd)
{
    const string &std_input = param.stdinRedirection,
                 std_output = param.stdoutRedirection,
                 std_error = param.stderrRedirection;

    int inputfd, outputfd, errorfd;
    if (param.stdinRedirectionFileDescriptor == -1)
    {
        if (std_input != "")
        {
            inputfd = Ensure(open(std_input.c_str(), O_RDONLY));
        }
        else
        {
            inputfd = nullfd;
        }
    }
    else
    {
        inputfd = param.stdinRedirectionFileDescriptor;
    }
    Ensure(dup2(inputfd, STDIN_FILENO));

    if (param.stdoutRedirectionFileDescriptor == -1)
    {
        if (std_output != "")
        {
            outputfd = Ensure(open(std_output.c_str(), O_WRONLY | O_TRUNC | O_CREAT,
                                   S_IWUSR | S_IRUSR | S_IRGRP | S_IWGRP));
        }
        else
        {
            outputfd = nullfd;
        }
    }
    else
    {
        outputfd = param.stdoutRedirectionFileDescriptor;
    }
    Ensure(dup2(outputfd, STDOUT_FILENO));

    if (param.stderrRedirectionFileDescriptor == -1)
    {
        if (std_error != "")
        {
            if (std_error == std_output)
            {
                errorfd = outputfd;
            }
            else
            {
                errorfd = Ensure(open(std_error.c_str(), O_WRONLY | O_TRUNC | O_CREAT,
                                      S_IWUSR | S_IRUSR | S_IRGRP | S_IWGRP));
            }
        }
        else
        {
            errorfd = nullfd;
        }
    }
    else
    {
        errorfd = param.stderrRedirectionFileDescriptor;
    }
    Ensure(dup2(errorfd, STDERR_FILENO));
}

struct ExecutionParameter
{
    const SandboxParameter &parameter;

    PosixSemaphore semaphore1, semaphore2;
    // This pipe is used to forward error message from the child process to the parent.
    PosixPipe pipefd;

    ExecutionParameter(const SandboxParameter &param, int pipeOptions) : parameter(param),
                                                                         semaphore1(true, 0),
                                                                         semaphore2(true, 0),
                                                                         pipefd(pipeOptions)
    {
    }
};

static int ChildProcess(void *param_ptr)
{
    ExecutionParameter &execParam = *reinterpret_cast<ExecutionParameter *>(param_ptr);
    // We obtain a full copy of parameters here. The arguments may be destoryed after some time.
    SandboxParameter parameter = execParam.parameter;

    try
    {
        Ensure(close(execParam.pipefd[0]));
        passwd *newUser = nullptr;
        if (parameter.userName != "")
        {
            // Get the user info before chroot, or it will be unable to open /etc/passwd
            newUser = CheckNull(getpwnam(parameter.userName.c_str()));
        }

        int nullfd = Ensure(open("/dev/null", O_RDWR));
        if (parameter.redirectBeforeChroot)
        {
            RedirectIO(parameter, nullfd);
        }

        Ensure(mount("none", "/", NULL, MS_REC | MS_PRIVATE, NULL)); // Make root private

        Ensure(mount(parameter.chrootDirectory.string().c_str(),
                     parameter.chrootDirectory.string().c_str(), "", MS_BIND | MS_RDONLY | MS_REC, ""));
        Ensure(mount("", parameter.chrootDirectory.string().c_str(), "", MS_BIND | MS_REMOUNT | MS_RDONLY | MS_REC, ""));

        for (MountInfo &info : parameter.mounts)
        {
            fs::path target = parameter.chrootDirectory / info.dst;
            Ensure(mount(info.src.string().c_str(), target.string().c_str(), "", MS_BIND | MS_REC, ""));
            if (info.limit == 0)
            {
                Ensure(mount("", target.string().c_str(), "", MS_BIND | MS_REMOUNT | MS_RDONLY | MS_REC, ""));
            }
            else if (info.limit != -1)
            {
                // TODO: implement.
            }
        }

        Ensure(chroot(parameter.chrootDirectory.string().c_str()));
        Ensure(chdir(parameter.workingDirectory.string().c_str()));

        if (parameter.mountProc)
        {
            Ensure(mount("proc", "/proc", "proc", 0, NULL));
        }
        if (!parameter.redirectBeforeChroot)
        {
            RedirectIO(parameter, nullfd);
        }

        const char *newHostname = "BraveNewWorld";
        Ensure(sethostname(newHostname, strlen(newHostname)));

        if (parameter.stackSize != -2)
        {
            rlimit rlim;
            rlim.rlim_max = rlim.rlim_cur = parameter.stackSize != -1 ? parameter.stackSize : RLIM_INFINITY;
            Ensure(setrlimit(RLIMIT_STACK, &rlim));
        }

        if (newUser != nullptr)
        {
            gid_t groupList[1];
            groupList[0] = newUser->pw_gid;
            Ensure(syscall(SYS_setgid, newUser->pw_gid));
            Ensure(syscall(SYS_setgroups, 1, groupList));
            Ensure(syscall(SYS_setuid, newUser->pw_uid));
        }

        vector<char *> params = StringToPtr(parameter.executableParameters),
                       envi = StringToPtr(parameter.environmentVariables);

        int temp = -1;
        // Inform the parent that no exception occurred.
        Ensure(write(execParam.pipefd[1], &temp, sizeof(int)));

        // Inform our parent that we are ready to go.
        execParam.semaphore1.Post();
        // Wait for parent's reply.
        execParam.semaphore2.Wait();

        Ensure(execve(parameter.executablePath.c_str(), &params[0], &envi[0]));

        // If execve returns, then we meet an error.
        raise(SIGABRT);
        return 255;
    }
    catch (std::exception &err)
    {
        // TODO: implement error handling
        // abort(); // This will cause segmentation fault.
        // throw;
        // return 222;

        const char *errMessage = err.what();
        int len = strlen(errMessage);
        try
        {
            Ensure(write(execParam.pipefd[1], &len, sizeof(int)));
            Ensure(write(execParam.pipefd[1], errMessage, len));
            Ensure(close(execParam.pipefd[1]));
            execParam.semaphore1.Post();
            return 126;
        }
        catch (...)
        {
            return 125;
        }
    }
    catch (...)
    {
        return 125;
    }
}

// The child stack is only used before `execve`, so it does not need much space.
const int childStackSize = 1024 * 700;
pid_t StartSandbox(const SandboxParameter &parameter
                   /* ,std::function<void(pid_t)> reportPid*/) // Let's use some fancy C++11 feature.
{
    pid_t container_pid = -1;
    try
    {
        // char* childStack = new char[childStackSize];
        std::vector<char> childStack(childStackSize); // I don't want to call `delete`

        ExecutionParameter execParam(parameter, O_CLOEXEC | O_NONBLOCK);

        container_pid = Ensure(clone(ChildProcess, &*childStack.end(),
                                     CLONE_NEWNET | CLONE_NEWUTS | CLONE_NEWPID | CLONE_NEWNS | SIGCHLD,
                                     const_cast<void *>(reinterpret_cast<const void *>(&execParam))));

        CgroupInfo memInfo("memory", parameter.cgroupName),
            cpuInfo("cpuacct", parameter.cgroupName),
            pidInfo("pids", parameter.cgroupName);

        vector<CgroupInfo *> infos = {&memInfo, &cpuInfo, &pidInfo};
        for (auto &item : infos)
        {
            CreateGroup(*item);
            KillGroupMembers(*item);
            WriteGroupProperty(*item, "tasks", container_pid);
        }

#define WRITE_WITH_CHECK(__where, __name, __value)                  \
    {                                                               \
        if ((__value) >= 0)                                         \
        {                                                           \
            WriteGroupProperty((__where), (__name), (__value));     \
        }                                                           \
        else                                                        \
        {                                                           \
            WriteGroupProperty((__where), (__name), string("max")); \
        }                                                           \
    }

        // Forcibly clear any memory usage by cache.
        // WriteGroupProperty(memInfo, "memory.force_empty", 0); // This is too slow!!!!
        WriteGroupProperty(memInfo, "memory.memsw.limit_in_bytes", -1);
        WriteGroupProperty(memInfo, "memory.limit_in_bytes", -1);
        WRITE_WITH_CHECK(memInfo, "memory.limit_in_bytes", parameter.memoryLimit);
        WRITE_WITH_CHECK(memInfo, "memory.memsw.limit_in_bytes", parameter.memoryLimit);
        WRITE_WITH_CHECK(pidInfo, "pids.max", parameter.processLimit);

        // Wait for at most 100ms. If the child process hasn't posted the semaphore,
        // We will assume that the child has already dead.
        bool waitResult = execParam.semaphore1.TimedWait(100);

        int errLen, bytesRead = read(execParam.pipefd[0], &errLen, sizeof(int));
        // Child will be killed once the error has been thrown.
        if (!waitResult || bytesRead == 0 || bytesRead == -1)
        {
            // No information available.
            throw std::runtime_error("The child process has exited unexpectedly.");
        }
        else if (errLen != -1) // -1 indicates OK.
        {
            vector<char> buf(errLen);
            Ensure(read(execParam.pipefd[0], &*buf.begin(), errLen));
            string errstr(buf.begin(), buf.end());
            throw std::runtime_error((format("The child process has reported the following error: %1%") % errstr).str());
        }

        // Clear usage stats.
        WriteGroupProperty(memInfo, "memory.memsw.max_usage_in_bytes", 0);
        WriteGroupProperty(cpuInfo, "cpuacct.usage", 0);

        // Continue the child.
        execParam.semaphore2.Post();

        // Wait for 1ms to prevent the child stack deallocated before execve.
        // TODO: Find a better way to handle this.
        usleep(1000);

        return container_pid;
    }
    catch (std::exception &ex)
    {
        // Do the cleanups; we don't care whether these operations are successful.
        if (container_pid != -1)
        {
            (void)kill(container_pid, SIGKILL);
            (void)waitpid(container_pid, NULL, WNOHANG);
        }
        throw;
    }
}

ExecutionResult
SBWaitForProcess(pid_t pid)
{
    ExecutionResult result;
    int status;
    Ensure(waitpid(pid, &status, 0));
    if (WIFEXITED(status))
    {
        result.Status = EXITED;
        result.Code = WEXITSTATUS(status);
    }
    else if (WIFSIGNALED(status))
    {
        result.Status = SIGNALED;
        result.Code = WTERMSIG(status);
    }
    return result;
}
<commit_msg>Give more friendly information when path does not exist.<commit_after>#include <string>
#include <iostream>
#include <functional>
#include <system_error>
#include <vector>
#include <map>
#include <stdexcept>

#include <cstring>

#include <boost/filesystem.hpp>
#include <boost/format.hpp>

#include <fcntl.h>
#include <sched.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <syscall.h>
#include <pwd.h>
#include <grp.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/mount.h>
#include <sys/wait.h>
#include <sys/resource.h>

#include "sandbox.h"
#include "utils.h"
#include "cgroup.h"
#include "semaphore.h"
#include "pipe.h"

namespace fs = boost::filesystem;
using std::string;
using std::vector;
using boost::format;

// Make sure fd 0,1,2 exists.
static void RedirectIO(const SandboxParameter &param, int nullfd)
{
    const string &std_input = param.stdinRedirection,
                 std_output = param.stdoutRedirection,
                 std_error = param.stderrRedirection;

    int inputfd, outputfd, errorfd;
    if (param.stdinRedirectionFileDescriptor == -1)
    {
        if (std_input != "")
        {
            inputfd = Ensure(open(std_input.c_str(), O_RDONLY));
        }
        else
        {
            inputfd = nullfd;
        }
    }
    else
    {
        inputfd = param.stdinRedirectionFileDescriptor;
    }
    Ensure(dup2(inputfd, STDIN_FILENO));

    if (param.stdoutRedirectionFileDescriptor == -1)
    {
        if (std_output != "")
        {
            outputfd = Ensure(open(std_output.c_str(), O_WRONLY | O_TRUNC | O_CREAT,
                                   S_IWUSR | S_IRUSR | S_IRGRP | S_IWGRP));
        }
        else
        {
            outputfd = nullfd;
        }
    }
    else
    {
        outputfd = param.stdoutRedirectionFileDescriptor;
    }
    Ensure(dup2(outputfd, STDOUT_FILENO));

    if (param.stderrRedirectionFileDescriptor == -1)
    {
        if (std_error != "")
        {
            if (std_error == std_output)
            {
                errorfd = outputfd;
            }
            else
            {
                errorfd = Ensure(open(std_error.c_str(), O_WRONLY | O_TRUNC | O_CREAT,
                                      S_IWUSR | S_IRUSR | S_IRGRP | S_IWGRP));
            }
        }
        else
        {
            errorfd = nullfd;
        }
    }
    else
    {
        errorfd = param.stderrRedirectionFileDescriptor;
    }
    Ensure(dup2(errorfd, STDERR_FILENO));
}

struct ExecutionParameter
{
    const SandboxParameter &parameter;

    PosixSemaphore semaphore1, semaphore2;
    // This pipe is used to forward error message from the child process to the parent.
    PosixPipe pipefd;

    ExecutionParameter(const SandboxParameter &param, int pipeOptions) : parameter(param),
                                                                         semaphore1(true, 0),
                                                                         semaphore2(true, 0),
                                                                         pipefd(pipeOptions)
    {
    }
};

static void EnsureDirectoryExistance(fs::path dir) {
    if (!fs::exists(dir))
    {
        throw std::runtime_error((format("The specified path %1% does not exist.") % dir).str());
    }
    if (!fs::is_directory(dir))
    {
        throw std::runtime_error((format("The specified path %1% exists, but is not a directory.") % dir).str());
    }
}

static int ChildProcess(void *param_ptr)
{
    ExecutionParameter &execParam = *reinterpret_cast<ExecutionParameter *>(param_ptr);
    // We obtain a full copy of parameters here. The arguments may be destoryed after some time.
    SandboxParameter parameter = execParam.parameter;

    try
    {
        Ensure(close(execParam.pipefd[0]));
        passwd *newUser = nullptr;
        if (parameter.userName != "")
        {
            // Get the user info before chroot, or it will be unable to open /etc/passwd
            newUser = CheckNull(getpwnam(parameter.userName.c_str()));
        }

        int nullfd = Ensure(open("/dev/null", O_RDWR));
        if (parameter.redirectBeforeChroot)
        {
            RedirectIO(parameter, nullfd);
        }

        Ensure(mount("none", "/", NULL, MS_REC | MS_PRIVATE, NULL)); // Make root private

        EnsureDirectoryExistance(parameter.chrootDirectory);
        Ensure(mount(parameter.chrootDirectory.string().c_str(),
                     parameter.chrootDirectory.string().c_str(), "", MS_BIND | MS_RDONLY | MS_REC, ""));
        Ensure(mount("", parameter.chrootDirectory.string().c_str(), "", MS_BIND | MS_REMOUNT | MS_RDONLY | MS_REC, ""));

        for (MountInfo &info : parameter.mounts)
        {
            fs::path target = parameter.chrootDirectory / info.dst;

            EnsureDirectoryExistance(info.src);
            EnsureDirectoryExistance(target);
            Ensure(mount(info.src.string().c_str(), target.string().c_str(), "", MS_BIND | MS_REC, ""));
            if (info.limit == 0)
            {
                Ensure(mount("", target.string().c_str(), "", MS_BIND | MS_REMOUNT | MS_RDONLY | MS_REC, ""));
            }
            else if (info.limit != -1)
            {
                // TODO: implement.
            }
        }

        Ensure(chroot(parameter.chrootDirectory.string().c_str()));
        Ensure(chdir(parameter.workingDirectory.string().c_str()));

        if (parameter.mountProc)
        {
            Ensure(mount("proc", "/proc", "proc", 0, NULL));
        }
        if (!parameter.redirectBeforeChroot)
        {
            RedirectIO(parameter, nullfd);
        }

        const char *newHostname = "BraveNewWorld";
        Ensure(sethostname(newHostname, strlen(newHostname)));

        if (parameter.stackSize != -2)
        {
            rlimit rlim;
            rlim.rlim_max = rlim.rlim_cur = parameter.stackSize != -1 ? parameter.stackSize : RLIM_INFINITY;
            Ensure(setrlimit(RLIMIT_STACK, &rlim));
        }

        if (newUser != nullptr)
        {
            gid_t groupList[1];
            groupList[0] = newUser->pw_gid;
            Ensure(syscall(SYS_setgid, newUser->pw_gid));
            Ensure(syscall(SYS_setgroups, 1, groupList));
            Ensure(syscall(SYS_setuid, newUser->pw_uid));
        }

        vector<char *> params = StringToPtr(parameter.executableParameters),
                       envi = StringToPtr(parameter.environmentVariables);

        int temp = -1;
        // Inform the parent that no exception occurred.
        Ensure(write(execParam.pipefd[1], &temp, sizeof(int)));

        // Inform our parent that we are ready to go.
        execParam.semaphore1.Post();
        // Wait for parent's reply.
        execParam.semaphore2.Wait();

        Ensure(execve(parameter.executablePath.c_str(), &params[0], &envi[0]));

        // If execve returns, then we meet an error.
        raise(SIGABRT);
        return 255;
    }
    catch (std::exception &err)
    {
        // TODO: implement error handling
        // abort(); // This will cause segmentation fault.
        // throw;
        // return 222;

        const char *errMessage = err.what();
        int len = strlen(errMessage);
        try
        {
            Ensure(write(execParam.pipefd[1], &len, sizeof(int)));
            Ensure(write(execParam.pipefd[1], errMessage, len));
            Ensure(close(execParam.pipefd[1]));
            execParam.semaphore1.Post();
            return 126;
        }
        catch (...)
        {
            return 125;
        }
    }
    catch (...)
    {
        return 125;
    }
}

// The child stack is only used before `execve`, so it does not need much space.
const int childStackSize = 1024 * 700;
pid_t StartSandbox(const SandboxParameter &parameter
                   /* ,std::function<void(pid_t)> reportPid*/) // Let's use some fancy C++11 feature.
{
    pid_t container_pid = -1;
    try
    {
        // char* childStack = new char[childStackSize];
        std::vector<char> childStack(childStackSize); // I don't want to call `delete`

        ExecutionParameter execParam(parameter, O_CLOEXEC | O_NONBLOCK);

        container_pid = Ensure(clone(ChildProcess, &*childStack.end(),
                                     CLONE_NEWNET | CLONE_NEWUTS | CLONE_NEWPID | CLONE_NEWNS | SIGCHLD,
                                     const_cast<void *>(reinterpret_cast<const void *>(&execParam))));

        CgroupInfo memInfo("memory", parameter.cgroupName),
            cpuInfo("cpuacct", parameter.cgroupName),
            pidInfo("pids", parameter.cgroupName);

        vector<CgroupInfo *> infos = {&memInfo, &cpuInfo, &pidInfo};
        for (auto &item : infos)
        {
            CreateGroup(*item);
            KillGroupMembers(*item);
            WriteGroupProperty(*item, "tasks", container_pid);
        }

#define WRITE_WITH_CHECK(__where, __name, __value)                  \
    {                                                               \
        if ((__value) >= 0)                                         \
        {                                                           \
            WriteGroupProperty((__where), (__name), (__value));     \
        }                                                           \
        else                                                        \
        {                                                           \
            WriteGroupProperty((__where), (__name), string("max")); \
        }                                                           \
    }

        // Forcibly clear any memory usage by cache.
        // WriteGroupProperty(memInfo, "memory.force_empty", 0); // This is too slow!!!!
        WriteGroupProperty(memInfo, "memory.memsw.limit_in_bytes", -1);
        WriteGroupProperty(memInfo, "memory.limit_in_bytes", -1);
        WRITE_WITH_CHECK(memInfo, "memory.limit_in_bytes", parameter.memoryLimit);
        WRITE_WITH_CHECK(memInfo, "memory.memsw.limit_in_bytes", parameter.memoryLimit);
        WRITE_WITH_CHECK(pidInfo, "pids.max", parameter.processLimit);

        // Wait for at most 100ms. If the child process hasn't posted the semaphore,
        // We will assume that the child has already dead.
        bool waitResult = execParam.semaphore1.TimedWait(100);

        int errLen, bytesRead = read(execParam.pipefd[0], &errLen, sizeof(int));
        // Child will be killed once the error has been thrown.
        if (!waitResult || bytesRead == 0 || bytesRead == -1)
        {
            // No information available.
            throw std::runtime_error("The child process has exited unexpectedly.");
        }
        else if (errLen != -1) // -1 indicates OK.
        {
            vector<char> buf(errLen);
            Ensure(read(execParam.pipefd[0], &*buf.begin(), errLen));
            string errstr(buf.begin(), buf.end());
            throw std::runtime_error((format("The child process has reported the following error: %1%") % errstr).str());
        }

        // Clear usage stats.
        WriteGroupProperty(memInfo, "memory.memsw.max_usage_in_bytes", 0);
        WriteGroupProperty(cpuInfo, "cpuacct.usage", 0);

        // Continue the child.
        execParam.semaphore2.Post();

        // Wait for 1ms to prevent the child stack deallocated before execve.
        // TODO: Find a better way to handle this.
        usleep(1000);

        return container_pid;
    }
    catch (std::exception &ex)
    {
        // Do the cleanups; we don't care whether these operations are successful.
        if (container_pid != -1)
        {
            (void)kill(container_pid, SIGKILL);
            (void)waitpid(container_pid, NULL, WNOHANG);
        }
        throw;
    }
}

ExecutionResult
SBWaitForProcess(pid_t pid)
{
    ExecutionResult result;
    int status;
    Ensure(waitpid(pid, &status, 0));
    if (WIFEXITED(status))
    {
        result.Status = EXITED;
        result.Code = WEXITSTATUS(status);
    }
    else if (WIFSIGNALED(status))
    {
        result.Status = SIGNALED;
        result.Code = WTERMSIG(status);
    }
    return result;
}
<|endoftext|>