Page MenuHomePhabricator (Chris)

No OneTemporary

Authored By
Unknown
Size
23 KB
Referenced Files
None
Subscribers
None
diff --git a/util/file-system.cpp b/util/file-system.cpp
index 41230114..d8b1e07b 100644
--- a/util/file-system.cpp
+++ b/util/file-system.cpp
@@ -1,399 +1,403 @@
#ifdef USE_ALLEGRO
#include <allegro.h>
/* FIXME: replace with <winalleg.h> */
#ifdef _WIN32
#define BITMAP dummyBITMAP
#include <windows.h>
#undef BITMAP
#endif
#endif
#include "funcs.h"
#include "file-system.h"
#include "system.h"
#include "globals.h"
#include <dirent.h>
#include <sstream>
#include <exception>
#include <string>
#include <ostream>
#ifndef USE_ALLEGRO
/* some sfl symbols conflict with allegro */
#include "sfl/sfl.h"
#include "sfl/sfldir.h"
#endif
#ifdef _WIN32
#define _WIN32_IE 0x400
#include <shlobj.h>
#endif
using namespace std;
namespace Filesystem{
Exception::Exception(const std::string & where, int line, const std::string & file):
Exc::Base(where, line),
reason(file){
}
Exception::Exception(const std::string & where, int line, const Exc::Base & nested, const std::string & file):
Exc::Base(where, line, nested),
reason(file){
}
Exception::Exception(const Exception & copy):
Exc::Base(copy),
reason(copy.reason){
}
Exception::~Exception() throw (){
}
+
+const std::string Exception::getReason() const {
+ return reason;
+}
NotFound::NotFound(const std::string & where, int line, const std::string & file):
Exception(where, line, file + string(" was not found")){
}
NotFound::NotFound(const std::string & where, int line, const Exc::Base & nested, const std::string & file):
Exception(where, line, nested, file + string(" was not found")){
}
NotFound::NotFound(const NotFound & copy):
Exception(copy){
}
NotFound::~NotFound() throw (){
}
IllegalPath::IllegalPath(const std::string & where, int line, const std::string & file):
Exception(where, line, file){
}
IllegalPath::IllegalPath(const std::string & where, int line, const Exc::Base & nested, const std::string & file):
Exception(where, line, nested, file){
}
IllegalPath::IllegalPath(const IllegalPath & copy):
Exception(copy){
}
IllegalPath::~IllegalPath() throw(){
}
#ifdef _WIN32
AbsolutePath userDirectory(){
ostringstream str;
char path[MAX_PATH];
SHGetSpecialFolderPathA(0, path, CSIDL_APPDATA, false);
str << path << "/paintown/";
return AbsolutePath(str.str());
}
AbsolutePath configFile(){
ostringstream str;
char path[MAX_PATH];
SHGetSpecialFolderPathA(0, path, CSIDL_APPDATA, false);
str << path << "/paintown_configuration.txt";
return AbsolutePath(str.str());
}
#else
AbsolutePath configFile(){
ostringstream str;
/* what if HOME isn't set? */
str << getenv("HOME") << "/.paintownrc";
return AbsolutePath(str.str());
}
AbsolutePath userDirectory(){
ostringstream str;
/* what if HOME isn't set? */
str << getenv("HOME") << "/.paintown/";
return AbsolutePath(str.str());
}
#endif
static AbsolutePath lookup(const RelativePath path) throw (NotFound){
/* first try the main data directory */
AbsolutePath final = Util::getDataPath2().join(path);
if (System::readable(final.path())){
return final;
}
/* then try the user directory, like ~/.paintown */
final = userDirectory().join(path);
if (System::readable(final.path())){
return final;
}
/* then just look in the cwd */
if (System::readable(path.path())){
return AbsolutePath(path.path());
}
ostringstream out;
out << "Cannot find " << path.path() << ". I looked in '" << Util::getDataPath2().join(path).path() << "', '" << userDirectory().join(path).path() << "', and '" << path.path() << "'" << endl;
throw NotFound(__FILE__, __LINE__, out.str());
}
static vector<AbsolutePath> findDirectoriesIn(const AbsolutePath & path){
vector<AbsolutePath> dirs;
DIR * dir = opendir(path.path().c_str());
if (dir == NULL){
return dirs;
}
struct dirent * entry = readdir(dir);
while (entry != NULL){
string total = path.path() + "/" + entry->d_name;
if (System::isDirectory(total)){
dirs.push_back(AbsolutePath(total));
}
entry = readdir(dir);
}
closedir(dir);
return dirs;
}
vector<AbsolutePath> findDirectories(const RelativePath & path){
typedef vector<AbsolutePath> Paths;
Paths dirs;
Paths main_dirs = findDirectoriesIn(Util::getDataPath2().join(path));
Paths user_dirs = findDirectoriesIn(userDirectory().join(path));
Paths here_dirs = findDirectoriesIn(Filesystem::AbsolutePath(path.path()));
dirs.insert(dirs.end(), main_dirs.begin(), main_dirs.end());
dirs.insert(dirs.end(), user_dirs.begin(), user_dirs.end());
dirs.insert(dirs.end(), here_dirs.begin(), here_dirs.end());
return dirs;
}
vector<string> getFiles(const AbsolutePath & dataPath, const string & find){
#ifdef USE_ALLEGRO
struct al_ffblk info;
vector< string > files;
if ( al_findfirst( (dataPath.path() + find).c_str(), &info, FA_ALL ) != 0 ){
return files;
}
files.push_back( dataPath.path() + string( info.name ) );
while ( al_findnext( &info ) == 0 ){
files.push_back( dataPath.path() + string( info.name ) );
}
al_findclose( &info );
return files;
#else
vector<string> files;
DIRST sflEntry;
bool ok = open_dir(&sflEntry, dataPath.path().c_str());
while (ok){
if (file_matches(sflEntry.file_name, find.c_str())){
files.push_back(dataPath.path() + string(sflEntry.file_name));
}
ok = read_dir(&sflEntry);
}
close_dir(&sflEntry);
// Global::debug(0) << "Warning: Filesystem::getFiles() is not implemented yet for SDL" << endl;
return files;
#endif
}
/* remove extra path separators (/) */
static string sanitize(string path){
size_t double_slash = path.find("//");
while (double_slash != string::npos){
path.erase(double_slash, 1);
double_slash = path.find("//");
}
return path;
}
/*
std::string find(const std::string path){
if (path.length() == 0){
throw NotFound("No path given");
}
if (path[0] == '/'){
string str(path);
str.erase(0, 1);
string out = lookup(str);
if (System::isDirectory(out)){
return sanitize(out + "/");
}
return sanitize(out);
}
string out = lookup(path);
if (System::isDirectory(out)){
return sanitize(out + "/");
}
return sanitize(out);
}
*/
AbsolutePath find(const RelativePath & path){
if (path.isEmpty()){
throw NotFound(__FILE__, __LINE__, "No path given");
}
AbsolutePath out = lookup(path);
if (System::isDirectory(out.path())){
return AbsolutePath(sanitize(out.path() + "/"));
}
return AbsolutePath(sanitize(out.path()));
}
RelativePath cleanse(const AbsolutePath & path){
string str = path.path();
if (str.find(Util::getDataPath2().path()) == 0){
str.erase(0, Util::getDataPath2().path().length());
} else if (str.find(userDirectory().path()) == 0){
str.erase(0, userDirectory().path().length());
}
return RelativePath(str);
}
static string dirname(string path){
if (path.find("/") != string::npos ||
path.find("\\") != string::npos){
size_t rem = path.find_last_of("/");
if (rem != string::npos){
return path.substr(0, rem+1);
}
rem = path.find_last_of("\\");
if (rem != string::npos){
return path.substr(0, rem+1);
}
}
return "";
}
std::string stripDir(const std::string & str){
std::string temp = str;
if (str.find( "/") != std::string::npos || str.find( "\\") != std::string::npos){
size_t rem = temp.find_last_of( "/" );
if (rem != std::string::npos){
return str.substr(rem+1,str.size());
}
rem = temp.find_last_of( "\\" );
if( rem != std::string::npos ){
return str.substr(rem+1,str.size());
}
}
return str;
}
std::string removeExtension(const std::string & str){
if (str.find(".") != std::string::npos){
return str.substr(0, str.find_last_of("."));
}
return str;
}
const string & Path::path() const {
return mypath;
}
bool Path::isEmpty() const {
return mypath.empty();
}
Path::~Path(){
}
Path::Path(){
}
static const std::string invertSlashes(const string & str){
string tempStr = str;
if (tempStr.find('\\') != string::npos){
for (int i = tempStr.size()-1; i>-1; --i){
if (tempStr[i] == '\\'){
tempStr[i] = '/';
}
}
}
return tempStr;
}
Path::Path(const std::string & path):
mypath(sanitize(invertSlashes(path))){
}
Path::Path(const Path & path):
mypath(sanitize(invertSlashes(path.path()))){
}
RelativePath::RelativePath(){
}
RelativePath::RelativePath(const std::string & path):
Path(path){
if (! path.empty() && path[0] == '/'){
ostringstream out;
out << "Relative path '" << path << "' cannot start with a /. Only absolute paths can start with /";
throw IllegalPath(__FILE__, __LINE__, out.str());
}
}
RelativePath::RelativePath(const RelativePath & path):
Path(path){
}
RelativePath RelativePath::getDirectory() const {
return RelativePath(dirname(path()));
}
RelativePath RelativePath::getFilename() const {
return RelativePath(stripDir(path()));
}
RelativePath RelativePath::join(const RelativePath & him) const {
return RelativePath(sanitize(path() + "/" + him.path()));
}
RelativePath & RelativePath::operator=(const RelativePath & copy){
setPath(copy.path());
return *this;
}
AbsolutePath::AbsolutePath(){
}
AbsolutePath::AbsolutePath(const std::string & path):
Path(path){
}
AbsolutePath::AbsolutePath(const AbsolutePath & path):
Path(path){
}
AbsolutePath & AbsolutePath::operator=(const AbsolutePath & copy){
setPath(copy.path());
return *this;
}
bool AbsolutePath::operator==(const AbsolutePath & path) const {
return this->path() == path.path();
}
AbsolutePath AbsolutePath::getDirectory() const {
return AbsolutePath(dirname(path()));
}
AbsolutePath AbsolutePath::getFilename() const {
return AbsolutePath(stripDir(path()));
}
AbsolutePath AbsolutePath::join(const RelativePath & path) const {
return AbsolutePath(sanitize(this->path() + "/" + path.path()));
}
}
diff --git a/util/file-system.h b/util/file-system.h
index a24211db..78c6f899 100644
--- a/util/file-system.h
+++ b/util/file-system.h
@@ -1,140 +1,139 @@
#ifndef _paintown_file_system_h
#define _paintown_file_system_h
#include "exceptions/exception.h"
#include <string>
#include <vector>
namespace Filesystem{
/* sorry for the crappy abbreviation, but can't collide with the
* Exception class here
*/
namespace Exc = ::Exception;
class Exception: public Exc::Base {
public:
Exception(const std::string & where, int line, const std::string & file);
Exception(const std::string & where, int line, const Exc::Base & nested, const std::string & file);
Exception(const Exception & copy);
virtual ~Exception() throw ();
- const std::string & getReason() const {
- return reason;
- }
protected:
+ virtual const std::string getReason() const;
+
virtual Exc::Base * copy() const {
return new Exception(*this);
}
private:
std::string reason;
};
class NotFound: public Exception {
public:
NotFound(const std::string & where, int line, const std::string & file);
NotFound(const std::string & where, int line, const Exc::Base & nested, const std::string & file);
virtual ~NotFound() throw();
NotFound(const NotFound & copy);
protected:
virtual Exc::Base * copy() const {
return new NotFound(*this);
}
};
class IllegalPath: public Exception {
public:
IllegalPath(const std::string & where, int line, const std::string & file);
IllegalPath(const std::string & where, int line, const Exc::Base & nested, const std::string & file);
virtual ~IllegalPath() throw();
IllegalPath(const IllegalPath & copy);
protected:
virtual Exc::Base * copy() const {
return new IllegalPath(*this);
}
};
class Path{
public:
const std::string & path() const;
bool isEmpty() const;
virtual ~Path();
protected:
Path();
Path(const std::string & path);
Path(const Path & path);
virtual inline void setPath(const std::string & s){
mypath = s;
}
std::string mypath;
};
/* relative path should not have the leading data directory on it, just
* the path within the paintown system.
*/
class RelativePath: public Path {
public:
explicit RelativePath();
explicit RelativePath(const std::string & path);
RelativePath(const RelativePath & path);
virtual RelativePath getDirectory() const;
virtual RelativePath getFilename() const;
/* a/ + b/ = a/b/ */
RelativePath join(const RelativePath & path) const;
RelativePath & operator=(const RelativePath & copy);
};
/* absolute paths should have the entire filesystem path on it */
class AbsolutePath: public Path {
public:
explicit AbsolutePath();
explicit AbsolutePath(const std::string & path);
AbsolutePath(const AbsolutePath & path);
AbsolutePath & operator=(const AbsolutePath & copy);
bool operator==(const AbsolutePath & path) const;
virtual AbsolutePath getDirectory() const;
virtual AbsolutePath getFilename() const;
AbsolutePath join(const RelativePath & path) const;
};
/* given a relative path like sounds/arrow.png, prepend the proper
* data path to it to give data/sounds/arrow.png
*/
AbsolutePath find(const RelativePath & path);
/* remove the data path from a string
* data/sounds/arrow.png -> sounds/arrow.png
*/
RelativePath cleanse(const AbsolutePath & path);
/* returns all the directories starting with the given path.
* will look in the main data directory, the user directory, and
* the current working directory.
*/
std::vector<AbsolutePath> findDirectories(const RelativePath & path);
/* basename, just get the filename and remove the directory part */
std::string stripDir(const std::string & str);
/* remove extension. foo.txt -> foo */
std::string removeExtension(const std::string & str);
/* user specific directory to hold persistent data */
AbsolutePath userDirectory();
/* user specific path to store the configuration file */
AbsolutePath configFile();
std::vector<std::string> getFiles(const AbsolutePath & dataPath, const std::string & find);
}
#endif
diff --git a/util/load_exception.cpp b/util/load_exception.cpp
index 21c61a0d..8f79143d 100644
--- a/util/load_exception.cpp
+++ b/util/load_exception.cpp
@@ -1,26 +1,30 @@
#include <string>
#include "load_exception.h"
using namespace std;
LoadException::LoadException(const string & file, int line, const string & reason):
Exception::Base(file, line),
reason(reason){
}
LoadException::LoadException(const std::string & file, int line, const Exception::Base & nested, const std::string & reason):
Exception::Base(file, line, nested),
reason(reason){
}
LoadException::~LoadException() throw (){
}
LoadException::LoadException(const LoadException & copy):
Exception::Base(copy),
reason(copy.reason){
}
Exception::Base * LoadException::copy() const {
return new LoadException(*this);
}
+
+const std::string LoadException::getReason() const {
+ return reason;
+}
diff --git a/util/load_exception.h b/util/load_exception.h
index c28d76a8..4bef6924 100644
--- a/util/load_exception.h
+++ b/util/load_exception.h
@@ -1,31 +1,29 @@
#ifndef _load_exception_h
#define _load_exception_h
#include "exceptions/exception.h"
/* Generic load exception class. Thrown whenever a structure is being created
* and an error occurs.
*/
#include <string>
/* FIXME: put this in the Exception namespace */
class LoadException: public Exception::Base {
public:
LoadException(const std::string & file, int line, const std::string & reason);
LoadException(const std::string & file, int line, const Exception::Base & nested, const std::string & reason);
LoadException(const LoadException & copy);
- inline const std::string & getReason() const {
- return reason;
- }
-
virtual ~LoadException() throw();
protected:
+ virtual const std::string getReason() const;
+
virtual Exception::Base * copy() const;
std::string reason;
};
#endif
diff --git a/util/thread.h b/util/thread.h
index f648b8e3..4206eeb5 100644
--- a/util/thread.h
+++ b/util/thread.h
@@ -1,135 +1,182 @@
#ifndef _paintown_thread_h
#define _paintown_thread_h
#ifdef USE_SDL
#include <SDL_thread.h>
#include <SDL_mutex.h>
#else
#include <pthread.h>
#include <semaphore.h>
#endif
#include "exceptions/exception.h"
+#include "util/load_exception.h"
+#include "util/token_exception.h"
namespace Util{
/* Either uses pthreads or SDL_thread */
namespace Thread{
#ifdef USE_SDL
typedef SDL_mutex* Lock;
typedef SDL_Thread* Id;
typedef int (*ThreadFunction)(void*);
typedef SDL_semaphore* Semaphore;
#else
typedef pthread_mutex_t Lock;
typedef pthread_t Id;
typedef sem_t Semaphore;
typedef void * (*ThreadFunction)(void*);
#endif
void initializeLock(Lock * lock);
void initializeSemaphore(Semaphore * semaphore, unsigned int value);
void destroySemaphore(Semaphore * semaphore);
void semaphoreDecrease(Semaphore * semaphore);
void semaphoreIncrease(Semaphore * semaphore);
int acquireLock(Lock * lock);
int releaseLock(Lock * lock);
void destroyLock(Lock * lock);
bool createThread(Id * thread, void * attributes, ThreadFunction function, void * arg);
void joinThread(Id thread);
void cancelThread(Id thread);
}
class WaitThread{
public:
/* does not start a new thread yet */
WaitThread();
/* starts a thread */
WaitThread(Thread::ThreadFunction thread, void * arg);
/* starts a thread */
void start(Thread::ThreadFunction thread, void * arg);
bool isRunning();
void kill();
virtual ~WaitThread();
public:
/* actually runs the thread */
void doRun();
protected:
Thread::Lock doneLock;
Thread::Id thread;
volatile bool done;
void * arg;
Thread::ThreadFunction function;
};
/* wraps a boolean with lock/unlock while checking/setting it */
class ThreadBoolean{
public:
ThreadBoolean(volatile bool & what, Thread::Lock & lock);
bool get();
void set(bool value);
protected:
volatile bool & what;
Thread::Lock & lock;
};
+/* Computes stuff in a separate thread and gives it back when you ask for it.
+ * As soon as the future is created a thread will start executing and compute
+ * whatever it is that the class is supposed to do. You can then call `get'
+ * on the future object to get the result. If the thread is still executing
+ * then `get' will block until the future completes. If the future has already
+ * completed then `get' will return immediately with the computed value.
+ * The use case is computing something that has to be used later:
+ * Future future; // might take a while to compute
+ * do_stuff_that_takes_a_while(); // future might finish sometime in here
+ * Object o = future.get(); // future is already done
+ *
+ * TODO: handle exceptions
+ */
template<class X>
class Future{
+protected:
+ /* WARNING: hack to find out the type of the exception */
+ enum ExceptionType{
+ None,
+ Load,
+ Token,
+ Base
+ };
+
public:
Future():
- thing(0){
+ thing(0),
+ exception(__FILE__, __LINE__),
+ haveException(None){
/* future will increase the count */
Thread::initializeSemaphore(&future, 0);
}
virtual ~Future(){
Thread::joinThread(thread);
Thread::destroySemaphore(&future);
}
virtual X get(){
+ switch (haveException){
+ case None : break;
+ case Load : throw LoadException(__FILE__, __LINE__, exception, "Failed in future");
+ case Token: throw TokenException(exception);
+ default : throw Exception::Base(__FILE__, __LINE__, exception);
+ }
+
X out;
Thread::semaphoreDecrease(&future);
out = thing;
Thread::semaphoreIncrease(&future);
return out;
}
protected:
static void * runit(void * arg){
Future<X> * me = (Future<X>*) arg;
- me->compute();
- Thread::semaphoreIncrease(&me->future);
+ try{
+ me->compute();
+ Thread::semaphoreIncrease(&me->future);
+ } catch (const LoadException & load){
+ me->haveException = Load;
+ me->exception.set(load);
+ } catch (const TokenException & t){
+ me->haveException = Token;
+ me->exception.set(t);
+ } catch (const Exception::Base & base){
+ me->haveException = Base;
+ me->exception.set(base);
+ }
return NULL;
}
virtual void set(X x){
this->thing = x;
}
virtual void start(){
if (!Thread::createThread(&thread, NULL, (Thread::ThreadFunction) runit, this)){
throw Exception::Base(__FILE__, __LINE__);
}
}
virtual void compute() = 0;
X thing;
Thread::Id thread;
Thread::Semaphore future;
+ /* if any exceptions occur, throw them from `get' */
+ Exception::Base exception;
+ ExceptionType haveException;
};
}
#endif
diff --git a/util/token_exception.cpp b/util/token_exception.cpp
index 56fa888b..7e6df458 100644
--- a/util/token_exception.cpp
+++ b/util/token_exception.cpp
@@ -1,19 +1,24 @@
#include <string>
#include "token_exception.h"
TokenException::TokenException(const std::string & file, int line, const std::string reason):
Exception::Base(file, line),
reason(reason){
}
-
+
TokenException::TokenException(const TokenException & copy):
Exception::Base(copy),
reason(copy.reason){
}
+
+TokenException::TokenException(const Exception::Base & copy):
+Exception::Base(copy),
+reason("unknown"){
+}
Exception::Base * TokenException::copy() const {
return new TokenException(*this);
}
TokenException::~TokenException() throw() {
}
diff --git a/util/token_exception.h b/util/token_exception.h
index 59ca1386..7ea66682 100644
--- a/util/token_exception.h
+++ b/util/token_exception.h
@@ -1,25 +1,25 @@
#ifndef _paintown_token_exception_h
#define _paintown_token_exception_h
#include "exceptions/exception.h"
#include <string>
class TokenException: public Exception::Base {
public:
TokenException(const std::string & file, int line, const std::string reason = "");
+ TokenException(const TokenException & copy);
+ TokenException(const Exception::Base & base);
virtual ~TokenException() throw();
- inline const std::string & getReason() const{
- return reason;
- }
-
- TokenException(const TokenException & copy);
-
protected:
virtual Exception::Base * copy() const;
+ virtual inline const std::string getReason() const {
+ return reason;
+ }
+
std::string reason;
};
#endif

File Metadata

Mime Type
text/x-diff
Expires
Thu, Jun 11, 12:25 PM (3 w, 4 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
69021
Default Alt Text
(23 KB)

Event Timeline