<commit_before>/**
 * Copyright (c) Sjors Gielen, 2010
 * See LICENSE for license.
 */

#include "config.h"

/**
 * @brief Constructor
 *
 * This constructor sets default configuration. A new Config object is usable,
 * but will not contain any networks or servers.
 */
Config::Config()
: QObject()
, nickName_( "DaVinci" )
, error_( "" )
{
}

/**
 * @brief Returns the last error triggered by this class.
 *
 * If there was no error, returns an empty string.
 */
const QString &Config::lastError()
{
  return error_;
}

/**
 * @brief Load configuration from file.
 *
 * This method attempts to load all contents from the given file to the Config
 * object, then returns whether that worked or not.
 */
bool Config::loadFromFile( QString fileName )
{
  oldNetworks_ = networks_;
  networks_.clear();
  error_ = "";

  emit beforeConfigReload();

  // load!
  if( 0 )
  {
    emit configReloadFailed();
    return false;
  }

  emit configReloaded();
  return true;
}

const QList<NetworkConfig*> &Config::networks()
{
  // TODO remove later
  if( networks_.count() > 0 )
    return networks_;
  ServerConfig *sc;
  NetworkConfig *nc;

  // Temporary network config for localhost
  nc = new NetworkConfig;
  nc->name = "localhost";
  nc->displayName = "Localhost";
  nc->autoConnect = true;
  nc->nickName = nickName_;
  sc = new ServerConfig;
  sc->host = "localhost";
  sc->port = 6667;
  sc->priority = 5;
  sc->ssl = false;
  sc->network = nc;
  nc->servers.append( sc );
  networks_.append( nc );

  // Temporary network config for Tweakers
  nc = new NetworkConfig;
  nc->name = "tweakers";
  nc->displayName = "Tweakers";
  nc->autoConnect = true;
  nc->nickName = nickName_;
  sc = new ServerConfig;
  sc->host = "irc.tweakers.net";
  sc->port = 6667;
  sc->priority = 5;
  sc->ssl = false;
  sc->network = nc;
  nc->servers.append( sc );
  networks_.append( nc );

  // Temporary network config for Freenode
  nc = new NetworkConfig;
  nc->name = "freenode";
  nc->displayName = "FweaNers";
  nc->autoConnect = false;
  nc->nickName = nickName_;
  sc = new ServerConfig;
  sc->host = "anthony.freenode.net";
  sc->port = 6667;
  sc->priority = 5;
  sc->ssl = false;
  sc->network = nc;
  nc->servers.append( sc );
  sc = new ServerConfig;
  sc->host = "wolfe.freenode.net";
  sc->port = 6667;
  sc->priority = 5;
  sc->ssl = false;
  sc->network = nc;
  nc->servers.append( sc );
  sc = new ServerConfig;
  sc->host = "2001:1418:13:1::25";
  sc->port = 6667;
  sc->priority = 10;
  sc->ssl = false;
  sc->network = nc;
  nc->servers.append( sc );
  networks_.append( nc );

  return networks_;
}
<commit_msg>Made DaVinci join FreeNode automatically (and fixed network name)<commit_after>/**
 * Copyright (c) Sjors Gielen, 2010
 * See LICENSE for license.
 */

#include "config.h"

/**
 * @brief Constructor
 *
 * This constructor sets default configuration. A new Config object is usable,
 * but will not contain any networks or servers.
 */
Config::Config()
: QObject()
, nickName_( "DaVinci" )
, error_( "" )
{
}

/**
 * @brief Returns the last error triggered by this class.
 *
 * If there was no error, returns an empty string.
 */
const QString &Config::lastError()
{
  return error_;
}

/**
 * @brief Load configuration from file.
 *
 * This method attempts to load all contents from the given file to the Config
 * object, then returns whether that worked or not.
 */
bool Config::loadFromFile( QString fileName )
{
  oldNetworks_ = networks_;
  networks_.clear();
  error_ = "";

  emit beforeConfigReload();

  // load!
  if( 0 )
  {
    emit configReloadFailed();
    return false;
  }

  emit configReloaded();
  return true;
}

const QList<NetworkConfig*> &Config::networks()
{
  // TODO remove later
  if( networks_.count() > 0 )
    return networks_;
  ServerConfig *sc;
  NetworkConfig *nc;

  // Temporary network config for localhost
  nc = new NetworkConfig;
  nc->name = "localhost";
  nc->displayName = "Localhost";
  nc->autoConnect = true;
  nc->nickName = nickName_;
  sc = new ServerConfig;
  sc->host = "localhost";
  sc->port = 6667;
  sc->priority = 5;
  sc->ssl = false;
  sc->network = nc;
  nc->servers.append( sc );
  networks_.append( nc );

  // Temporary network config for Tweakers
  nc = new NetworkConfig;
  nc->name = "tweakers";
  nc->displayName = "Tweakers";
  nc->autoConnect = true;
  nc->nickName = nickName_;
  sc = new ServerConfig;
  sc->host = "irc.tweakers.net";
  sc->port = 6667;
  sc->priority = 5;
  sc->ssl = false;
  sc->network = nc;
  nc->servers.append( sc );
  networks_.append( nc );

  // Temporary network config for Freenode
  nc = new NetworkConfig;
  nc->name = "freenode";
  nc->displayName = "FreeNode";
  nc->autoConnect = true;
  nc->nickName = nickName_;
  sc = new ServerConfig;
  sc->host = "anthony.freenode.net";
  sc->port = 6667;
  sc->priority = 5;
  sc->ssl = false;
  sc->network = nc;
  nc->servers.append( sc );
  sc = new ServerConfig;
  sc->host = "wolfe.freenode.net";
  sc->port = 6667;
  sc->priority = 5;
  sc->ssl = false;
  sc->network = nc;
  nc->servers.append( sc );
  sc = new ServerConfig;
  sc->host = "2001:1418:13:1::25";
  sc->port = 6667;
  sc->priority = 10;
  sc->ssl = false;
  sc->network = nc;
  nc->servers.append( sc );
  networks_.append( nc );

  return networks_;
}
<|endoftext|>


<commit_before>#line 2 "pickle/app_core/main.cpp"
/**
@copyright MIT license; see @ref index or the accompanying LICENSE file.
*/

#include <pickle/app_core/config.hpp>
#include <pickle/app_core/types.hpp>
#include <pickle/app_core/internal.hpp>

#include <togo/core/utility/utility.hpp>
#include <togo/core/log/log.hpp>
#include <togo/core/memory/memory.hpp>
#include <togo/core/filesystem/filesystem.hpp>
#include <togo/core/io/io.hpp>
#include <togo/core/lua/lua.hpp>

using namespace togo;
using namespace pickle;

namespace {

static LuaModuleFunctionArray const li_internal_funcs{
	TOGO_LI_FUNC_REF(internal, template_transform)
};

static LuaModuleRef const li_modules[]{
{
	"Pickle",
	"pickle/app_core/Pickle.lua",
	null_ref_tag{},
	#include <pickle/app_core/Pickle.lua>
},
{
	"Pickle.Interface",
	"pickle/app_core/Pickle.Interface.lua",
	null_ref_tag{},
	#include <pickle/app_core/Pickle.Interface.lua>
},
{
	"Pickle.Filter",
	"pickle/app_core/Pickle.Filter.lua",
	null_ref_tag{},
	#include <pickle/app_core/Pickle.Filter.lua>
},
{
	"Pickle.Internal",
	"pickle/app_core/Pickle.Internal.lua",
	li_internal_funcs,
	#include <pickle/app_core/Pickle.Internal.lua>
},
};

} // anonymous namespace

signed main(signed argc, char* argv[]) {
	signed ec = 0;
	memory::init();

	lua_State* L = lua::new_state();
	luaL_openlibs(L);

	lua::register_core(L);
	filesystem::register_lua_interface(L);
	io::register_lua_interface(L);

	for (auto& module : li_modules) {
		lua::preload_module(L, module);
	}

	lua::push_value(L, lua::pcall_error_message_handler);
	lua::load_module(L, "Pickle.Interface", true);
	lua::table_get_raw(L, "main");
	lua_remove(L, -2);
	lua_createtable(L, 0, argc);
	for (signed i = 0; i < argc; ++i) {
		lua::table_set_index_raw(L, i + 1, StringRef{argv[i], cstr_tag{}});
	}
	if (lua_pcall(L, 1, 1, -3)) {
		auto error = lua::get_string(L, -1);
		TOGO_LOGF("error: %.*s\n", error.size, error.data);
		ec = 2;
	} else {
		if (!lua::get_boolean(L, -1)) {
			ec = 1;
		}
	}
	lua_pop(L, 2);
	lua_close(L);
	memory::shutdown();
	return ec;
}
<commit_msg>app/core/main: register Lua interface for togo::system.<commit_after>#line 2 "pickle/app_core/main.cpp"
/**
@copyright MIT license; see @ref index or the accompanying LICENSE file.
*/

#include <pickle/app_core/config.hpp>
#include <pickle/app_core/types.hpp>
#include <pickle/app_core/internal.hpp>

#include <togo/core/utility/utility.hpp>
#include <togo/core/log/log.hpp>
#include <togo/core/memory/memory.hpp>
#include <togo/core/system/system.hpp>
#include <togo/core/filesystem/filesystem.hpp>
#include <togo/core/io/io.hpp>
#include <togo/core/lua/lua.hpp>

using namespace togo;
using namespace pickle;

namespace {

static LuaModuleFunctionArray const li_internal_funcs{
	TOGO_LI_FUNC_REF(internal, template_transform)
};

static LuaModuleRef const li_modules[]{
{
	"Pickle",
	"pickle/app_core/Pickle.lua",
	null_ref_tag{},
	#include <pickle/app_core/Pickle.lua>
},
{
	"Pickle.Interface",
	"pickle/app_core/Pickle.Interface.lua",
	null_ref_tag{},
	#include <pickle/app_core/Pickle.Interface.lua>
},
{
	"Pickle.Filter",
	"pickle/app_core/Pickle.Filter.lua",
	null_ref_tag{},
	#include <pickle/app_core/Pickle.Filter.lua>
},
{
	"Pickle.Internal",
	"pickle/app_core/Pickle.Internal.lua",
	li_internal_funcs,
	#include <pickle/app_core/Pickle.Internal.lua>
},
};

} // anonymous namespace

signed main(signed argc, char* argv[]) {
	signed ec = 0;
	memory::init();

	lua_State* L = lua::new_state();
	luaL_openlibs(L);

	lua::register_core(L);
	system::register_lua_interface(L);
	filesystem::register_lua_interface(L);
	io::register_lua_interface(L);

	for (auto& module : li_modules) {
		lua::preload_module(L, module);
	}

	lua::push_value(L, lua::pcall_error_message_handler);
	lua::load_module(L, "Pickle.Interface", true);
	lua::table_get_raw(L, "main");
	lua_remove(L, -2);
	lua_createtable(L, 0, argc);
	for (signed i = 0; i < argc; ++i) {
		lua::table_set_index_raw(L, i + 1, StringRef{argv[i], cstr_tag{}});
	}
	if (lua_pcall(L, 1, 1, -3)) {
		auto error = lua::get_string(L, -1);
		TOGO_LOGF("error: %.*s\n", error.size, error.data);
		ec = 2;
	} else {
		if (!lua::get_boolean(L, -1)) {
			ec = 1;
		}
	}
	lua_pop(L, 2);
	lua_close(L);
	memory::shutdown();
	return ec;
}
<|endoftext|>


<commit_before>#include "Window.h"

namespace hm
{
	Window::Window()
	{
		screen = SDL_SetVideoMode(640, 480, 32, SDL_SWSURFACE);
		resetClearColor();
	}

	Window::Window(int w, int h, int bpp)
	{
		screen = SDL_SetVideoMode(w, h, bpp, SDL_SWSURFACE);
		resetClearColor();
	}

	Window::Window(std::string title, int w, int h, int bpp)
	{
		screen = SDL_SetVideoMode(w, h, bpp, SDL_SWSURFACE);

		SDL_WM_SetCaption(title.c_str(), NULL);
		resetClearColor();
	}

	Window::~Window()
	{
		// Nothing to do here.
	}

    bool Window::getStatus()
    {
        return (screen != NULL);
    }

	void Window::draw(Blittable& b)
	{
		clear();
		SDL_BlitSurface(b.getSurface(), NULL, screen, b.getPosition());
		needRefresh = true;
		return;
	}

	void Window::draw(Sprite& s)
	{
		// Drawing for sprites is specially handled.
		clear();
		SDL_BlitSurface(s.getSurface(), s.getSpriteClip(), screen, s.getPosition());
		needRefresh = true; // Needs to be flipped.
		return;
	}

	void Window::clear()
	{
		// Don't clear the window if there are changes pending.
		if(!needRefresh)
			SDL_FillRect(screen, NULL, clearColor);
		return;
	}

	Uint32 Window::getClearColor()
	{
		return clearColor;
	}

	void Window::setClearColor(Uint32 clearColor)
	{
		this->clearColor = clearColor;
		return;
	}

	void Window::setClearColor(Uint8 red, Uint8 green, Uint8 blue)
	{
		clearColor = SDL_MapRGB(screen->format, red, green, blue);
		return;
	}

	void Window::resetClearColor()
	{
		// Sets the clearColor to black.
		clearColor = SDL_MapRGB(screen->format, 0x00, 0x00, 0x00);
		return;
	}

	void Window::refresh()
	{

		if(needRefresh)
		{
			SDL_Flip(screen);
			needRefresh = false;
		}

		return;
	}

	// Centers the given Blittable in the given Window.
	void center(Blittable& b, Window& w)
	{
		b.getPosition()->x = w.screen->w / 2 - b.getSurface()->w / 2;
		b.getPosition()->y = w.screen->h / 2 - b.getSurface()->h / 2;

		return;
	}

	// Centers the given Blittable on the X-Axis in the given window.
	void centerx(Blittable& b, Window& w)
	{
		b.getPosition()->x = w.screen->w / 2 - b.getSurface()->w / 2;
		return;
	}

	// Centers the given Blittable on the Y-Axis in the given window.
	void centery(Blittable& b, Window& w)
	{
		b.getPosition()->y = w.screen->h / 2 - b.getSurface()->h / 2;
		return;
	}
}
<commit_msg>Improved efficiency in Window::draw functions.<commit_after>#include "Window.h"

namespace hm
{
	Window::Window()
	{
		screen = SDL_SetVideoMode(640, 480, 32, SDL_SWSURFACE);
		resetClearColor();
	}

	Window::Window(int w, int h, int bpp)
	{
		screen = SDL_SetVideoMode(w, h, bpp, SDL_SWSURFACE);
		resetClearColor();
	}

	Window::Window(std::string title, int w, int h, int bpp)
	{
		screen = SDL_SetVideoMode(w, h, bpp, SDL_SWSURFACE);

		SDL_WM_SetCaption(title.c_str(), NULL);
		resetClearColor();
	}

	Window::~Window()
	{
		// Nothing to do here.
	}

    bool Window::getStatus()
    {
        return (screen != NULL);
    }

	void Window::draw(Blittable& b)
	{
		// Don't draw if transparent. Waste of resources.
		if(b.getAlpha() == TRANSPARENT)
			return;
		clear();
		SDL_BlitSurface(b.getSurface(), NULL, screen, b.getPosition());
		needRefresh = true;
		return;
	}

	void Window::draw(Sprite& s)
	{
		// Drawing for sprites is specially handled.
		// Don't draw if transparent. Wast of resources.
		if(s.getAlpha() == TRANSPARENT)
			return;
		clear();
		SDL_BlitSurface(s.getSurface(), s.getSpriteClip(), screen, s.getPosition());
		needRefresh = true; // Needs to be flipped.
		return;
	}

	void Window::clear()
	{
		// Don't clear the window if there are changes pending.
		if(!needRefresh)
			SDL_FillRect(screen, NULL, clearColor);
		return;
	}

	Uint32 Window::getClearColor()
	{
		return clearColor;
	}

	void Window::setClearColor(Uint32 clearColor)
	{
		this->clearColor = clearColor;
		return;
	}

	void Window::setClearColor(Uint8 red, Uint8 green, Uint8 blue)
	{
		clearColor = SDL_MapRGB(screen->format, red, green, blue);
		return;
	}

	void Window::resetClearColor()
	{
		// Sets the clearColor to black.
		clearColor = SDL_MapRGB(screen->format, 0x00, 0x00, 0x00);
		return;
	}

	void Window::refresh()
	{

		if(needRefresh)
		{
			SDL_Flip(screen);
			needRefresh = false;
		}

		return;
	}

	// Centers the given Blittable in the given Window.
	void center(Blittable& b, Window& w)
	{
		b.getPosition()->x = w.screen->w / 2 - b.getSurface()->w / 2;
		b.getPosition()->y = w.screen->h / 2 - b.getSurface()->h / 2;

		return;
	}

	// Centers the given Blittable on the X-Axis in the given window.
	void centerx(Blittable& b, Window& w)
	{
		b.getPosition()->x = w.screen->w / 2 - b.getSurface()->w / 2;
		return;
	}

	// Centers the given Blittable on the Y-Axis in the given window.
	void centery(Blittable& b, Window& w)
	{
		b.getPosition()->y = w.screen->h / 2 - b.getSurface()->h / 2;
		return;
	}
}
<|endoftext|>


<commit_before>/*
 * Minimal code using CGAL's LCC package for constructing linear cell complex of a cube
 */
#include <iostream>
#include <vector>
#include <unordered_set>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Linear_cell_complex.h>

using namespace std;
using namespace CGAL;

typedef Exact_predicates_inexact_constructions_kernel K;
typedef Linear_cell_complex<3, 3> LCC;
typedef Point_3<K> Point;
typedef LCC::Dart_handle DartHandle;

/*
bool operator == (DartHandle a, DartHandle b)
{
	// Vertex
	Point pA = cubeLCC.getPoint(a);
	Point pB = cubeLCC.getPoint(b);
	vector<vector<Point> > duplicatePoint;
	if (pA == pB)
	{
		duplicatePoint[cubeLCC.info<0>(a)].push_back(pB); // pA is already present in set
		return true;
	}
	else
		return false;
}

void removeDuplicateVertices(LCC &inputLCC)
{
	// Find duplicate n-cells
	// Put handles to each duplicate element in a vector
	unordered_set<DartHandle> cubeVertices;
	for (LCC::One_dart_per_cell_range<0>::iterator vIter = inputLCC.one_dart_per_cell<0>().begin(); vIter != inputLCC.one_dart_per_cell<0>().end(); vIter++)
		cubeVertices.insert(vIter);

	// Modify beta links of neighbors of duplicate n-cells
}

void removeDuplicateSegments(LCC &inputLCC)
{
}

*/

int main()
{
	vector<Point> cubePoints;

	// create storage for points of a cube
	cubePoints.push_back(Point(0, 0, 0)); // points of a cube
	cubePoints.push_back(Point(0, 0, 1));
	cubePoints.push_back(Point(0, 1, 0));
	cubePoints.push_back(Point(0, 1, 1));
	cubePoints.push_back(Point(1, 0, 0));
	cubePoints.push_back(Point(1, 0, 1));
	cubePoints.push_back(Point(1, 1, 0));
	cubePoints.push_back(Point(1, 1, 1));

	LCC cubeLCC;

	// add triangles representing cube to lcc
	DartHandle d1 = cubeLCC.make_triangle(cubePoints[0], cubePoints[4], cubePoints[6]);
	DartHandle d2 = cubeLCC.make_triangle(cubePoints[6], cubePoints[2], cubePoints[0]);
	DartHandle d3 = cubeLCC.make_triangle(cubePoints[4], cubePoints[5], cubePoints[7]);
	DartHandle d4 = cubeLCC.make_triangle(cubePoints[7], cubePoints[6], cubePoints[4]);
	DartHandle d5 = cubeLCC.make_triangle(cubePoints[5], cubePoints[1], cubePoints[3]);
	DartHandle d6 = cubeLCC.make_triangle(cubePoints[3], cubePoints[7], cubePoints[5]);
	DartHandle d7 = cubeLCC.make_triangle(cubePoints[2], cubePoints[3], cubePoints[1]);
	DartHandle d8 = cubeLCC.make_triangle(cubePoints[1], cubePoints[0], cubePoints[2]);
	DartHandle d9 = cubeLCC.make_triangle(cubePoints[6], cubePoints[7], cubePoints[3]);
	DartHandle d10 = cubeLCC.make_triangle(cubePoints[3], cubePoints[2], cubePoints[6]);
	DartHandle d11 = cubeLCC.make_triangle(cubePoints[0], cubePoints[1], cubePoints[5]);
	DartHandle d12 = cubeLCC.make_triangle(cubePoints[5], cubePoints[4], cubePoints[0]);

	// Gluing...
	cubeLCC.sew<2>(d1, d2);
	cubeLCC.sew<2>(d3, d4);
	cubeLCC.sew<2>(d5, d6);
	cubeLCC.sew<2>(d7, d8);
	cubeLCC.sew<2>(d9, d10);
	cubeLCC.sew<2>(d11, d12);

	cubeLCC.sew<2>(cubeLCC.beta(d1, 1), cubeLCC.beta(d4, 1));
	cubeLCC.sew<2>(cubeLCC.beta(d1, 1, 1), cubeLCC.beta(d12, 1));
	cubeLCC.sew<2>(cubeLCC.beta(d2, 1, 1), cubeLCC.beta(d8, 1));
	cubeLCC.sew<2>(cubeLCC.beta(d2, 1), cubeLCC.beta(d10, 1));	//TODO
	cubeLCC.sew<2>(cubeLCC.beta(d3, 1), cubeLCC.beta(d12, 1, 1));
	cubeLCC.sew<2>(cubeLCC.beta(d3, 1, 1), cubeLCC.beta(d6, 1));

	cubeLCC.sew<2>(cubeLCC.beta(d4, 1, 1), cubeLCC.beta(d9, 1, 1));
	cubeLCC.sew<2>(cubeLCC.beta(d5, 1, 1), cubeLCC.beta(d11, 1));
	cubeLCC.sew<2>(cubeLCC.beta(d5, 1), cubeLCC.beta(d7, 1));
	cubeLCC.sew<2>(cubeLCC.beta(d6, 1, 1), cubeLCC.beta(d9, 1));
	cubeLCC.sew<2>(cubeLCC.beta(d7, 1, 1), cubeLCC.beta(d10, 1, 1));
	cubeLCC.sew<2>(cubeLCC.beta(d8, 1, 1), cubeLCC.beta(d11, 1, 1));

	// Verify correctness
	unsigned int nVertices = 0;
	for (LCC::One_dart_per_cell_range<0>::iterator vIter = cubeLCC.one_dart_per_cell<0>().begin(); vIter != cubeLCC.one_dart_per_cell<0>().end(); vIter++)
		nVertices++;

	cout << "Number of vertices: " << nVertices << "\n";

	unsigned int nSegments = 0;
	for (LCC::One_dart_per_cell_range<1>::iterator sIter = cubeLCC.one_dart_per_cell<1>().begin(); sIter != cubeLCC.one_dart_per_cell<1>().end(); sIter++)
		nSegments++;

	cout << "Number of segments: " << nSegments << "\n";

	unsigned int nFaces = 0;
	for (LCC::One_dart_per_cell_range<2>::iterator fIter = cubeLCC.one_dart_per_cell<2>().begin(); fIter != cubeLCC.one_dart_per_cell<2>().end(); fIter++)
		nFaces++;

	cout << "Number of faces: " << nFaces << "\n";

	return 0;
}

<commit_msg>fixed wrong sewing<commit_after>/*
 * Minimal code using CGAL's LCC package for constructing linear cell complex of a cube
 */
#include <iostream>
#include <vector>
#include <unordered_set>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Linear_cell_complex.h>

using namespace std;
using namespace CGAL;

typedef Exact_predicates_inexact_constructions_kernel K;
typedef Linear_cell_complex<3, 3> LCC;
typedef Point_3<K> Point;
typedef LCC::Dart_handle DartHandle;

/*
bool operator == (DartHandle a, DartHandle b)
{
	// Vertex
	Point pA = cubeLCC.getPoint(a);
	Point pB = cubeLCC.getPoint(b);
	vector<vector<Point> > duplicatePoint;
	if (pA == pB)
	{
		duplicatePoint[cubeLCC.info<0>(a)].push_back(pB); // pA is already present in set
		return true;
	}
	else
		return false;
}

void removeDuplicateVertices(LCC &inputLCC)
{
	// Find duplicate n-cells
	// Put handles to each duplicate element in a vector
	unordered_set<DartHandle> cubeVertices;
	for (LCC::One_dart_per_cell_range<0>::iterator vIter = inputLCC.one_dart_per_cell<0>().begin(); vIter != inputLCC.one_dart_per_cell<0>().end(); vIter++)
		cubeVertices.insert(vIter);

	// Modify beta links of neighbors of duplicate n-cells
}

void removeDuplicateSegments(LCC &inputLCC)
{
}

*/

int main()
{
	vector<Point> cubePoints;

	// create storage for points of a cube
	cubePoints.push_back(Point(0, 0, 0)); // points of a cube
	cubePoints.push_back(Point(0, 0, 1));
	cubePoints.push_back(Point(0, 1, 0));
	cubePoints.push_back(Point(0, 1, 1));
	cubePoints.push_back(Point(1, 0, 0));
	cubePoints.push_back(Point(1, 0, 1));
	cubePoints.push_back(Point(1, 1, 0));
	cubePoints.push_back(Point(1, 1, 1));

	LCC cubeLCC;

	// add triangles representing cube to lcc
	DartHandle d1 = cubeLCC.make_triangle(cubePoints[0], cubePoints[4], cubePoints[6]);
	DartHandle d2 = cubeLCC.make_triangle(cubePoints[6], cubePoints[2], cubePoints[0]);
	DartHandle d3 = cubeLCC.make_triangle(cubePoints[4], cubePoints[5], cubePoints[7]);
	DartHandle d4 = cubeLCC.make_triangle(cubePoints[7], cubePoints[6], cubePoints[4]);
	DartHandle d5 = cubeLCC.make_triangle(cubePoints[5], cubePoints[1], cubePoints[3]);
	DartHandle d6 = cubeLCC.make_triangle(cubePoints[3], cubePoints[7], cubePoints[5]);
	DartHandle d7 = cubeLCC.make_triangle(cubePoints[2], cubePoints[3], cubePoints[1]);
	DartHandle d8 = cubeLCC.make_triangle(cubePoints[1], cubePoints[0], cubePoints[2]);
	DartHandle d9 = cubeLCC.make_triangle(cubePoints[6], cubePoints[7], cubePoints[3]);
	DartHandle d10 = cubeLCC.make_triangle(cubePoints[3], cubePoints[2], cubePoints[6]);
	DartHandle d11 = cubeLCC.make_triangle(cubePoints[0], cubePoints[1], cubePoints[5]);
	DartHandle d12 = cubeLCC.make_triangle(cubePoints[5], cubePoints[4], cubePoints[0]);

	// Gluing...
	cubeLCC.sew<2>(d1, d2);
	cubeLCC.sew<2>(d3, d4);
	cubeLCC.sew<2>(d5, d6);
	cubeLCC.sew<2>(d7, d8);
	cubeLCC.sew<2>(d9, d10);
	cubeLCC.sew<2>(d11, d12);

	cubeLCC.sew<2>(cubeLCC.beta(d1, 1), cubeLCC.beta(d4, 1));
	cubeLCC.sew<2>(cubeLCC.beta(d1, 1, 1), cubeLCC.beta(d12, 1));
	cubeLCC.sew<2>(cubeLCC.beta(d2, 1), cubeLCC.beta(d8, 1));
	cubeLCC.sew<2>(cubeLCC.beta(d2, 1, 1), cubeLCC.beta(d10, 1));
	cubeLCC.sew<2>(cubeLCC.beta(d3, 1, 1), cubeLCC.beta(d12, 1, 1));
	cubeLCC.sew<2>(cubeLCC.beta(d3, 1), cubeLCC.beta(d6, 1));

	cubeLCC.sew<2>(cubeLCC.beta(d4, 1, 1), cubeLCC.beta(d9, 1, 1));
	cubeLCC.sew<2>(cubeLCC.beta(d5, 1, 1), cubeLCC.beta(d11, 1));
	cubeLCC.sew<2>(cubeLCC.beta(d5, 1), cubeLCC.beta(d7, 1));
	cubeLCC.sew<2>(cubeLCC.beta(d6, 1, 1), cubeLCC.beta(d9, 1));
	cubeLCC.sew<2>(cubeLCC.beta(d7, 1, 1), cubeLCC.beta(d10, 1, 1));
	cubeLCC.sew<2>(cubeLCC.beta(d8, 1, 1), cubeLCC.beta(d11, 1, 1));

	// Verify correctness
	unsigned int nVertices = 0;
	for (LCC::One_dart_per_cell_range<0>::iterator vIter = cubeLCC.one_dart_per_cell<0>().begin(); vIter != cubeLCC.one_dart_per_cell<0>().end(); vIter++)
		nVertices++;

	cout << "Number of vertices: " << nVertices << "\n";

	unsigned int nSegments = 0;
	for (LCC::One_dart_per_cell_range<1>::iterator sIter = cubeLCC.one_dart_per_cell<1>().begin(); sIter != cubeLCC.one_dart_per_cell<1>().end(); sIter++)
		nSegments++;

	cout << "Number of segments: " << nSegments << "\n";

	unsigned int nFaces = 0;
	for (LCC::One_dart_per_cell_range<2>::iterator fIter = cubeLCC.one_dart_per_cell<2>().begin(); fIter != cubeLCC.one_dart_per_cell<2>().end(); fIter++)
		nFaces++;

	cout << "Number of faces: " << nFaces << "\n";

	return 0;
}

<|endoftext|>


<commit_before>/*
 * This file is part of OpenModelica.
 *
 * Copyright (c) 1998-CurrentYear, Linköping University,
 * Department of Computer and Information Science,
 * SE-58183 Linköping, Sweden.
 *
 * All rights reserved.
 *
 * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF GPL VERSION 3
 * AND THIS OSMC PUBLIC LICENSE (OSMC-PL).
 * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES RECIPIENT'S
 * ACCEPTANCE OF THE OSMC PUBLIC LICENSE.
 *
 * The OpenModelica software and the Open Source Modelica
 * Consortium (OSMC) Public License (OSMC-PL) are obtained
 * from Linköping University, either from the above address,
 * from the URLs: http://www.ida.liu.se/projects/OpenModelica or
 * http://www.openmodelica.org, and in the OpenModelica distribution.
 * GNU version 3 is obtained from: http://www.gnu.org/copyleft/gpl.html.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without
 * even the implied warranty of  MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH
 * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS
 * OF OSMC-PL.
 *
 * See the full OSMC Public License conditions for more details.
 *
 */

/*
 * HopsanGUI
 * Fluid and Mechatronic Systems, Department of Management and Engineering, Linköping University
 * Main Authors 2009-2010:  Robert Braun, Björn Eriksson, Peter Nordin
 * Contributors 2009-2010:  Mikael Axin, Alessandro Dell'Amico, Karl Pettersson, Ingo Staack
 */

//!
//! @file   SystemParametersWidget.cpp
//! @author Robert Braun <robert.braun@liu.se>
//! @date   2010-10-04
//!
//! @brief Contains a System parameter widget class
//!
//$Id$

#include <QtGui>

#include "../MainWindow.h"
#include "SystemParametersWidget.h"

#include <QWidget>
#include <QDialog>

#include "ProjectTabWidget.h"
#include "../GUIObjects/GUISystem.h"

#include "../common.h"

//! Construtor for System Parameters widget, where the user can see and change the System parameters in the model.
//! @param parent Pointer to the main window
SystemParametersWidget::SystemParametersWidget(MainWindow *parent)
    : QWidget(parent)
{
    //mpParentMainWindow = parent;
    //Set the name and size of the main window
    this->setObjectName("SystemParameterWidget");
    this->resize(400,500);
    this->setWindowTitle("System Parameters");

    mpSystemParametersTable = new SystemParameterTableWidget(0,1,this);

    mpAddButton = new QPushButton(tr("&Set"), this);
    mpAddButton->setFixedHeight(30);
    mpAddButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
    mpAddButton->setAutoDefault(false);
    QFont tempFont = mpAddButton->font();
    tempFont.setBold(true);
    mpAddButton->setFont(tempFont);

    mpRemoveButton = new QPushButton(tr("&Unset"), this);
    mpRemoveButton->setFixedHeight(30);
    mpRemoveButton->setAutoDefault(false);
    mpRemoveButton->setFont(tempFont);

    mpGridLayout = new QGridLayout(this);
    mpGridLayout->addWidget(mpSystemParametersTable, 0, 0);
    mpGridLayout->addWidget(mpAddButton, 1, 0);
    mpGridLayout->addWidget(mpRemoveButton, 2, 0);

    connect(mpAddButton, SIGNAL(clicked()), mpSystemParametersTable, SLOT(openComponentPropertiesDialog()));
    connect(mpRemoveButton, SIGNAL(clicked()), mpSystemParametersTable, SLOT(removeSelectedParameters()));
    connect(gpMainWindow->mpProjectTabs, SIGNAL(currentChanged(int)), this, SLOT(update()));//Strössel!
    connect(gpMainWindow->mpProjectTabs, SIGNAL(newTabAdded()), this, SLOT(update()));//Strössel!
}

void SystemParametersWidget::update()
{
    if(gpMainWindow->mpProjectTabs->count()>0)
    {
        mpAddButton->setEnabled(true);
        mpRemoveButton->setEnabled(true);
    }
    else
    {
        mpAddButton->setEnabled(false);
        mpRemoveButton->setEnabled(false);
    }

    mpSystemParametersTable->update();
}

SystemParameterTableWidget::SystemParameterTableWidget(int rows, int columns, QWidget *parent)
    : QTableWidget(rows, columns, parent)
{
    setFocusPolicy(Qt::StrongFocus);
    setSelectionMode(QAbstractItemView::SingleSelection);

    setBaseSize(400, 500);
    horizontalHeader()->setStretchLastSection(true);
    horizontalHeader()->hide();

    update();

    connect(this, SIGNAL(itemChanged(QTableWidgetItem*)), this, SLOT(changeParameter(QTableWidgetItem*)));
}

void SystemParameterTableWidget::keyPressEvent(QKeyEvent *event)
{
    QTableWidget::keyPressEvent(event);
    if(event->key() == Qt::Key_Delete)
    {
        std::cout << "Delete current System Parameter Widget Items" << std::endl;
        removeSelectedParameters();
    }
}

//! @brief Used for parameter changes done directly in the label
void SystemParameterTableWidget::changeParameter(QTableWidgetItem *item)
{
    //Filter out value labels
    if(item->column() == 1)
    {
        QTableWidgetItem *neighborItem = itemAt(item->row(), item->column()-1);
        QString parName = neighborItem->text();
        QString parValue = item->text();

        //Do not do update, then crash due to the rebuild of the QTableWidgetItems
        setParameter(parName, parValue, false);
    }
}

double SystemParameterTableWidget::getParameter(QString name)
{
    return gpMainWindow->mpProjectTabs->getCurrentTopLevelSystem()->getCoreSystemAccessPtr()->getSystemParameter(name);
}

bool SystemParameterTableWidget::hasParameter(QString name)
{
    return gpMainWindow->mpProjectTabs->getCurrentTopLevelSystem()->getCoreSystemAccessPtr()->hasSystemParameter(name);
}

//! Slot that adds a System parameter value
//! @param name Lookup name for the System parameter
//! @param value Value of the System parameter
void SystemParameterTableWidget::setParameter(QString name, double value, bool doUpdate)
{
    //Error check
    if(!(gpMainWindow->mpProjectTabs->getCurrentTopLevelSystem()->getCoreSystemAccessPtr()->setSystemParameter(name, value)))
    {
        QMessageBox::critical(0, "Hopsan GUI",
                              QString("'%1' is an invalid name for a system parameter.")
                              .arg(name));
        return;
    }
    if(doUpdate)
    {
        update();
    }

    emit modifiedSystemParameter();
}

//! Slot that adds a System parameter value
//! @param name Lookup name for the System parameter
//! @param value Value of the System parameter
void SystemParameterTableWidget::setParameter(QString name, QString valueTxt, bool doUpdate)
{
    //Error check
    bool isDbl;
    double value = valueTxt.toDouble((&isDbl));
    if(!(isDbl))
    {
        QMessageBox::critical(0, "Hopsan GUI",
                              QString("'%1' is not a valid number.")
                              .arg(valueTxt));
        QString oldValue = QString::number(gpMainWindow->mpProjectTabs->getCurrentTopLevelSystem()->getCoreSystemAccessPtr()->getSystemParameter(name));
        QList<QTableWidgetItem *> items = selectedItems();
        //Error if size() > 1, but it should not be! :)
        for(int i = 0; i<items.size(); ++i)
        {
            items[i]->setText(oldValue);
        }
    }
    else
    {
        setParameter(name, value, doUpdate);
    }
}

void SystemParameterTableWidget::setParameters()
{
//    if(gpMainWindow->mpProjectTabs->getCurrentTopLevelSystem()->getCoreSystemAccessPtr()->getNumberOfSystemParameters() > 0)
//    {
        for(int i=0; i<rowCount(); ++i)
        {
            QString name = item(i, 0)->text();
            double value = item(i, 1)->text().toDouble();
            setParameter(name, value);
        }
//    }
}

//! Slot that removes all selected System parameters in parameter table
//! @todo This shall remove the actual System parameters when they have been implemented, wherever they are stored.
void SystemParameterTableWidget::removeSelectedParameters()
{
    if(gpMainWindow->mpProjectTabs->count()>0)
    {
        QList<QTableWidgetItem *> pSelectedItems = selectedItems();
        QStringList parametersToRemove;
        QString tempName;

        for(int i=0; i<pSelectedItems.size(); ++i)
        {
            tempName = item(pSelectedItems[i]->row(),0)->text();
            if(!parametersToRemove.contains(tempName))
            {
                parametersToRemove.append(tempName);
            }
            removeCellWidget(pSelectedItems[i]->row(), pSelectedItems[i]->column());
            delete pSelectedItems[i];
        }

        for(int j=0; j<parametersToRemove.size(); ++j)
        {
            std::cout << "Removing: " << parametersToRemove[j].toStdString() << std::endl;
            gpMainWindow->mpProjectTabs->getCurrentTopLevelSystem()->getCoreSystemAccessPtr()->removeSystemParameter(parametersToRemove.at(j));
        }
    }

    update();
}

//! Slot that opens "Add Parameter" dialog, where the user can add new System parameters
void SystemParameterTableWidget::openComponentPropertiesDialog()
{
    QDialog *pAddComponentPropertiesDialog = new QDialog(this);
    pAddComponentPropertiesDialog->setWindowTitle("Set System Parameter");

    mpNameLabel = new QLabel("Name: ", this);
    mpNameBox = new QLineEdit(this);
    mpValueLabel = new QLabel("Value: ", this);
    mpValueBox = new QLineEdit(this);
    mpValueBox->setValidator(new QDoubleValidator(this));
    mpAddInDialogButton = new QPushButton("Set", this);
    mpDoneInDialogButton = new QPushButton("Done", this);
    QDialogButtonBox *pButtonBox = new QDialogButtonBox(Qt::Horizontal);
    pButtonBox->addButton(mpAddInDialogButton, QDialogButtonBox::ActionRole);
    pButtonBox->addButton(mpDoneInDialogButton, QDialogButtonBox::ActionRole);

    QGridLayout *pDialogLayout = new QGridLayout(this);
    pDialogLayout->addWidget(mpNameLabel,0,0);
    pDialogLayout->addWidget(mpNameBox,0,1);
    pDialogLayout->addWidget(mpValueLabel,1,0);
    pDialogLayout->addWidget(mpValueBox,1,1);
    pDialogLayout->addWidget(pButtonBox,2,0,1,2);
    pAddComponentPropertiesDialog->setLayout(pDialogLayout);
    pAddComponentPropertiesDialog->show();

    connect(mpDoneInDialogButton,SIGNAL(clicked()),pAddComponentPropertiesDialog,SLOT(close()));
    connect(mpAddInDialogButton,SIGNAL(clicked()),this,SLOT(addParameter()));
}

//! @Private help slot that adds a parameter from the selected name and value in "Add Parameter" dialog
void SystemParameterTableWidget::addParameter()
{
    bool ok;
    setParameter(mpNameBox->text(), mpValueBox->text().toDouble(&ok));
}

//! Updates the parameter table from the contents list
void SystemParameterTableWidget::update()
{
    QMap<std::string, double>::iterator it;
    QMap<std::string, double> tempMap;
    if(gpMainWindow->mpProjectTabs->count()>0)
    {
        tempMap = gpMainWindow->mpProjectTabs->getCurrentTopLevelSystem()->getCoreSystemAccessPtr()->getSystemParametersMap();
    }
    else
    {
        tempMap.clear();
        return;
    }

    clear();

    if(tempMap.isEmpty())
    {
        setColumnCount(1);
        setRowCount(1);
        verticalHeader()->hide();

        QTableWidgetItem *item = new QTableWidgetItem();
        item->setText("No System parameters set.");
        item->setBackgroundColor(QColor("white"));
        item->setTextAlignment(Qt::AlignCenter);
        item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
        setItem(0,0,item);
    }
    else
    {
        setRowCount(0);
        setColumnCount(2);
        setColumnWidth(0, 120);
        verticalHeader()->show();
    }
    for(it=tempMap.begin(); it!=tempMap.end(); ++it)
    {
        QString valueString;
        valueString.setNum(it.value());
        insertRow(rowCount());
        QTableWidgetItem *nameItem = new QTableWidgetItem(QString(it.key().c_str()));
        QTableWidgetItem *valueItem = new QTableWidgetItem(valueString);
        nameItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
        valueItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable);
        setItem(rowCount()-1, 0, nameItem);
        setItem(rowCount()-1, 1, valueItem);
    }
}
<commit_msg>fixed yet another bug in system parameter widget<commit_after>/*
 * This file is part of OpenModelica.
 *
 * Copyright (c) 1998-CurrentYear, Linköping University,
 * Department of Computer and Information Science,
 * SE-58183 Linköping, Sweden.
 *
 * All rights reserved.
 *
 * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF GPL VERSION 3
 * AND THIS OSMC PUBLIC LICENSE (OSMC-PL).
 * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES RECIPIENT'S
 * ACCEPTANCE OF THE OSMC PUBLIC LICENSE.
 *
 * The OpenModelica software and the Open Source Modelica
 * Consortium (OSMC) Public License (OSMC-PL) are obtained
 * from Linköping University, either from the above address,
 * from the URLs: http://www.ida.liu.se/projects/OpenModelica or
 * http://www.openmodelica.org, and in the OpenModelica distribution.
 * GNU version 3 is obtained from: http://www.gnu.org/copyleft/gpl.html.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without
 * even the implied warranty of  MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH
 * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS
 * OF OSMC-PL.
 *
 * See the full OSMC Public License conditions for more details.
 *
 */

/*
 * HopsanGUI
 * Fluid and Mechatronic Systems, Department of Management and Engineering, Linköping University
 * Main Authors 2009-2010:  Robert Braun, Björn Eriksson, Peter Nordin
 * Contributors 2009-2010:  Mikael Axin, Alessandro Dell'Amico, Karl Pettersson, Ingo Staack
 */

//!
//! @file   SystemParametersWidget.cpp
//! @author Robert Braun <robert.braun@liu.se>
//! @date   2010-10-04
//!
//! @brief Contains a System parameter widget class
//!
//$Id$

#include <QtGui>

#include "../MainWindow.h"
#include "SystemParametersWidget.h"

#include <QWidget>
#include <QDialog>

#include "ProjectTabWidget.h"
#include "../GUIObjects/GUISystem.h"

#include "../common.h"

//! Construtor for System Parameters widget, where the user can see and change the System parameters in the model.
//! @param parent Pointer to the main window
SystemParametersWidget::SystemParametersWidget(MainWindow *parent)
    : QWidget(parent)
{
    //mpParentMainWindow = parent;
    //Set the name and size of the main window
    this->setObjectName("SystemParameterWidget");
    this->resize(400,500);
    this->setWindowTitle("System Parameters");

    mpSystemParametersTable = new SystemParameterTableWidget(0,1,this);

    mpAddButton = new QPushButton(tr("&Set"), this);
    mpAddButton->setFixedHeight(30);
    mpAddButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
    mpAddButton->setAutoDefault(false);
    QFont tempFont = mpAddButton->font();
    tempFont.setBold(true);
    mpAddButton->setFont(tempFont);
    mpAddButton->setEnabled(false);

    mpRemoveButton = new QPushButton(tr("&Unset"), this);
    mpRemoveButton->setFixedHeight(30);
    mpRemoveButton->setAutoDefault(false);
    mpRemoveButton->setFont(tempFont);
    mpRemoveButton->setEnabled(false);

    mpGridLayout = new QGridLayout(this);
    mpGridLayout->addWidget(mpSystemParametersTable, 0, 0);
    mpGridLayout->addWidget(mpAddButton, 1, 0);
    mpGridLayout->addWidget(mpRemoveButton, 2, 0);

    update();

    connect(mpAddButton, SIGNAL(clicked()), mpSystemParametersTable, SLOT(openComponentPropertiesDialog()));
    connect(mpRemoveButton, SIGNAL(clicked()), mpSystemParametersTable, SLOT(removeSelectedParameters()));
    connect(gpMainWindow->mpProjectTabs, SIGNAL(currentChanged(int)), this, SLOT(update()));//Strössel!
    connect(gpMainWindow->mpProjectTabs, SIGNAL(newTabAdded()), this, SLOT(update()));//Strössel!
}

void SystemParametersWidget::update()
{
    if(gpMainWindow->mpProjectTabs->count()>0)
    {
        mpAddButton->setEnabled(true);
        mpRemoveButton->setEnabled(true);
    }
    else
    {
        mpAddButton->setEnabled(false);
        mpRemoveButton->setEnabled(false);
    }

    mpSystemParametersTable->update();
}

SystemParameterTableWidget::SystemParameterTableWidget(int rows, int columns, QWidget *parent)
    : QTableWidget(rows, columns, parent)
{
    setFocusPolicy(Qt::StrongFocus);
    setSelectionMode(QAbstractItemView::SingleSelection);

    setBaseSize(400, 500);
    horizontalHeader()->setStretchLastSection(true);
    horizontalHeader()->hide();

    update();

    connect(this, SIGNAL(itemChanged(QTableWidgetItem*)), this, SLOT(changeParameter(QTableWidgetItem*)));
}

void SystemParameterTableWidget::keyPressEvent(QKeyEvent *event)
{
    QTableWidget::keyPressEvent(event);
    if(event->key() == Qt::Key_Delete)
    {
        std::cout << "Delete current System Parameter Widget Items" << std::endl;
        removeSelectedParameters();
    }
}

//! @brief Used for parameter changes done directly in the label
void SystemParameterTableWidget::changeParameter(QTableWidgetItem *item)
{
    //Filter out value labels
    if(item->column() == 1)
    {
        QTableWidgetItem *neighborItem = itemAt(item->row(), item->column()-1);
        QString parName = neighborItem->text();
        QString parValue = item->text();

        //Do not do update, then crash due to the rebuild of the QTableWidgetItems
        setParameter(parName, parValue, false);
    }
}

double SystemParameterTableWidget::getParameter(QString name)
{
    return gpMainWindow->mpProjectTabs->getCurrentTopLevelSystem()->getCoreSystemAccessPtr()->getSystemParameter(name);
}

bool SystemParameterTableWidget::hasParameter(QString name)
{
    return gpMainWindow->mpProjectTabs->getCurrentTopLevelSystem()->getCoreSystemAccessPtr()->hasSystemParameter(name);
}

//! Slot that adds a System parameter value
//! @param name Lookup name for the System parameter
//! @param value Value of the System parameter
void SystemParameterTableWidget::setParameter(QString name, double value, bool doUpdate)
{
    //Error check
    if(!(gpMainWindow->mpProjectTabs->getCurrentTopLevelSystem()->getCoreSystemAccessPtr()->setSystemParameter(name, value)))
    {
        QMessageBox::critical(0, "Hopsan GUI",
                              QString("'%1' is an invalid name for a system parameter.")
                              .arg(name));
        return;
    }
    if(doUpdate)
    {
        update();
    }

    emit modifiedSystemParameter();
}

//! Slot that adds a System parameter value
//! @param name Lookup name for the System parameter
//! @param value Value of the System parameter
void SystemParameterTableWidget::setParameter(QString name, QString valueTxt, bool doUpdate)
{
    //Error check
    bool isDbl;
    double value = valueTxt.toDouble((&isDbl));
    if(!(isDbl))
    {
        QMessageBox::critical(0, "Hopsan GUI",
                              QString("'%1' is not a valid number.")
                              .arg(valueTxt));
        QString oldValue = QString::number(gpMainWindow->mpProjectTabs->getCurrentTopLevelSystem()->getCoreSystemAccessPtr()->getSystemParameter(name));
        QList<QTableWidgetItem *> items = selectedItems();
        //Error if size() > 1, but it should not be! :)
        for(int i = 0; i<items.size(); ++i)
        {
            items[i]->setText(oldValue);
        }
    }
    else
    {
        setParameter(name, value, doUpdate);
    }
}

void SystemParameterTableWidget::setParameters()
{
    //    if(gpMainWindow->mpProjectTabs->getCurrentTopLevelSystem()->getCoreSystemAccessPtr()->getNumberOfSystemParameters() > 0)
    //    {
    for(int i=0; i<rowCount(); ++i)
    {
        QString name = item(i, 0)->text();
        double value = item(i, 1)->text().toDouble();
        setParameter(name, value);
    }
    //    }
}

//! Slot that removes all selected System parameters in parameter table
//! @todo This shall remove the actual System parameters when they have been implemented, wherever they are stored.
void SystemParameterTableWidget::removeSelectedParameters()
{
    if(gpMainWindow->mpProjectTabs->count()>0)
    {
        QList<QTableWidgetItem *> pSelectedItems = selectedItems();
        QStringList parametersToRemove;
        QString tempName;

        for(int i=0; i<pSelectedItems.size(); ++i)
        {
            tempName = item(pSelectedItems[i]->row(),0)->text();
            if(!parametersToRemove.contains(tempName))
            {
                parametersToRemove.append(tempName);
            }
            removeCellWidget(pSelectedItems[i]->row(), pSelectedItems[i]->column());
            delete pSelectedItems[i];
        }

        for(int j=0; j<parametersToRemove.size(); ++j)
        {
            std::cout << "Removing: " << parametersToRemove[j].toStdString() << std::endl;
            gpMainWindow->mpProjectTabs->getCurrentTopLevelSystem()->getCoreSystemAccessPtr()->removeSystemParameter(parametersToRemove.at(j));
        }
    }

    update();
}

//! Slot that opens "Add Parameter" dialog, where the user can add new System parameters
void SystemParameterTableWidget::openComponentPropertiesDialog()
{
    QDialog *pAddComponentPropertiesDialog = new QDialog(this);
    pAddComponentPropertiesDialog->setWindowTitle("Set System Parameter");

    mpNameLabel = new QLabel("Name: ", this);
    mpNameBox = new QLineEdit(this);
    mpValueLabel = new QLabel("Value: ", this);
    mpValueBox = new QLineEdit(this);
    mpValueBox->setValidator(new QDoubleValidator(this));
    mpAddInDialogButton = new QPushButton("Set", this);
    mpDoneInDialogButton = new QPushButton("Done", this);
    QDialogButtonBox *pButtonBox = new QDialogButtonBox(Qt::Horizontal);
    pButtonBox->addButton(mpAddInDialogButton, QDialogButtonBox::ActionRole);
    pButtonBox->addButton(mpDoneInDialogButton, QDialogButtonBox::ActionRole);

    QGridLayout *pDialogLayout = new QGridLayout(this);
    pDialogLayout->addWidget(mpNameLabel,0,0);
    pDialogLayout->addWidget(mpNameBox,0,1);
    pDialogLayout->addWidget(mpValueLabel,1,0);
    pDialogLayout->addWidget(mpValueBox,1,1);
    pDialogLayout->addWidget(pButtonBox,2,0,1,2);
    pAddComponentPropertiesDialog->setLayout(pDialogLayout);
    pAddComponentPropertiesDialog->show();

    connect(mpDoneInDialogButton,SIGNAL(clicked()),pAddComponentPropertiesDialog,SLOT(close()));
    connect(mpAddInDialogButton,SIGNAL(clicked()),this,SLOT(addParameter()));
}

//! @Private help slot that adds a parameter from the selected name and value in "Add Parameter" dialog
void SystemParameterTableWidget::addParameter()
{
    bool ok;
    setParameter(mpNameBox->text(), mpValueBox->text().toDouble(&ok));
}

//! Updates the parameter table from the contents list
void SystemParameterTableWidget::update()
{
    QMap<std::string, double>::iterator it;
    QMap<std::string, double> tempMap;
    tempMap.clear();
    clear();
    if(gpMainWindow->mpProjectTabs->count()>0)
    {
        tempMap = gpMainWindow->mpProjectTabs->getCurrentTopLevelSystem()->getCoreSystemAccessPtr()->getSystemParametersMap();
    }
    if(tempMap.isEmpty())
    {
        setColumnCount(1);
        setRowCount(1);
        verticalHeader()->hide();

        QTableWidgetItem *item = new QTableWidgetItem();
        item->setText("No System parameters set.");
        item->setBackgroundColor(QColor("white"));
        item->setTextAlignment(Qt::AlignCenter);
        item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
        setItem(0,0,item);
    }
    else
    {
        setRowCount(0);
        setColumnCount(2);
        setColumnWidth(0, 120);
        verticalHeader()->show();

        for(it=tempMap.begin(); it!=tempMap.end(); ++it)
        {
            QString valueString;
            valueString.setNum(it.value());
            insertRow(rowCount());
            QTableWidgetItem *nameItem = new QTableWidgetItem(QString(it.key().c_str()));
            QTableWidgetItem *valueItem = new QTableWidgetItem(valueString);
            nameItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
            valueItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable);
            setItem(rowCount()-1, 0, nameItem);
            setItem(rowCount()-1, 1, valueItem);
        }
    }
}
<|endoftext|>


<commit_before>/*
// $Id$
// Fennel is a library of data storage and processing components.
// Copyright (C) 2005-2005 LucidEra, Inc.
// Copyright (C) 2005-2005 The Eigenbase Project
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 of the License, or (at your option)
// any later version approved by The Eigenbase Project.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include "fennel/common/CommonPreamble.h"
#include "fennel/test/ExecStreamUnitTestBase.h"
//#include "fennel/tuple/StandardTypeDescriptor.h"
#include "fennel/exec/MockProducerExecStream.h"
#include "fennel/exec/ExecStreamEmbryo.h"

#include "fennel/exec/ExecStreamGraph.h"
#include "fennel/exec/ExecStreamGraphEmbryo.h"
#include "fennel/exec/ExecStreamScheduler.h"
#include "fennel/exec/ExecStream.h"
#include "fennel/exec/ScratchBufferExecStream.h"
#include "fennel/exec/ExecStreamEmbryo.h"
#include "fennel/exec/ExecStreamBufAccessor.h"
#include "fennel/exec/MockProducerExecStream.h"
#include "fennel/tuple/TuplePrinter.h"
#include "fennel/tuple/StandardTypeDescriptor.h"

#include <boost/test/test_tools.hpp>

#include "fennel/lucidera/flatfile/FlatFileBuffer.h"
#include "fennel/lucidera/flatfile/FlatFileParser.h"
#include "fennel/lucidera/flatfile/FlatFileExecStream.h"

using namespace fennel;

/**
 * StringExecStreamGenerator defines an interface for generating
 * a data stream of strings.
 */
class StringExecStreamGenerator
{
public:
    virtual ~StringExecStreamGenerator() {}

    /**
     * Generates one data value.
     *
     * @param iRow 0-based row number to generate
     */
    virtual const std::string &generateValue(uint iRow) = 0;
};

class StringExecStreamGeneratorImpl : public StringExecStreamGenerator
{
    std::vector<std::string> values;

public:
    void insert(const std::string &value)
    {
        values.push_back(value);
    }

    // Implement StringExecStreamGenerator
    const std::string &generateValue(uint iRow)
    {
        BOOST_CHECK(iRow < values.size());
        return values[iRow];
    }
};

class FlatFileExecStreamTest : public ExecStreamUnitTestBase
{
public:
    explicit FlatFileExecStreamTest()
    {
        FENNEL_UNIT_TEST_CASE(FlatFileExecStreamTest, testBuffer);
        FENNEL_UNIT_TEST_CASE(FlatFileExecStreamTest, testParser);
        FENNEL_UNIT_TEST_CASE(FlatFileExecStreamTest, testStream);
    }

    void testBuffer();
    void testParser();
    void testStream();

    void verifyOutput(
        ExecStream &stream,
        uint nRowsExpected,
        StringExecStreamGenerator &generator);
};

void FlatFileExecStreamTest::testBuffer()
{
    FixedBuffer fixedBuffer[8];
    std::string path = "flatfile/buffer";

    FlatFileBuffer fileBuffer(path);
    fileBuffer.setStorage((char *) fixedBuffer, (uint)8);
    fileBuffer.open();
    BOOST_REQUIRE(fileBuffer.buf()==(char *)fixedBuffer);
    BOOST_REQUIRE(fileBuffer.size()==0);
    fileBuffer.fill();
    BOOST_REQUIRE(fileBuffer.size() == 8);
    BOOST_REQUIRE(strncmp(fileBuffer.buf(), "12345671", 8)==0);
    fileBuffer.fill(fileBuffer.buf()+7);
    BOOST_REQUIRE(fileBuffer.size() == 8);
    BOOST_REQUIRE(strncmp(fileBuffer.buf(), "12345676", 8)==0);
    fileBuffer.fill(fileBuffer.buf()+6);
    BOOST_REQUIRE(fileBuffer.size()==5);
    BOOST_REQUIRE(strncmp(fileBuffer.buf(), "7654\n", 5)==0);
    BOOST_REQUIRE(fileBuffer.end());
    fileBuffer.close();

    // TODO: test missing file, empty file
}

void FlatFileExecStreamTest::testParser()
{
    FlatFileParser parser(',', '\n', '"', '"');
    char buffer[128];

    strcpy(buffer, "");
    BOOST_CHECK_EQUAL(parser.trim(buffer, 0), 0);
    BOOST_CHECK_EQUAL(strncmp(buffer, "", 0), 0);
    strcpy(buffer, "aRobin");
    BOOST_CHECK_EQUAL(parser.trim(buffer, 6), 6);
    BOOST_CHECK_EQUAL(strncmp(buffer, "aRobin", 6), 0);
    strcpy(buffer, "   red breast in cage  ");
    BOOST_CHECK_EQUAL(parser.trim(buffer, 23), 18);
    BOOST_CHECK_EQUAL(strncmp(buffer, "red breast in cage", 18), 0);

    strcpy(buffer, "");
    BOOST_CHECK_EQUAL(parser.stripQuoting(buffer, 0, true), 0);
    BOOST_CHECK_EQUAL(strncmp(buffer, "", 0), 0);
    strcpy(buffer, "puts all");
    BOOST_CHECK_EQUAL(parser.stripQuoting(buffer, 8, true), 8);
    BOOST_CHECK_EQUAL(strncmp(buffer, "puts all", 8), 0);
    strcpy(buffer, "\"heaven\"");
    BOOST_CHECK_EQUAL(parser.stripQuoting(buffer, 8, true), 6);
    BOOST_CHECK_EQUAL(strncmp(buffer, "heaven", 6), 0);
    strcpy(buffer, "   \"in a\"  ");
    BOOST_CHECK_EQUAL(parser.stripQuoting(buffer, 11, true), 4);
    BOOST_CHECK_EQUAL(strncmp(buffer, "in a", 4), 0);
    strcpy(buffer, "   \"\"\"rage\"\"\"  ");
    BOOST_CHECK_EQUAL(parser.stripQuoting(buffer, 15, true), 6);
    BOOST_CHECK_EQUAL(strncmp(buffer, "\"rage\"", 6), 0);

    FlatFileColumnParseResult result;
    // quote/escapes are plain escapes if not column is not char type
    strcpy(buffer, "\"all that\"\n is gold, ");
    parser.scanColumn(buffer, 21, 128, false, result);
    BOOST_CHECK_EQUAL(result.type, FlatFileColumnParseResult::FIELD_DELIM);
    BOOST_CHECK_EQUAL(result.size, 19);
    BOOST_CHECK(result.next == buffer + 20);
    // quotes are valid for char columns
    strcpy(buffer, "\"does not glitter\"\n ");
    parser.scanColumn(buffer, 20, 128, true, result);
    BOOST_CHECK_EQUAL(result.type, FlatFileColumnParseResult::ROW_DELIM);
    BOOST_CHECK_EQUAL(result.size, 18);
    BOOST_CHECK(result.next == buffer + 19);
    // embedded quotes
    strcpy(buffer, "\"not all those who \"\"wander\"\"\", ");
    parser.scanColumn(buffer, 32, 128, true, result);
    BOOST_CHECK_EQUAL(result.type, FlatFileColumnParseResult::FIELD_DELIM);
    BOOST_CHECK_EQUAL(result.size, 30);
    BOOST_CHECK(result.next == buffer + 31);
    // fixed column type
    strcpy(buffer, " are lost  ");
    parser.scanColumn(buffer, 11, 9, true, result);
    BOOST_CHECK_EQUAL(result.type, FlatFileColumnParseResult::MAX_LENGTH);
    BOOST_CHECK_EQUAL(result.size, 9);
    BOOST_CHECK(result.next == buffer + 9);
    // imbalanced quote
    strcpy(buffer, "\"JRR, ");
    parser.scanColumn(buffer, 6, 128, true, result);
    BOOST_CHECK_EQUAL(result.type, FlatFileColumnParseResult::NO_DELIM);
    BOOST_CHECK_EQUAL(result.size, 6);
    BOOST_CHECK(result.next == buffer + 6);
    // data after quote
    strcpy(buffer, "\"Tolkien\"  , ");
    parser.scanColumn(buffer, 13, 128, true, result);
    BOOST_CHECK_EQUAL(result.type, FlatFileColumnParseResult::FIELD_DELIM);
    BOOST_CHECK_EQUAL(result.size, 11);
    BOOST_CHECK(result.next == buffer + 12);
    // fixed length exactly equal to buffer size
    strcpy(buffer, "some poems");
    parser.scanColumn(buffer, 10, 10, true, result);
    BOOST_CHECK_EQUAL(result.type, FlatFileColumnParseResult::NO_DELIM);
    BOOST_CHECK_EQUAL(result.size, 10);
    BOOST_CHECK(result.next == buffer + 10);
}

void FlatFileExecStreamTest::testStream()
{
    StandardTypeDescriptorFactory stdTypeFactory;
    TupleAttributeDescriptor attrDesc(
        stdTypeFactory.newDataType(STANDARD_TYPE_VARCHAR),
        false,
        32);

    FlatFileExecStreamParams flatfileParams;
    flatfileParams.scratchAccessor =
        pSegmentFactory->newScratchSegment(pCache,1);
     flatfileParams.outputTupleDesc.push_back(attrDesc);
    flatfileParams.outputTupleDesc.push_back(attrDesc);
    flatfileParams.path = "/home/jpham/open/fennel/lucidera/test/flatfile/stream";
    flatfileParams.fieldDelim = ",";
    flatfileParams.rowDelim = "\n";
    flatfileParams.quoteChar = '"';
    flatfileParams.escapeChar = '\\';
    flatfileParams.header = false;
    flatfileParams.logging = true;

    ExecStreamEmbryo flatfileStreamEmbryo;
    flatfileStreamEmbryo.init(
        FlatFileExecStream::newFlatFileExecStream(), flatfileParams);
    flatfileStreamEmbryo.getStream()->setName("FlatFileExecStream");

    SharedExecStream pOutputStream = prepareSourceGraph(flatfileStreamEmbryo);
    StringExecStreamGeneratorImpl verifier;
    verifier.insert("[ 'No one', 'travels' ]");
    verifier.insert("[ 'Along this way', 'but I,' ]");
    verifier.insert("[ 'This', 'autumn evening.' ]");

    verifyOutput(
        *pOutputStream,
        3,
        verifier);
}

void FlatFileExecStreamTest::verifyOutput(
    ExecStream &stream,
    uint nRowsExpected,
    StringExecStreamGenerator &generator)
{
    // TODO:  assertions about output tuple, or better yet, use proper tuple
    // access

    pGraph->open();
    pScheduler->start();
    uint nRows = 0;
    for (;;) {
        ExecStreamBufAccessor &bufAccessor =
            pScheduler->readStream(stream);
        if (bufAccessor.getState() == EXECBUF_EOS) {
            break;
        }
        BOOST_REQUIRE(bufAccessor.isConsumptionPossible());
        const uint nCol =
            bufAccessor.getConsumptionTupleAccessor().size();
        BOOST_REQUIRE(nCol == bufAccessor.getTupleDesc().size());
        BOOST_REQUIRE(nCol >= 1);
        TupleData inputTuple;
        inputTuple.compute(bufAccessor.getTupleDesc());
        std::ostringstream oss;
        TuplePrinter tuplePrinter;
        for (;;) {
            if (!bufAccessor.demandData()) {
                break;
            }
            BOOST_REQUIRE(nRows < nRowsExpected);
            bufAccessor.unmarshalTuple(inputTuple);
            tuplePrinter.print(oss,bufAccessor.getTupleDesc(),inputTuple);
            std::string actualValue = oss.str();
            oss.str("");
            const std::string &expectedValue = generator.generateValue(nRows);
            if (actualValue.compare(expectedValue)) {
                std::cout << "(Row) = (" << nRows << ")" << std::endl;
                BOOST_CHECK_EQUAL(expectedValue,actualValue);
                return;
            }
            bufAccessor.consumeTuple();
            ++nRows;
        }
    }
    BOOST_CHECK_EQUAL(nRowsExpected,nRows);
}

FENNEL_UNIT_TEST_SUITE(FlatFileExecStreamTest);

// End FlatFileStreamTest.cpp
<commit_msg>FENNEL: disable flat file tests until file paths are figured out<commit_after>/*
// $Id$
// Fennel is a library of data storage and processing components.
// Copyright (C) 2005-2005 LucidEra, Inc.
// Copyright (C) 2005-2005 The Eigenbase Project
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 of the License, or (at your option)
// any later version approved by The Eigenbase Project.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include "fennel/common/CommonPreamble.h"
#include "fennel/test/ExecStreamUnitTestBase.h"
//#include "fennel/tuple/StandardTypeDescriptor.h"
#include "fennel/exec/MockProducerExecStream.h"
#include "fennel/exec/ExecStreamEmbryo.h"

#include "fennel/exec/ExecStreamGraph.h"
#include "fennel/exec/ExecStreamGraphEmbryo.h"
#include "fennel/exec/ExecStreamScheduler.h"
#include "fennel/exec/ExecStream.h"
#include "fennel/exec/ScratchBufferExecStream.h"
#include "fennel/exec/ExecStreamEmbryo.h"
#include "fennel/exec/ExecStreamBufAccessor.h"
#include "fennel/exec/MockProducerExecStream.h"
#include "fennel/tuple/TuplePrinter.h"
#include "fennel/tuple/StandardTypeDescriptor.h"

#include <boost/test/test_tools.hpp>

#include "fennel/lucidera/flatfile/FlatFileBuffer.h"
#include "fennel/lucidera/flatfile/FlatFileParser.h"
#include "fennel/lucidera/flatfile/FlatFileExecStream.h"

using namespace fennel;

/**
 * StringExecStreamGenerator defines an interface for generating
 * a data stream of strings.
 */
class StringExecStreamGenerator
{
public:
    virtual ~StringExecStreamGenerator() {}

    /**
     * Generates one data value.
     *
     * @param iRow 0-based row number to generate
     */
    virtual const std::string &generateValue(uint iRow) = 0;
};

class StringExecStreamGeneratorImpl : public StringExecStreamGenerator
{
    std::vector<std::string> values;

public:
    void insert(const std::string &value)
    {
        values.push_back(value);
    }

    // Implement StringExecStreamGenerator
    const std::string &generateValue(uint iRow)
    {
        BOOST_CHECK(iRow < values.size());
        return values[iRow];
    }
};

class FlatFileExecStreamTest : public ExecStreamUnitTestBase
{
public:
    explicit FlatFileExecStreamTest()
    {
        //FENNEL_UNIT_TEST_CASE(FlatFileExecStreamTest, testBuffer);
        FENNEL_UNIT_TEST_CASE(FlatFileExecStreamTest, testParser);
        //FENNEL_UNIT_TEST_CASE(FlatFileExecStreamTest, testStream);
    }

    void testBuffer();
    void testParser();
    void testStream();

    void verifyOutput(
        ExecStream &stream,
        uint nRowsExpected,
        StringExecStreamGenerator &generator);
};

void FlatFileExecStreamTest::testBuffer()
{
    FixedBuffer fixedBuffer[8];
    std::string path = "flatfile/buffer";

    FlatFileBuffer fileBuffer(path);
    fileBuffer.setStorage((char *) fixedBuffer, (uint)8);
    fileBuffer.open();
    BOOST_REQUIRE(fileBuffer.buf()==(char *)fixedBuffer);
    BOOST_REQUIRE(fileBuffer.size()==0);
    fileBuffer.fill();
    BOOST_REQUIRE(fileBuffer.size() == 8);
    BOOST_REQUIRE(strncmp(fileBuffer.buf(), "12345671", 8)==0);
    fileBuffer.fill(fileBuffer.buf()+7);
    BOOST_REQUIRE(fileBuffer.size() == 8);
    BOOST_REQUIRE(strncmp(fileBuffer.buf(), "12345676", 8)==0);
    fileBuffer.fill(fileBuffer.buf()+6);
    BOOST_REQUIRE(fileBuffer.size()==5);
    BOOST_REQUIRE(strncmp(fileBuffer.buf(), "7654\n", 5)==0);
    BOOST_REQUIRE(fileBuffer.end());
    fileBuffer.close();

    // TODO: test missing file, empty file
}

void FlatFileExecStreamTest::testParser()
{
    FlatFileParser parser(',', '\n', '"', '"');
    char buffer[128];

    strcpy(buffer, "");
    BOOST_CHECK_EQUAL(parser.trim(buffer, 0), 0);
    BOOST_CHECK_EQUAL(strncmp(buffer, "", 0), 0);
    strcpy(buffer, "aRobin");
    BOOST_CHECK_EQUAL(parser.trim(buffer, 6), 6);
    BOOST_CHECK_EQUAL(strncmp(buffer, "aRobin", 6), 0);
    strcpy(buffer, "   red breast in cage  ");
    BOOST_CHECK_EQUAL(parser.trim(buffer, 23), 18);
    BOOST_CHECK_EQUAL(strncmp(buffer, "red breast in cage", 18), 0);

    strcpy(buffer, "");
    BOOST_CHECK_EQUAL(parser.stripQuoting(buffer, 0, true), 0);
    BOOST_CHECK_EQUAL(strncmp(buffer, "", 0), 0);
    strcpy(buffer, "puts all");
    BOOST_CHECK_EQUAL(parser.stripQuoting(buffer, 8, true), 8);
    BOOST_CHECK_EQUAL(strncmp(buffer, "puts all", 8), 0);
    strcpy(buffer, "\"heaven\"");
    BOOST_CHECK_EQUAL(parser.stripQuoting(buffer, 8, true), 6);
    BOOST_CHECK_EQUAL(strncmp(buffer, "heaven", 6), 0);
    strcpy(buffer, "   \"in a\"  ");
    BOOST_CHECK_EQUAL(parser.stripQuoting(buffer, 11, true), 4);
    BOOST_CHECK_EQUAL(strncmp(buffer, "in a", 4), 0);
    strcpy(buffer, "   \"\"\"rage\"\"\"  ");
    BOOST_CHECK_EQUAL(parser.stripQuoting(buffer, 15, true), 6);
    BOOST_CHECK_EQUAL(strncmp(buffer, "\"rage\"", 6), 0);

    FlatFileColumnParseResult result;
    // quote/escapes are plain escapes if not column is not char type
    strcpy(buffer, "\"all that\"\n is gold, ");
    parser.scanColumn(buffer, 21, 128, false, result);
    BOOST_CHECK_EQUAL(result.type, FlatFileColumnParseResult::FIELD_DELIM);
    BOOST_CHECK_EQUAL(result.size, 19);
    BOOST_CHECK(result.next == buffer + 20);
    // quotes are valid for char columns
    strcpy(buffer, "\"does not glitter\"\n ");
    parser.scanColumn(buffer, 20, 128, true, result);
    BOOST_CHECK_EQUAL(result.type, FlatFileColumnParseResult::ROW_DELIM);
    BOOST_CHECK_EQUAL(result.size, 18);
    BOOST_CHECK(result.next == buffer + 19);
    // embedded quotes
    strcpy(buffer, "\"not all those who \"\"wander\"\"\", ");
    parser.scanColumn(buffer, 32, 128, true, result);
    BOOST_CHECK_EQUAL(result.type, FlatFileColumnParseResult::FIELD_DELIM);
    BOOST_CHECK_EQUAL(result.size, 30);
    BOOST_CHECK(result.next == buffer + 31);
    // fixed column type
    strcpy(buffer, " are lost  ");
    parser.scanColumn(buffer, 11, 9, true, result);
    BOOST_CHECK_EQUAL(result.type, FlatFileColumnParseResult::MAX_LENGTH);
    BOOST_CHECK_EQUAL(result.size, 9);
    BOOST_CHECK(result.next == buffer + 9);
    // imbalanced quote
    strcpy(buffer, "\"JRR, ");
    parser.scanColumn(buffer, 6, 128, true, result);
    BOOST_CHECK_EQUAL(result.type, FlatFileColumnParseResult::NO_DELIM);
    BOOST_CHECK_EQUAL(result.size, 6);
    BOOST_CHECK(result.next == buffer + 6);
    // data after quote
    strcpy(buffer, "\"Tolkien\"  , ");
    parser.scanColumn(buffer, 13, 128, true, result);
    BOOST_CHECK_EQUAL(result.type, FlatFileColumnParseResult::FIELD_DELIM);
    BOOST_CHECK_EQUAL(result.size, 11);
    BOOST_CHECK(result.next == buffer + 12);
    // fixed length exactly equal to buffer size
    strcpy(buffer, "some poems");
    parser.scanColumn(buffer, 10, 10, true, result);
    BOOST_CHECK_EQUAL(result.type, FlatFileColumnParseResult::NO_DELIM);
    BOOST_CHECK_EQUAL(result.size, 10);
    BOOST_CHECK(result.next == buffer + 10);
}

void FlatFileExecStreamTest::testStream()
{
    StandardTypeDescriptorFactory stdTypeFactory;
    TupleAttributeDescriptor attrDesc(
        stdTypeFactory.newDataType(STANDARD_TYPE_VARCHAR),
        false,
        32);

    FlatFileExecStreamParams flatfileParams;
    flatfileParams.scratchAccessor =
        pSegmentFactory->newScratchSegment(pCache,1);
     flatfileParams.outputTupleDesc.push_back(attrDesc);
    flatfileParams.outputTupleDesc.push_back(attrDesc);
    flatfileParams.path = "flatfile/stream";
    flatfileParams.fieldDelim = ",";
    flatfileParams.rowDelim = "\n";
    flatfileParams.quoteChar = '"';
    flatfileParams.escapeChar = '\\';
    flatfileParams.header = false;
    flatfileParams.logging = true;

    ExecStreamEmbryo flatfileStreamEmbryo;
    flatfileStreamEmbryo.init(
        FlatFileExecStream::newFlatFileExecStream(), flatfileParams);
    flatfileStreamEmbryo.getStream()->setName("FlatFileExecStream");

    SharedExecStream pOutputStream = prepareSourceGraph(flatfileStreamEmbryo);
    StringExecStreamGeneratorImpl verifier;
    verifier.insert("[ 'No one', 'travels' ]");
    verifier.insert("[ 'Along this way', 'but I,' ]");
    verifier.insert("[ 'This', 'autumn evening.' ]");

    verifyOutput(
        *pOutputStream,
        3,
        verifier);
}

void FlatFileExecStreamTest::verifyOutput(
    ExecStream &stream,
    uint nRowsExpected,
    StringExecStreamGenerator &generator)
{
    // TODO:  assertions about output tuple, or better yet, use proper tuple
    // access

    pGraph->open();
    pScheduler->start();
    uint nRows = 0;
    for (;;) {
        ExecStreamBufAccessor &bufAccessor =
            pScheduler->readStream(stream);
        if (bufAccessor.getState() == EXECBUF_EOS) {
            break;
        }
        BOOST_REQUIRE(bufAccessor.isConsumptionPossible());
        const uint nCol =
            bufAccessor.getConsumptionTupleAccessor().size();
        BOOST_REQUIRE(nCol == bufAccessor.getTupleDesc().size());
        BOOST_REQUIRE(nCol >= 1);
        TupleData inputTuple;
        inputTuple.compute(bufAccessor.getTupleDesc());
        std::ostringstream oss;
        TuplePrinter tuplePrinter;
        for (;;) {
            if (!bufAccessor.demandData()) {
                break;
            }
            BOOST_REQUIRE(nRows < nRowsExpected);
            bufAccessor.unmarshalTuple(inputTuple);
            tuplePrinter.print(oss,bufAccessor.getTupleDesc(),inputTuple);
            std::string actualValue = oss.str();
            oss.str("");
            const std::string &expectedValue = generator.generateValue(nRows);
            if (actualValue.compare(expectedValue)) {
                std::cout << "(Row) = (" << nRows << ")" << std::endl;
                BOOST_CHECK_EQUAL(expectedValue,actualValue);
                return;
            }
            bufAccessor.consumeTuple();
            ++nRows;
        }
    }
    BOOST_CHECK_EQUAL(nRowsExpected,nRows);
}

FENNEL_UNIT_TEST_SUITE(FlatFileExecStreamTest);

// End FlatFileStreamTest.cpp
<|endoftext|>


<commit_before>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2015.  All rights reserved
 */
#include    "../../StroikaPreComp.h"

#include    <cstdio>
#include    <random>

#if     qPlatform_POSIX
//@todo see how many of these includes are needed
#include    <unistd.h>
#include    <arpa/inet.h>
#include    <net/if.h>
#include    <netinet/in.h>
#include    <netdb.h>
#include    <sys/socket.h>
#include    <sys/ioctl.h>
#if     qPlatform_Linux
#include    <linux/types.h>     // needed on RedHat5
#include    <linux/ethtool.h>
#include    <linux/sockios.h>
#endif
#elif   qPlatform_Windows
#include    <WinSock2.h>
#include    <WS2tcpip.h>
#include    <Iphlpapi.h>
#include    <netioapi.h>
#endif

#include    "../../Characters/CString/Utilities.h"
#include    "../../Characters/Format.h"
#include    "../../Containers/Collection.h"
#include    "../../Containers/Mapping.h"
#include    "../../Execution/ErrNoException.h"
#include    "../../Execution/Finally.h"
#if     qPlatform_Windows
#include    "../../../Foundation/Execution/Platform/Windows/Exception.h"
#endif
#include    "../../Execution/Synchronized.h"
#include    "../../Memory/SmallStackBuffer.h"

#include    "Socket.h"

#include    "Interface.h"

using   namespace   Stroika::Foundation;
using   namespace   Stroika::Foundation::Containers;
using   namespace   Stroika::Foundation::Execution;
using   namespace   Stroika::Foundation::Memory;
using   namespace   Stroika::Foundation::IO;
using   namespace   Stroika::Foundation::IO::Network;

// Comment this in to turn on aggressive noisy DbgTrace in this module
//#define   USE_NOISY_TRACE_IN_THIS_MODULE_       1

#if     defined (_MSC_VER)
// support use of Iphlpapi - but better to reference here than in lib entry of project file cuz
// easiser to see/modularize (and only pulled in if this module is referenced)
#pragma comment (lib, "Iphlpapi.lib")
#endif

/*
 ********************************************************************************
 **************************** Network::Interface ********************************
 ********************************************************************************
 */
const Configuration::EnumNames<Interface::Status>   Interface::Stroika_Enum_Names(Status)
{
    { Interface::Status::eConnected, L"Connected" },
    { Interface::Status::eRunning, L"Running" },
};

const Configuration::EnumNames<Interface::Type>   Interface::Stroika_Enum_Names(Type)
{
    { Interface::Type::eLoopback, L"Loopback" },
    { Interface::Type::eWiredEthernet, L"WiredEthernet" },
    { Interface::Type::eWIFI, L"WIFI" },
    { Interface::Type::eTunnel, L"Tunnel" },
    { Interface::Type::eOther, L"Other" },
};

#if     qPlatform_Linux
// Hack for centos5 support:
//      Overload with linux version so other one wins, but this gets called if other doesnt exist
//      TRY --LGP 2015-05-19
template    <typename HACK = int>
static __inline__ __u32 ethtool_cmd_speed (const struct ethtool_cmd* ep, HACK i = 0)
{
    //return (ep->speed_hi << 16) | ep->speed;
    return ep->speed;
}
#endif

namespace {
    // Windows uses '-' as separator, and linux ':'. Pick arbitrarily (more linux machines
    // than windows, or soon will be)
    auto     PrintMacAddr_ (const uint8_t* macaddrBytes, const uint8_t* macaddrBytesEnd) -> String {
        Require (macaddrBytesEnd - macaddrBytesEnd == 6);
        char     buf[100] {};
        (void)snprintf (buf, sizeof (buf), "%02x:%02x:%02x:%02x:%02x:%02x",
                        macaddrBytes[0], macaddrBytes[1],
                        macaddrBytes[2], macaddrBytes[3],
                        macaddrBytes[4], macaddrBytes[5]
                       );
        return String::FromAscii (buf);
    };
}

/*
 ********************************************************************************
 ************************** Network::GetInterfaces ******************************
 ********************************************************************************
 */
Traversal::Iterable<Interface>  Network::GetInterfaces ()
{
#if     USE_NOISY_TRACE_IN_THIS_MODULE_
    Debug::TraceContextBumper ctx ("Network::GetInterfaces");
#endif
    Collection<Interface>   result;
#if     qPlatform_POSIX
    auto getFlags = [] (int sd, const char* name) {
        struct ifreq ifreq {};
        Characters::CString::Copy (ifreq.ifr_name, NEltsOf (ifreq.ifr_name), name);

        int r = ::ioctl (sd, SIOCGIFFLAGS, (char*)&ifreq);
        Assert (r == 0);
        return ifreq.ifr_flags;
    };

    struct ifreq    ifreqs[128] {};
    struct ifconf   ifconf {};
    ifconf.ifc_req = ifreqs;
    ifconf.ifc_len = sizeof(ifreqs);

    int sd = ::socket (PF_INET, SOCK_STREAM, 0);
    Assert (sd >= 0);
    Execution::Finally cleanup ([sd] () {
        ::close (sd);
    });

    int r = ::ioctl (sd, SIOCGIFCONF, (char*)&ifconf);
    Assert (r == 0);

    for (int i = 0; i < ifconf.ifc_len / sizeof(struct ifreq); ++i) {
#if     USE_NOISY_TRACE_IN_THIS_MODULE_
        DbgTrace ("interface: ifr_name=%s; ifr_addr.sa_family = %d", ifreqs[i].ifr_name, ifreqs[i].ifr_addr.sa_family);
#endif
#if     qPlatform_AIX
        // I don't understand the logic behind this, but without this, we get errors
        // in getFlags(). We could check there - and handle that with an extra return value, but this
        // is simpler.
        //
        // And - its somewhat prescribed in https://www.ibm.com/developerworks/community/forums/html/topic?id=77777777-0000-0000-0000-000014698597
        //
        if (ifreqs[i].ifr_addr.sa_family != AF_INET and ifreqs[i].ifr_addr.sa_family != AF_INET6 and ifreqs[i].ifr_addr.sa_family != AF_LINK) {
            // Skip interfaces not bound to and IPv4 or IPv6 address, or AF_LINK (not sure what later is used for)
            // this list of exceptions arrived at experimentally on the one AIX machine I tested (so not good)
            continue;
        }
#endif
        Interface   newInterface;
        String interfaceName { String::FromSDKString (ifreqs[i].ifr_name) };
        newInterface.fInternalInterfaceID = interfaceName;
        newInterface.fFriendlyName = interfaceName;         // not great - maybe find better name - but this will do for now...
        int flags = getFlags (sd, ifreqs[i].ifr_name);

        if (flags & IFF_LOOPBACK) {
            newInterface.fType = Interface::Type::eLoopback;
        }
        else {
            // NYI
            newInterface.fType = Interface::Type::eWiredEthernet;    // WAY - not the right way to tell!
        }

        if (::ioctl (sd, SIOCGIFHWADDR, &ifr) == 0 and ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
            newInterface.fHwardwareAddress = PrintMacAddr_ (reinterpret_cast<const uint8_t*> (ifr.ifr_hwaddr.sa_data), reinterpret_cast<const uint8_t*> (ifr.ifr_hwaddr.sa_data) + 6);
        }

#if     qPlatform_AIX
        {
            auto getSpeed = [] (int sd, const char* name) -> Optional<uint64_t> {
                struct ifreq ifreq;
                (void)::memset (&ifreq, 0, sizeof (ifreq));
                Characters::CString::Copy (ifreq.ifr_name, NEltsOf (ifreq.ifr_name), name);
                int r = ioctl (sd, SIOCGIFBAUDRATE, &ifreq);
                if (r != 0)
                {
                    DbgTrace ("No speed for interface %s, errno=%d", name, errno);
                    return Optional<uint64_t> ();
                }
                return ifreq.ifr_baudrate;
            };
            newInterface.fTransmitSpeedBaud = getSpeed (sd, ifreqs[i].ifr_name);
            newInterface.fReceiveLinkSpeedBaud = newInterface.fTransmitSpeedBaud;
        }
#elif   qPlatform_Linux
        {
            auto getSpeed = [] (int sd, const char* name) -> Optional<uint64_t> {
                struct ifreq ifreq {};
                Characters::CString::Copy (ifreq.ifr_name, NEltsOf (ifreq.ifr_name), name);
                struct ethtool_cmd edata {};
                ifreq.ifr_data = reinterpret_cast<caddr_t> (&edata);
                edata.cmd = ETHTOOL_GSET;
                int r = ioctl(sd, SIOCETHTOOL, &ifreq);
                if (r != 0)
                {
                    DbgTrace ("No speed for interface %s, errno=%d", name, errno);
                    return Optional<uint64_t> ();
                }
                constexpr uint64_t kMegabit_ = 1000 * 1000;
                DbgTrace ("ethtool_cmd_speed (&edata)=%d", ethtool_cmd_speed (&edata));
                switch (ethtool_cmd_speed (&edata))
                {
                    case SPEED_10:
                        return 10 * kMegabit_;
                    case SPEED_100:
                        return 100 * kMegabit_;
                    case SPEED_1000:
                        return 1000 * kMegabit_;
                    case SPEED_2500:
                        return 2500 * kMegabit_;
                    case SPEED_10000:
                        return 10000 * kMegabit_;
                    default:
                        return Optional<uint64_t> ();
                }
            };
            newInterface.fTransmitSpeedBaud = getSpeed (sd, ifreqs[i].ifr_name);
            newInterface.fReceiveLinkSpeedBaud = newInterface.fTransmitSpeedBaud;
        }
#endif

        {
            Containers::Set<Interface::Status>  status;
            if (flags & IFF_RUNNING) {
                // not right!!! But a start...
                status.Add (Interface::Status::eConnected);
                status.Add (Interface::Status::eRunning);
            }
            newInterface.fStatus = status;
        }
        newInterface.fBindings.Add (InternetAddress (((struct sockaddr_in*)&ifreqs[i].ifr_addr)->sin_addr));    // @todo fix so works for ipv6 addresses as well!
        result.Add (newInterface);
    }
#elif   qPlatform_Windows
    ULONG flags = GAA_FLAG_INCLUDE_PREFIX;
    ULONG family = AF_UNSPEC;       // Both IPv4 and IPv6 addresses
    Memory::SmallStackBuffer<Byte>  buf(0);
Again:
    ULONG ulOutBufLen = static_cast<ULONG> (buf.GetSize ());
    PIP_ADAPTER_ADDRESSES   pAddresses = reinterpret_cast<PIP_ADAPTER_ADDRESSES> (buf.begin ());
    // NB: we use GetAdapaterAddresses () instead of GetInterfaceInfo  () so we get non-ipv4 addresses
    DWORD dwRetVal = ::GetAdaptersAddresses (family, flags, nullptr, pAddresses, &ulOutBufLen);
    if (dwRetVal == NO_ERROR) {
        for (PIP_ADAPTER_ADDRESSES currAddresses  = pAddresses; currAddresses != nullptr; currAddresses = currAddresses->Next) {
            Interface   newInterface;
            String      adapterName     { String::FromNarrowSDKString (currAddresses->AdapterName) };
            newInterface.fInternalInterfaceID = adapterName;
            newInterface.fFriendlyName = currAddresses->FriendlyName;
            newInterface.fDescription = currAddresses->Description;
            switch (currAddresses->IfType) {
                case    IF_TYPE_SOFTWARE_LOOPBACK:
                    newInterface.fType = Interface::Type::eLoopback;
                    break;
                case    IF_TYPE_IEEE80211:
                    newInterface.fType = Interface::Type::eWIFI;
                    break;
                case    IF_TYPE_ETHERNET_CSMACD:
                    newInterface.fType = Interface::Type::eWiredEthernet;
                    break;
                default:
                    newInterface.fType = Interface::Type::eOther;
                    break;
            }
            if (currAddresses->TunnelType != TUNNEL_TYPE_NONE) {
                newInterface.fType = Interface::Type::eTunnel;
            }
            switch (currAddresses->OperStatus) {
                case    IfOperStatusUp:
                    newInterface.fStatus = Set<Interface::Status> ({Interface::Status::eConnected, Interface::Status::eRunning});
                    break;
                case    IfOperStatusDown:
                    newInterface.fStatus = Set<Interface::Status> ();
                    break;
                default:
                    // Dont know how to interpret the other status states
                    break;
            }
            for (PIP_ADAPTER_UNICAST_ADDRESS pu = currAddresses->FirstUnicastAddress; pu != nullptr; pu = pu->Next) {
                SocketAddress sa { pu->Address };
                if (sa.IsInternetAddress ()) {
                    newInterface.fBindings.Add (sa.GetInternetAddress ());
                }
            }
            for (PIP_ADAPTER_ANYCAST_ADDRESS pa = currAddresses->FirstAnycastAddress; pa != nullptr; pa = pa->Next) {
                SocketAddress sa { pa->Address };
                if (sa.IsInternetAddress ()) {
                    newInterface.fBindings.Add (sa.GetInternetAddress ());
                }
            }
            for (PIP_ADAPTER_MULTICAST_ADDRESS  pm = currAddresses->FirstMulticastAddress; pm != nullptr; pm = pm->Next) {
                SocketAddress sa { pm->Address };
                if (sa.IsInternetAddress ()) {
                    newInterface.fBindings.Add (sa.GetInternetAddress ());
                }
            }

            if (currAddresses->PhysicalAddressLength == 6) {
                newInterface.fHwardwareAddress = PrintMacAddr_ (currAddresses->PhysicalAddress, currAddresses->PhysicalAddress + 6);
            }

#if     (NTDDI_VERSION >= NTDDI_WIN6)
            newInterface.fTransmitSpeedBaud = currAddresses->TransmitLinkSpeed;
            newInterface.fReceiveLinkSpeedBaud = currAddresses->ReceiveLinkSpeed;
#endif
            result.Add (newInterface);
        }
    }
    else if (dwRetVal == ERROR_BUFFER_OVERFLOW) {
        buf.GrowToSize (ulOutBufLen);
        goto Again;
    }
    else if (dwRetVal == ERROR_NO_DATA) {
        DbgTrace ("There are no network adapters with IPv4 enabled on the local system");
    }
    else {
        Execution::Platform::Windows::Exception::DoThrow (dwRetVal);
    }
#else
    AssertNotImplemented ();
#endif
    return result;
}

/*
 ********************************************************************************
 ************************** Network::GetInterfaceById ***************************
 ********************************************************************************
 */
Optional<Interface>  Network::GetInterfaceById (const String& internalInterfaceID)
{
#if     USE_NOISY_TRACE_IN_THIS_MODULE_
    Debug::TraceContextBumper ctx ("Network::GetInterfaceById");
#endif
    // @todo - a much more efficent implemenation - maybe good enuf to use caller staleness cache with a few seconds staleness
    for (Interface i : Network::GetInterfaces ()) {
        if (i.fInternalInterfaceID == internalInterfaceID) {
#if     USE_NOISY_TRACE_IN_THIS_MODULE_
            DbgTrace (L"found interface %s", internalInterfaceID.c_str ());
#endif
            return i;
        }
    }
#if     USE_NOISY_TRACE_IN_THIS_MODULE_
    DbgTrace (L"interface %s not found", internalInterfaceID.c_str ());
#endif
    return Optional<Interface> ();
}
<commit_msg>fixed typo<commit_after>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2015.  All rights reserved
 */
#include    "../../StroikaPreComp.h"

#include    <cstdio>
#include    <random>

#if     qPlatform_POSIX
//@todo see how many of these includes are needed
#include    <unistd.h>
#include    <arpa/inet.h>
#include    <net/if.h>
#include    <netinet/in.h>
#include    <netdb.h>
#include    <sys/socket.h>
#include    <sys/ioctl.h>
#if     qPlatform_Linux
#include    <linux/types.h>     // needed on RedHat5
#include    <linux/ethtool.h>
#include    <linux/sockios.h>
#endif
#elif   qPlatform_Windows
#include    <WinSock2.h>
#include    <WS2tcpip.h>
#include    <Iphlpapi.h>
#include    <netioapi.h>
#endif

#include    "../../Characters/CString/Utilities.h"
#include    "../../Characters/Format.h"
#include    "../../Containers/Collection.h"
#include    "../../Containers/Mapping.h"
#include    "../../Execution/ErrNoException.h"
#include    "../../Execution/Finally.h"
#if     qPlatform_Windows
#include    "../../../Foundation/Execution/Platform/Windows/Exception.h"
#endif
#include    "../../Execution/Synchronized.h"
#include    "../../Memory/SmallStackBuffer.h"

#include    "Socket.h"

#include    "Interface.h"

using   namespace   Stroika::Foundation;
using   namespace   Stroika::Foundation::Containers;
using   namespace   Stroika::Foundation::Execution;
using   namespace   Stroika::Foundation::Memory;
using   namespace   Stroika::Foundation::IO;
using   namespace   Stroika::Foundation::IO::Network;

// Comment this in to turn on aggressive noisy DbgTrace in this module
//#define   USE_NOISY_TRACE_IN_THIS_MODULE_       1

#if     defined (_MSC_VER)
// support use of Iphlpapi - but better to reference here than in lib entry of project file cuz
// easiser to see/modularize (and only pulled in if this module is referenced)
#pragma comment (lib, "Iphlpapi.lib")
#endif

/*
 ********************************************************************************
 **************************** Network::Interface ********************************
 ********************************************************************************
 */
const Configuration::EnumNames<Interface::Status>   Interface::Stroika_Enum_Names(Status)
{
    { Interface::Status::eConnected, L"Connected" },
    { Interface::Status::eRunning, L"Running" },
};

const Configuration::EnumNames<Interface::Type>   Interface::Stroika_Enum_Names(Type)
{
    { Interface::Type::eLoopback, L"Loopback" },
    { Interface::Type::eWiredEthernet, L"WiredEthernet" },
    { Interface::Type::eWIFI, L"WIFI" },
    { Interface::Type::eTunnel, L"Tunnel" },
    { Interface::Type::eOther, L"Other" },
};

#if     qPlatform_Linux
// Hack for centos5 support:
//      Overload with linux version so other one wins, but this gets called if other doesnt exist
//      TRY --LGP 2015-05-19
template    <typename HACK = int>
static __inline__ __u32 ethtool_cmd_speed (const struct ethtool_cmd* ep, HACK i = 0)
{
    //return (ep->speed_hi << 16) | ep->speed;
    return ep->speed;
}
#endif

namespace {
    // Windows uses '-' as separator, and linux ':'. Pick arbitrarily (more linux machines
    // than windows, or soon will be)
    auto     PrintMacAddr_ (const uint8_t* macaddrBytes, const uint8_t* macaddrBytesEnd) -> String {
        Require (macaddrBytesEnd - macaddrBytes == 6);
        char     buf[100] {};
        (void)snprintf (buf, sizeof (buf), "%02x:%02x:%02x:%02x:%02x:%02x",
                        macaddrBytes[0], macaddrBytes[1],
                        macaddrBytes[2], macaddrBytes[3],
                        macaddrBytes[4], macaddrBytes[5]
                       );
        return String::FromAscii (buf);
    };
}

/*
 ********************************************************************************
 ************************** Network::GetInterfaces ******************************
 ********************************************************************************
 */
Traversal::Iterable<Interface>  Network::GetInterfaces ()
{
#if     USE_NOISY_TRACE_IN_THIS_MODULE_
    Debug::TraceContextBumper ctx ("Network::GetInterfaces");
#endif
    Collection<Interface>   result;
#if     qPlatform_POSIX
    auto getFlags = [] (int sd, const char* name) {
        struct ifreq ifreq {};
        Characters::CString::Copy (ifreq.ifr_name, NEltsOf (ifreq.ifr_name), name);

        int r = ::ioctl (sd, SIOCGIFFLAGS, (char*)&ifreq);
        Assert (r == 0);
        return ifreq.ifr_flags;
    };

    struct ifreq    ifreqs[128] {};
    struct ifconf   ifconf {};
    ifconf.ifc_req = ifreqs;
    ifconf.ifc_len = sizeof(ifreqs);

    int sd = ::socket (PF_INET, SOCK_STREAM, 0);
    Assert (sd >= 0);
    Execution::Finally cleanup ([sd] () {
        ::close (sd);
    });

    int r = ::ioctl (sd, SIOCGIFCONF, (char*)&ifconf);
    Assert (r == 0);

    for (int i = 0; i < ifconf.ifc_len / sizeof(struct ifreq); ++i) {
#if     USE_NOISY_TRACE_IN_THIS_MODULE_
        DbgTrace ("interface: ifr_name=%s; ifr_addr.sa_family = %d", ifreqs[i].ifr_name, ifreqs[i].ifr_addr.sa_family);
#endif
#if     qPlatform_AIX
        // I don't understand the logic behind this, but without this, we get errors
        // in getFlags(). We could check there - and handle that with an extra return value, but this
        // is simpler.
        //
        // And - its somewhat prescribed in https://www.ibm.com/developerworks/community/forums/html/topic?id=77777777-0000-0000-0000-000014698597
        //
        if (ifreqs[i].ifr_addr.sa_family != AF_INET and ifreqs[i].ifr_addr.sa_family != AF_INET6 and ifreqs[i].ifr_addr.sa_family != AF_LINK) {
            // Skip interfaces not bound to and IPv4 or IPv6 address, or AF_LINK (not sure what later is used for)
            // this list of exceptions arrived at experimentally on the one AIX machine I tested (so not good)
            continue;
        }
#endif
        Interface   newInterface;
        String interfaceName { String::FromSDKString (ifreqs[i].ifr_name) };
        newInterface.fInternalInterfaceID = interfaceName;
        newInterface.fFriendlyName = interfaceName;         // not great - maybe find better name - but this will do for now...
        int flags = getFlags (sd, ifreqs[i].ifr_name);

        if (flags & IFF_LOOPBACK) {
            newInterface.fType = Interface::Type::eLoopback;
        }
        else {
            // NYI
            newInterface.fType = Interface::Type::eWiredEthernet;    // WAY - not the right way to tell!
        }

        if (::ioctl (sd, SIOCGIFHWADDR, &ifr) == 0 and ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
            newInterface.fHwardwareAddress = PrintMacAddr_ (reinterpret_cast<const uint8_t*> (ifr.ifr_hwaddr.sa_data), reinterpret_cast<const uint8_t*> (ifr.ifr_hwaddr.sa_data) + 6);
        }

#if     qPlatform_AIX
        {
            auto getSpeed = [] (int sd, const char* name) -> Optional<uint64_t> {
                struct ifreq ifreq;
                (void)::memset (&ifreq, 0, sizeof (ifreq));
                Characters::CString::Copy (ifreq.ifr_name, NEltsOf (ifreq.ifr_name), name);
                int r = ioctl (sd, SIOCGIFBAUDRATE, &ifreq);
                if (r != 0)
                {
                    DbgTrace ("No speed for interface %s, errno=%d", name, errno);
                    return Optional<uint64_t> ();
                }
                return ifreq.ifr_baudrate;
            };
            newInterface.fTransmitSpeedBaud = getSpeed (sd, ifreqs[i].ifr_name);
            newInterface.fReceiveLinkSpeedBaud = newInterface.fTransmitSpeedBaud;
        }
#elif   qPlatform_Linux
        {
            auto getSpeed = [] (int sd, const char* name) -> Optional<uint64_t> {
                struct ifreq ifreq {};
                Characters::CString::Copy (ifreq.ifr_name, NEltsOf (ifreq.ifr_name), name);
                struct ethtool_cmd edata {};
                ifreq.ifr_data = reinterpret_cast<caddr_t> (&edata);
                edata.cmd = ETHTOOL_GSET;
                int r = ioctl(sd, SIOCETHTOOL, &ifreq);
                if (r != 0)
                {
                    DbgTrace ("No speed for interface %s, errno=%d", name, errno);
                    return Optional<uint64_t> ();
                }
                constexpr uint64_t kMegabit_ = 1000 * 1000;
                DbgTrace ("ethtool_cmd_speed (&edata)=%d", ethtool_cmd_speed (&edata));
                switch (ethtool_cmd_speed (&edata))
                {
                    case SPEED_10:
                        return 10 * kMegabit_;
                    case SPEED_100:
                        return 100 * kMegabit_;
                    case SPEED_1000:
                        return 1000 * kMegabit_;
                    case SPEED_2500:
                        return 2500 * kMegabit_;
                    case SPEED_10000:
                        return 10000 * kMegabit_;
                    default:
                        return Optional<uint64_t> ();
                }
            };
            newInterface.fTransmitSpeedBaud = getSpeed (sd, ifreqs[i].ifr_name);
            newInterface.fReceiveLinkSpeedBaud = newInterface.fTransmitSpeedBaud;
        }
#endif

        {
            Containers::Set<Interface::Status>  status;
            if (flags & IFF_RUNNING) {
                // not right!!! But a start...
                status.Add (Interface::Status::eConnected);
                status.Add (Interface::Status::eRunning);
            }
            newInterface.fStatus = status;
        }
        newInterface.fBindings.Add (InternetAddress (((struct sockaddr_in*)&ifreqs[i].ifr_addr)->sin_addr));    // @todo fix so works for ipv6 addresses as well!
        result.Add (newInterface);
    }
#elif   qPlatform_Windows
    ULONG flags = GAA_FLAG_INCLUDE_PREFIX;
    ULONG family = AF_UNSPEC;       // Both IPv4 and IPv6 addresses
    Memory::SmallStackBuffer<Byte>  buf(0);
Again:
    ULONG ulOutBufLen = static_cast<ULONG> (buf.GetSize ());
    PIP_ADAPTER_ADDRESSES   pAddresses = reinterpret_cast<PIP_ADAPTER_ADDRESSES> (buf.begin ());
    // NB: we use GetAdapaterAddresses () instead of GetInterfaceInfo  () so we get non-ipv4 addresses
    DWORD dwRetVal = ::GetAdaptersAddresses (family, flags, nullptr, pAddresses, &ulOutBufLen);
    if (dwRetVal == NO_ERROR) {
        for (PIP_ADAPTER_ADDRESSES currAddresses  = pAddresses; currAddresses != nullptr; currAddresses = currAddresses->Next) {
            Interface   newInterface;
            String      adapterName     { String::FromNarrowSDKString (currAddresses->AdapterName) };
            newInterface.fInternalInterfaceID = adapterName;
            newInterface.fFriendlyName = currAddresses->FriendlyName;
            newInterface.fDescription = currAddresses->Description;
            switch (currAddresses->IfType) {
                case    IF_TYPE_SOFTWARE_LOOPBACK:
                    newInterface.fType = Interface::Type::eLoopback;
                    break;
                case    IF_TYPE_IEEE80211:
                    newInterface.fType = Interface::Type::eWIFI;
                    break;
                case    IF_TYPE_ETHERNET_CSMACD:
                    newInterface.fType = Interface::Type::eWiredEthernet;
                    break;
                default:
                    newInterface.fType = Interface::Type::eOther;
                    break;
            }
            if (currAddresses->TunnelType != TUNNEL_TYPE_NONE) {
                newInterface.fType = Interface::Type::eTunnel;
            }
            switch (currAddresses->OperStatus) {
                case    IfOperStatusUp:
                    newInterface.fStatus = Set<Interface::Status> ({Interface::Status::eConnected, Interface::Status::eRunning});
                    break;
                case    IfOperStatusDown:
                    newInterface.fStatus = Set<Interface::Status> ();
                    break;
                default:
                    // Dont know how to interpret the other status states
                    break;
            }
            for (PIP_ADAPTER_UNICAST_ADDRESS pu = currAddresses->FirstUnicastAddress; pu != nullptr; pu = pu->Next) {
                SocketAddress sa { pu->Address };
                if (sa.IsInternetAddress ()) {
                    newInterface.fBindings.Add (sa.GetInternetAddress ());
                }
            }
            for (PIP_ADAPTER_ANYCAST_ADDRESS pa = currAddresses->FirstAnycastAddress; pa != nullptr; pa = pa->Next) {
                SocketAddress sa { pa->Address };
                if (sa.IsInternetAddress ()) {
                    newInterface.fBindings.Add (sa.GetInternetAddress ());
                }
            }
            for (PIP_ADAPTER_MULTICAST_ADDRESS  pm = currAddresses->FirstMulticastAddress; pm != nullptr; pm = pm->Next) {
                SocketAddress sa { pm->Address };
                if (sa.IsInternetAddress ()) {
                    newInterface.fBindings.Add (sa.GetInternetAddress ());
                }
            }

            if (currAddresses->PhysicalAddressLength == 6) {
                newInterface.fHwardwareAddress = PrintMacAddr_ (currAddresses->PhysicalAddress, currAddresses->PhysicalAddress + 6);
            }

#if     (NTDDI_VERSION >= NTDDI_WIN6)
            newInterface.fTransmitSpeedBaud = currAddresses->TransmitLinkSpeed;
            newInterface.fReceiveLinkSpeedBaud = currAddresses->ReceiveLinkSpeed;
#endif
            result.Add (newInterface);
        }
    }
    else if (dwRetVal == ERROR_BUFFER_OVERFLOW) {
        buf.GrowToSize (ulOutBufLen);
        goto Again;
    }
    else if (dwRetVal == ERROR_NO_DATA) {
        DbgTrace ("There are no network adapters with IPv4 enabled on the local system");
    }
    else {
        Execution::Platform::Windows::Exception::DoThrow (dwRetVal);
    }
#else
    AssertNotImplemented ();
#endif
    return result;
}

/*
 ********************************************************************************
 ************************** Network::GetInterfaceById ***************************
 ********************************************************************************
 */
Optional<Interface>  Network::GetInterfaceById (const String& internalInterfaceID)
{
#if     USE_NOISY_TRACE_IN_THIS_MODULE_
    Debug::TraceContextBumper ctx ("Network::GetInterfaceById");
#endif
    // @todo - a much more efficent implemenation - maybe good enuf to use caller staleness cache with a few seconds staleness
    for (Interface i : Network::GetInterfaces ()) {
        if (i.fInternalInterfaceID == internalInterfaceID) {
#if     USE_NOISY_TRACE_IN_THIS_MODULE_
            DbgTrace (L"found interface %s", internalInterfaceID.c_str ());
#endif
            return i;
        }
    }
#if     USE_NOISY_TRACE_IN_THIS_MODULE_
    DbgTrace (L"interface %s not found", internalInterfaceID.c_str ());
#endif
    return Optional<Interface> ();
}
<|endoftext|>