Page MenuHomePhabricator (Chris)

No OneTemporary

Authored By
Unknown
Size
248 KB
Referenced Files
None
Subscribers
None
diff --git a/include/r-tech1/network/chat.h b/include/r-tech1/network/chat.h
index e9250ff7..4507486a 100644
--- a/include/r-tech1/network/chat.h
+++ b/include/r-tech1/network/chat.h
@@ -1,124 +1,124 @@
#ifndef _util_network_chat_h
#define _util_network_chat_h
#include "network.h"
-#include "util/pointer.h"
-#include "util/thread.h"
+#include "r-tech1/pointer.h"
+#include "r-tech1/thread.h"
#include <string>
#include <vector>
#include <queue>
namespace Network{
namespace Chat{
class Message{
public:
enum Type{
Ping,
Chat,
Command,
Unknown,
};
Message();
Message(const Type &);
Message(Socket socket);
Message(const Type &, const std::string &, const std::string &);
Message(const Message &);
virtual ~Message();
const Message & operator=(const Message &);
virtual void read(Socket socket);
virtual void send(Socket socket);
virtual const Type & getType() const;
virtual const std::string & getName() const;
virtual const std::string & getMessage() const;
virtual void setParameters(const std::vector<std::string> &);
virtual const std::vector<std::string> & getParameters() const;
protected:
Type type;
std::string sender;
std::string message;
std::vector<std::string> parameters;
};
class Threadable{
public:
Threadable();
virtual ~Threadable();
virtual void start();
virtual void run() = 0;
virtual void join();
protected:
::Util::Thread::Id thread;
::Util::Thread::LockObject lock;
};
class Client : public Threadable{
public:
Client(int id, Network::Socket socket);
virtual ~Client();
virtual void run();
virtual int getId() const;
virtual void sendMessage(Message &);
virtual bool hasMessages() const;
virtual Message nextMessage();
virtual void shutdown();
virtual bool isValid() const;
private:
int id;
Network::Socket socket;
bool end;
mutable std::queue<Message> messages;
bool valid;
};
class Server : public Threadable{
public:
Server(int port);
virtual ~Server();
virtual void run();
virtual void poll();
virtual void cleanup();
virtual bool hasMessages() const;
virtual Message nextMessage();
virtual void global(Message &);
virtual void relay(int id, Message &);
virtual void shutdown();
private:
Network::Socket remote;
std::vector< Util::ReferenceCount<Client> > clients;
mutable std::queue<Message> messages;
bool end;
};
}// end chat
}
-#endif
\ No newline at end of file
+#endif
diff --git a/include/r-tech1/network/irc-client.h b/include/r-tech1/network/irc-client.h
index 862969b7..61e2f508 100644
--- a/include/r-tech1/network/irc-client.h
+++ b/include/r-tech1/network/irc-client.h
@@ -1,13 +1,11 @@
#ifndef _util_network_irc_client_h
#define _util_network_irc_client_h
-#include "util/tabbed-box.h"
-
namespace Util{
namespace IRC{
class Chatter{
}
}
}
-#endif
\ No newline at end of file
+#endif
diff --git a/include/r-tech1/network/irc.h b/include/r-tech1/network/irc.h
index 8ba95e3e..1f675100 100644
--- a/include/r-tech1/network/irc.h
+++ b/include/r-tech1/network/irc.h
@@ -1,397 +1,397 @@
#ifndef _util_network_irc_h
#define _util_network_irc_h
#include "network.h"
#include "chat.h"
-#include "util/pointer.h"
-#include "util/thread.h"
+#include "r-tech1/pointer.h"
+#include "r-tech1/thread.h"
-#include "util/gui/tab-container.h"
-#include "util/gui/lineedit.h"
-#include "util/gui/list.h"
+#include "r-tech1/gui/tab-container.h"
+#include "r-tech1/gui/lineedit.h"
+#include "r-tech1/gui/list.h"
#include <string>
#include <vector>
#include <queue>
#include <map>
namespace Network{
namespace IRC{
class Command{
public:
enum Type{
Unknown,
Pass,
Nick,
User,
Userhost,
Server,
Oper,
Quit,
Squit,
Join,
Part,
Mode,
Topic,
Names,
List,
Invite,
Kick,
Version,
Stats,
Links,
Time,
Connect,
Trace,
Admin,
Info,
PrivateMessage,
Notice,
Who,
Whois,
Whowas,
Kill,
Ping,
Pong,
Error,
ErrorNickInUse,
ErrorNoSuchNick,
ErrorNoSuchChannel,
ErrorNeedMoreParams,
ErrorBannedFromChannel,
ErrorInviteOnlyChannel,
ErrorBadChannelKey,
ErrorChannelIsFull,
ReplyNames,
ReplyNamesEndOf,
ReplyNoTopic,
ReplyTopic,
ReplyTopicAuthor,
ReplyMOTD,
ReplyMOTDStart,
ReplyMOTDEndOf,
ReplyUserhost,
};
// Initializes it from an incoming message off of socket
Command(const std::string &);
// Create a message with owner and type
Command(const std::string &, const Type &);
Command(const Command &);
virtual ~Command();
virtual const Command & operator=(const Command &);
virtual std::string getSendable() const;
virtual std::string getCTCPSendable() const;
virtual inline const std::string & getOwner() const {
return this->owner;
}
virtual inline const Type & getType() const {
return this->type;
}
virtual inline void setParameters(const std::string & param1){
this->parameters.clear();
this->parameters.push_back(param1);
}
virtual inline void setParameters(const std::string & param1, const std::string & param2){
this->parameters.clear();
this->parameters.push_back(param1);
this->parameters.push_back(param2);
}
virtual inline void setParameters(const std::string & param1, const std::string & param2, const std::string & param3){
this->parameters.clear();
this->parameters.push_back(param1);
this->parameters.push_back(param2);
this->parameters.push_back(param3);
}
virtual inline void setParameters(const std::string & param1, const std::string & param2, const std::string & param3, const std::string & param4){
this->parameters.clear();
this->parameters.push_back(param1);
this->parameters.push_back(param2);
this->parameters.push_back(param3);
this->parameters.push_back(param4);
}
virtual inline void setParameters(const std::vector< std::string > & params){
this->parameters = params;
}
virtual inline const std::vector< std::string > & getParameters() const {
return this->parameters;
}
virtual inline bool hasCtcp() const {
return !this->ctcp.empty();
}
virtual inline const std::vector< std::string > & getCtcp() const {
return this->ctcp;
}
protected:
std::string owner;
Type type;
std::vector< std::string > parameters;
std::vector< std::string > ctcp;
};
class Channel{
public:
Channel();
Channel(const std::string &);
Channel(const Channel &);
~Channel();
const Channel & operator=(const Channel &);
void addUser(const std::string &);
void removeUser(const std::string &);
void replaceUser(const std::string &, const std::string &);
void addUsers(const std::vector<std::string> &);
inline const std::vector<std::string> & getUsers() const{
return this->users;
}
inline const std::string & getName() const {
return this->name;
}
inline void setTopic(const std::string & topic){
this->topic = topic;
}
inline void setTopicAuthor(const std::string & topicAuthor, uint64_t topicDate){
this->topicAuthor = topicAuthor;
this->topicDate = topicDate;
}
protected:
std::string name;
std::string topic;
std::string topicAuthor;
uint64_t topicDate;
std::vector<std::string> users;
};
// Channel ReferenceCount
typedef Util::ReferenceCount<Channel> ChannelPointer;
class Client : public Chat::Threadable{
public:
Client(const std::string &, int port);
virtual ~Client();
virtual void connect(const std::string & name = "paintown-test");
virtual void run();
virtual bool hasCommands() const;
virtual Command nextCommand() const;
virtual void sendCommand(const Command &);
virtual void sendCommand(const Command::Type &);
virtual void sendCommand(const Command::Type &, const std::string &);
virtual void sendCommand(const Command::Type &, const std::string &, const std::string &);
virtual void sendCommand(const Command::Type &, const std::string &, const std::string &, const std::string &);
virtual void sendCommand(const Command::Type &, const std::string &, const std::string &, const std::string &, const std::string &);
virtual void setName(const std::string &);
virtual inline const std::string & getName() const {
return this->username;
}
virtual void joinChannel(const std::string &);
virtual void partChannel(const std::string &);
virtual inline ChannelPointer getChannel() const {
if (this->activeChannels.empty()){
return ChannelPointer(NULL);
}
return this->activeChannels[this->currentChannel];
}
virtual inline std::vector< ChannelPointer > & channelList(){
return this->activeChannels;
}
virtual std::string channelListAsString();
virtual unsigned int getChannelIndex(const std::string &);
virtual bool isCurrentChannel(const std::string &);
virtual void setChannel(unsigned int channel);
virtual void nextChannel();
virtual void previousChannel();
virtual void sendMessage(const std::string &);
virtual void sendPong(const Command &);
virtual inline void setMessagesDisabled(bool disabled){
this->disableMessages = disabled;
}
protected:
void removeChannel(const std::string &);
ChannelPointer findChannel(const std::string &);
std::string readMessage();
//! Doesn't do anything to the command just handle some internal changes like username and channel stuff
void checkResponseAndHandle(const Command &);
Network::Socket socket;
std::string previousUsername;
std::string username;
unsigned int previousActiveChannel;
unsigned int currentChannel;
std::vector< ChannelPointer > activeChannels;
std::string hostname;
int port;
bool end;
mutable std::queue< Command > commands;
bool disableMessages;
};
namespace Message{
class EventInterface{
public:
EventInterface();
virtual ~EventInterface();
// Notify by message from local user
virtual void localNotify(const std::string &);
// Notify by command from local user
virtual void localCommand(const std::vector<std::string> &);
// Notify by message from remote
virtual void remoteNotify(const std::string &);
// Notify by command from remote
virtual void remoteCommand(const Command &);
};
class HandlerInterface{
public:
HandlerInterface();
virtual ~HandlerInterface();
typedef void *(*NotifyCallback)(const std::string &);
virtual inline void subscribe(NotifyCallback subscriber){
this->callbacks.push_back(subscriber);
}
virtual inline void subscribe(EventInterface * subscriber){
this->subscribers.push_back(subscriber);
}
protected:
// Callbacks for events and messages
std::vector<NotifyCallback> callbacks;
std::vector<EventInterface *> subscribers;
};
class QueueInterface{
public:
QueueInterface();
virtual ~QueueInterface();
virtual void addMessage(const std::string &) = 0;
class FontWrapper{
public:
FontWrapper();
virtual ~FontWrapper();
virtual int getWidth(const std::string &)=0;
virtual int getHeight()=0;
};
virtual void processMessages(FontWrapper &, int width, int height);
protected:
std::queue<std::string> messages;
std::deque<std::string> buffer;
};
}
// Create a tabbed chatter to implement in games
class ChatInterface: public Message::HandlerInterface{
public:
ChatInterface(const std::string &, int port, const std::string &);
virtual ~ChatInterface();
void act();
void draw(const Graphics::Bitmap &);
void nextChannel();
void previousChannel();
void gotoChannel(const std::string &);
Util::ReferenceCount<Client> getClient();
Util::ReferenceCount<Gui::TabItem> getCurrentTab();
Util::ReferenceCount<Gui::TabItem> getTabByName(const std::string &);
void addMessageToTab(const std::string &);
void addMessageToTab(const std::string &, const std::string &);
inline void setWidthRatio(double ratio){
this->widthRatio = ratio;
}
inline void setHeightRatio(double ratio){
this->heightRatio = ratio;
}
inline Gui::LineEdit & getInputBox() {
return this->inputBox;
}
protected:
void updateDimensions();
void remoteNotify(const std::string &);
void processRemoteCommands();
static void submit(void *);
// Notifications and commands for submit
void localNotify(const std::string &);
void localCommand(const std::vector<std::string> &);
// Update user list
void updateUserList();
void removeUser(const std::string &);
void changeUserName(const std::string &, const std::string &);
Util::ReferenceCount<Client> client;
const std::string & host;
Gui::TabContainer chatBox;
Gui::LineEdit inputBox;
Gui::SimpleList listBox;
double widthRatio;
double heightRatio;
int width;
int height;
int checkWidth;
int checkHeight;
Util::ReferenceCount<Gui::TabItem> serverTab;
// check ctcp reply
std::map<std::string, uint64_t> pingReply;
std::map< std::string, std::vector<std::string> > namesRequest;
};
}// end irc
}
#endif
diff --git a/include/r-tech1/system/init.h b/include/r-tech1/system/init.h
new file mode 100644
index 00000000..e8a7ab42
--- /dev/null
+++ b/include/r-tech1/system/init.h
@@ -0,0 +1,11 @@
+#ifndef _paintown_system_init_h
+#define _paintown_system_init_h
+
+#include "r-tech1/debug.h"
+#include "r-tech1/init.h"
+
+namespace System{
+ void initSystem(const Global::InitConditions & conditions, Global::stream_type & out);
+}
+
+#endif
diff --git a/include/r-tech1/system/timer.h b/include/r-tech1/system/timer.h
new file mode 100644
index 00000000..085eeb79
--- /dev/null
+++ b/include/r-tech1/system/timer.h
@@ -0,0 +1,19 @@
+#ifndef _paintown_system_timer_h
+#define _paintown_system_timer_h
+
+#include "r-tech1/thread.h"
+#include <vector>
+
+namespace System{
+
+extern volatile bool run_timer;
+extern Util::Thread::Lock run_timer_lock;
+extern Util::ThreadBoolean run_timer_guard;
+extern std::vector<Util::Thread::Id> running_timers;
+
+void closeTimers();
+void startTimers();
+
+}
+
+#endif
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 430f6ccd..1870e73b 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,104 +1,104 @@
# -------------------------------------------------------
# util cmake build script for paintown.
# Written by: juvinious
# Modified by: kazzmir
# -------------------------------------------------------
# -------------------------------------------------------
# Source directories containing all the necessary .cpp files
# -------------------------------------------------------
set(UTIL_SRC
argument.cpp
configuration.cpp
network/network.cpp
network/chat.cpp
network/irc.cpp
token.cpp
resource.cpp
tokenreader.cpp
timedifference.cpp
debug.cpp
timer.cpp
init.cpp
utf.cpp
console.cpp
input/keyboard.cpp
loading.cpp
messages.cpp
graphics/bitmap.cpp
graphics/image.cpp
events.cpp
font.cpp
font_factory.cpp
graphics/fire.cpp
ftalleg.cpp
funcs.cpp
directory.cpp
file-system.cpp
graphics/gradient.cpp
ebox.cpp
regex.cpp
language-string.cpp
thread.cpp
input/input.cpp
input/text-input.cpp
input/input-manager.cpp
input/input-source.cpp
input/joystick.cpp
input/allegro5/joystick.cpp
xenon/xenon.cpp
-lz4/lz4.c
+libs/lz4/lz4.c
system.cpp
version.cpp
compress.cpp
message-queue.cpp
input/linux_joystick.cpp
exceptions/load_exception.cpp
windows/funcs.cpp
windows/system.cpp
nacl/module.cpp
nacl/network-system.cpp
exceptions/exception.cpp
menu/actionfactory.cpp
menu/action_speed.cpp
menu/menu.cpp
menu/font-info.cpp
menu/menu_action.cpp
menu/menu_option.cpp
menu/options.cpp
menu/optionfactory.cpp
gui/animation.cpp
gui/box.cpp
gui/container.cpp
gui/context-box.cpp
gui/coordinate.cpp
gui/cutscene.cpp
gui/fadetool.cpp
gui/lineedit.cpp
gui/list.cpp
gui/rectarea.cpp
gui/popup-box.cpp
gui/scroll-list.cpp
gui/select-list.cpp
gui/tab-container.cpp
gui/tabbed-box.cpp
gui/timer.cpp
gui/widget.cpp
sound/sound.cpp
sound/audio.cpp
sound/music-player.cpp
sound/music-renderer.cpp
sound/music.cpp
../system/timer.cpp
../system/allegro5/timer.cpp
../system/allegro5/init.cpp)
# -------------------------------------------------------
# Include directory
# -------------------------------------------------------
#include_directories(include include/internal)
# -------------------------------------------------------
# module
# -------------------------------------------------------
add_library (util_module ${UTIL_SRC})
diff --git a/src/init.cpp b/src/init.cpp
index 47b94cc9..28c6292a 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -1,443 +1,443 @@
#ifdef USE_ALLEGRO
#include <allegro.h>
#ifdef ALLEGRO_WINDOWS
#include <winalleg.h>
#endif
#endif
/*
#ifdef USE_ALLEGRO5
#include <allegro5/allegro.h>
#include <allegro5/allegro_image.h>
#include <allegro5/allegro_primitives.h>
#endif
*/
#ifdef USE_SDL
#include <SDL.h>
#endif
#ifndef WINDOWS
#include <signal.h>
#include <string.h>
#include <unistd.h>
#endif
#if defined(LINUX) && !defined(UCLIBC)
#include <execinfo.h>
#endif
/* don't be a boring tuna */
// #warning you are ugly
/**
*
* FIXME No System, this outside util directory
*
*/
-//#include "system/init.h"
+#include "r-tech1/system/init.h"
#include "r-tech1/init.h"
#include "r-tech1/network/network.h"
#include "r-tech1/thread.h"
#include <time.h>
-//#include "system/timer.h"
+#include "r-tech1/system/timer.h"
#include <ostream>
#include "libs/dumb/include/dumb.h"
/*
#ifdef USE_ALLEGRO
#include "sound/dumb/include/aldumb.h"
#include "graphics/allegro/loadpng/loadpng.h"
#include "graphics/allegro/gif/algif.h"
#endif
*/
#include "r-tech1/graphics/bitmap.h"
#include "r-tech1/funcs.h"
#include "r-tech1/file-system.h"
#include "r-tech1/font.h"
#include "r-tech1/events.h"
#include "r-tech1/sound/sound.h"
#include "r-tech1/configuration.h"
#include "r-tech1/sound/music.h"
#include "r-tech1/resource.h"
#include "r-tech1/loading.h"
#include "r-tech1/input/keyboard.h"
#include "r-tech1/message-queue.h"
#ifdef WII
#include <fat.h>
#endif
#include "r-tech1/xenon/xenon.h"
using namespace std;
volatile int Global::speed_counter4 = 0;
bool Global::rateLimit = true;
/* enough seconds for 136 years */
volatile unsigned int Global::second_counter = 0;
/* the original engine was running at 90 ticks per second, but we dont
* need to render that fast, so TICS_PER_SECOND is really fps and
* LOGIC_MULTIPLIER will be used to adjust the speed counter to its
* original value.
*/
int Global::TICS_PER_SECOND = 40;
// const double Global::LOGIC_MULTIPLIER = (double) 90 / (double) Global::TICS_PER_SECOND;
double Global::ticksPerSecond(int ticks){
return (double) ticks / (double) TICS_PER_SECOND;
}
#ifdef USE_ALLEGRO
const int Global::WINDOWED = GFX_AUTODETECT_WINDOWED;
const int Global::FULLSCREEN = GFX_AUTODETECT_FULLSCREEN;
#else
/* FIXME: use enums here or something */
const int Global::WINDOWED = 0;
const int Global::FULLSCREEN = 1;
#endif
#if !defined(WINDOWS) && !defined(WII) && !defined(MINPSPW) && !defined(PS3) && !defined(NDS) && !defined(NACL) && !defined(XENON) && !defined(UCLIBC)
#ifdef LINUX
static void print_stack_trace(){
/* use addr2line on these addresses to get a filename and line number */
void *trace[128];
int frames = backtrace(trace, 128);
printf("Stack trace\n");
for (int i = 0; i < frames; i++){
printf(" %p\n", trace[i]);
}
}
#endif
static void handleSigSegV(int i, siginfo_t * sig, void * data){
const char * message = "Bug! Caught a memory violation. Shutting down..\n";
int dont_care = write(1, message, 48);
dont_care = dont_care;
#if defined(LINUX) && !defined(UCLIBC)
print_stack_trace();
#endif
// Global::shutdown_message = "Bug! Caught a memory violation. Shutting down..";
Graphics::setGfxModeText();
#ifdef USE_ALLEGRO
allegro_exit();
#endif
#ifdef USE_SDL
SDL_Quit();
#endif
/* write to a log file or something because sigsegv shouldn't
* normally happen.
*/
exit(1);
}
#else
#endif
/* catch a socket being closed prematurely on unix */
#if !defined(WINDOWS) && !defined(WII) && !defined(MINPSPW) && !defined(PS3) && !defined(NDS) && !defined(NACL) && !defined(XENON) && !defined(UCLIBC)
static void handleSigPipe( int i, siginfo_t * sig, void * data ){
}
/*
static void handleSigUsr1( int i, siginfo_t * sig, void * data ){
pthread_exit( NULL );
}
*/
#endif
static void registerSignals(){
#if !defined(WINDOWS) && !defined(WII) && !defined(MINPSPW) && !defined(PS3) && !defined(NDS) && !defined(NACL) && !defined(XENON) && !defined(UCLIBC)
struct sigaction action;
memset( &action, 0, sizeof(struct sigaction) );
action.sa_sigaction = handleSigPipe;
sigaction( SIGPIPE, &action, NULL );
memset( &action, 0, sizeof(struct sigaction) );
action.sa_sigaction = handleSigSegV;
sigaction( SIGSEGV, &action, NULL );
/*
action.sa_sigaction = handleSigUsr1;
sigaction( SIGUSR1, &action, NULL );
*/
#endif
}
/* mostly used for testing purposes */
#if 0
bool Global::initNoGraphics(){
/* copy/pasting the init code isn't ideal, maybe fix it later */
Global::stream_type & out = Global::debug(0);
out << "-- BEGIN init --" << endl;
out << "Data path is " << Util::getDataPath2().path() << endl;
out << "Build date " << __DATE__ << " " << __TIME__ << endl;
#ifdef WII
/* <WinterMute> fatInitDefault will set working dir to argv[0] passed by launcher,
* or root of first device mounted
*/
out << "Fat init " << (fatInitDefault() == true ? "Ok" : "Failed") << endl;
#endif
/*
char buffer[512];
if (getcwd(buffer, 512) != 0){
printf("Working directory '%s'\n", buffer);
}
*/
if (!Storage::instance().exists(Util::getDataPath2())){
Global::debug(0) << "Cannot find data path '" << Util::getDataPath2().path() << "'! Either use the -d switch to specify the data directory or find the data directory and move it to that path" << endl;
return false;
}
/* do implementation specific setup */
System::initSystem(out);
dumb_register_stdfiles();
// Sound::initialize();
// Filesystem::initialize();
/*
Graphics::SCALE_X = GFX_X;
Graphics::SCALE_Y = GFX_Y;
*/
Configuration::loadConfigurations();
const int sx = Configuration::getScreenWidth();
const int sy = Configuration::getScreenHeight();
Graphics::Bitmap::setFakeGraphicsMode(sx, sy);
/* music */
atexit(&dumb_exit);
out << "Initialize random number generator" << endl;
/* initialize random number generator */
srand(time(NULL));
registerSignals();
#ifdef HAVE_NETWORKING
out << "Initialize network" << endl;
Network::init();
atexit(Network::closeAll);
#endif
/* this mutex is used to show the loading screen while the game loads */
// Util::Thread::initializeLock(&Loader::loading_screen_mutex);
out << "-- END init --" << endl;
return true;
}
#endif
#ifdef PS3
extern "C" int SDL_JoystickInit();
static void ps3JoystickHack(){
/* FIXME: hack for the ps3. at the start of the program only 1 joystick is enabled
* even if more than 1 is connected, so we force another call to JoystickInit
* to pick up all joysticks.
*/
SDL_JoystickInit();
}
#endif
#if defined(USE_SDL) && defined(MACOSX)
#include <CoreFoundation/CoreFoundation.h>
#endif
static void maybeSetWorkingDirectory(){
#if defined(USE_SDL) && defined(MACOSX)
CFBundleRef mainBundle = CFBundleGetMainBundle();
if (mainBundle != NULL){
CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(mainBundle);
char path[PATH_MAX];
if (CFURLGetFileSystemRepresentation(resourcesURL, TRUE, (UInt8 *)path, PATH_MAX)){
chdir(path);
} else {
Global::debug(0) << "Could not set working directory to Resources" << std::endl;
}
CFRelease(resourcesURL);
}
#endif
}
Global::InitConditions::InitConditions():
graphics(Default),
sound(true),
fullscreen(false),
networking(true){
}
bool Global::init(const InitConditions & conditions){
/* Can xenon_init be moved lower? Probably.. */
#ifdef XENON
xenon_init();
#endif
Global::stream_type & out = Global::debug(0);
out << "-- BEGIN init --" << endl;
out << "Data path is " << Util::getDataPath2().path() << endl;
out << "Build date " << __DATE__ << " " << __TIME__ << endl;
maybeSetWorkingDirectory();
#ifdef WII
/* <WinterMute> fatInitDefault will set working dir to argv[0] passed by launcher,
* or root of first device mounted
*/
out << "Fat init " << (fatInitDefault() == 0 ? "Ok" : "Failed") << endl;
#endif
/*
char buffer[512];
if (getcwd(buffer, 512) != 0){
printf("Working directory '%s'\n", buffer);
}
*/
#ifndef NACL
/* do implementation specific setup */
System::initSystem(conditions, out);
#endif
dumb_register_stdfiles();
if (conditions.sound){
Sound::initialize();
}
// Filesystem::initialize();
/*
Graphics::SCALE_X = GFX_X;
Graphics::SCALE_Y = GFX_Y;
*/
Configuration::loadConfigurations();
if (conditions.graphics != InitConditions::Disabled){
const int sx = Configuration::getScreenWidth();
const int sy = Configuration::getScreenHeight();
InitConditions::WindowMode gfx = conditions.graphics;
if (conditions.graphics == InitConditions::Default){
gfx = Configuration::getFullscreen() ? InitConditions::Fullscreen : InitConditions::Window;
} else {
Configuration::setFullscreen(conditions.graphics == InitConditions::Fullscreen);
}
/* set up the screen */
int mode = WINDOWED;
switch (gfx){
case InitConditions::Disabled: break; /* won't happen */
case InitConditions::Default: break; /* already handled */
case InitConditions::Window: mode = WINDOWED; break;
case InitConditions::Fullscreen: mode = FULLSCREEN; break;
}
int gfxCode = Graphics::setGraphicsMode(mode, sx, sy);
if (gfxCode == 0){
out << "Set graphics mode: Ok" << endl;
} else {
out << "Set graphics mode: Failed! (" << gfxCode << ")" << endl;
return false;
}
}
/* music */
atexit(&dumb_exit);
out << "Initialize random number generator" << endl;
/* initialize random number generator */
srand(time(NULL));
registerSignals();
#ifdef HAVE_NETWORKING
if (conditions.networking){
out << "Initialize network" << endl;
Network::init();
atexit(Network::closeAll);
}
#endif
/* this mutex is used to show the loading screen while the game loads */
Util::Thread::initializeLock(&MessageQueue::messageLock);
Resource::initialize();
Util::Thread::initializeLock(&System::run_timer_lock);
System::run_timer = true;
Global::TICS_PER_SECOND = Configuration::getFps();
System::startTimers();
out << "-- END init --" << endl;
/*
const Font & font = Font::getDefaultFont();
// font.setSize(30, 30);
Bitmap temp(font.textLength("Loading") + 1, font.getHeight("Loading") + 1);
font.printf(0, 0, Bitmap::makeColor(255, 255, 255), temp, "Loading", 0);
temp.BlitToScreen(sx / 2, sy / 2);
*/
#ifdef PS3
// ps3JoystickHack();
#endif
return true;
}
/* Checks for the data path and blinks the screen a specific color based on its findings:
* grey: still looking
* red: failed
* white: found it
*/
bool Global::dataCheck(){
Graphics::Bitmap white(*Graphics::getScreenBuffer());
/* for nacl which takes a while to run exists(), we just want
* to show some progress
*/
white.fill(Graphics::makeColor(128, 128, 128));
white.BlitToScreen();
if (!Storage::instance().exists(Util::getDataPath2())){
white.fill(Graphics::makeColor(255, 0, 0));
white.BlitToScreen();
Global::debug(0) << "Cannot find data path '" << Util::getDataPath2().path() << "'! Either use the -d switch to specify the data directory or find the data directory and move it to that path" << endl;
/* The program is probably going to exit immediately, so allow the user some time
* to see that the red screen occured.
*/
Util::restSeconds(1);
return false;
} else {
white.fill(Graphics::makeColor(255, 255, 255));
white.BlitToScreen();
}
return true;
}
/* Restarts the timers */
void Global::setTicksPerSecond(int ticks){
if (ticks < 1){
ticks = 1;
}
if (ticks > 90){
ticks = 90;
}
if (ticks != TICS_PER_SECOND){
TICS_PER_SECOND = ticks;
System::closeTimers();
System::startTimers();
}
}
void Global::close(){
System::closeTimers();
}
diff --git a/src/menu/action_speed.cpp b/src/menu/action_speed.cpp
index a5d49986..342c6a55 100644
--- a/src/menu/action_speed.cpp
+++ b/src/menu/action_speed.cpp
@@ -1,19 +1,19 @@
-#include "action_speed.h"
-#include "util/configuration.h"
-#include "util/token.h"
+#include "r-tech1/menu/action_speed.h"
+#include "r-tech1/configuration.h"
+#include "r-tech1/token.h"
ActionSpeed::ActionSpeed(const Token *token):
speed(0.1){
token->view() >> speed;
}
ActionSpeed::~ActionSpeed(){
}
void ActionSpeed::act(){
if (speed < 0.1){
speed = 0.1;
}
Configuration::setGameSpeed(speed);
}
diff --git a/src/menu/actionfactory.cpp b/src/menu/actionfactory.cpp
index 514726eb..c761cc54 100644
--- a/src/menu/actionfactory.cpp
+++ b/src/menu/actionfactory.cpp
@@ -1,20 +1,20 @@
-#include "actionfactory.h"
-#include "util/token.h"
-#include "util/debug.h"
-#include "action_speed.h"
+#include "r-tech1/menu/actionfactory.h"
+#include "r-tech1/token.h"
+#include "r-tech1/debug.h"
+#include "r-tech1/menu/action_speed.h"
using namespace std;
void ActionAct(Token *token){
const Token * tok;
token->view() >> tok;
if ( *tok == "background" ){
} else if (*tok == "fixedspeed") {
ActionSpeed temp(tok);
temp.act();
} else {
Global::debug( 3 ) <<"Unhandled menu attribute: "<<endl;
tok->print(" ");
}
}
diff --git a/src/menu/font-info.cpp b/src/menu/font-info.cpp
index 6ed7361d..0f30e137 100644
--- a/src/menu/font-info.cpp
+++ b/src/menu/font-info.cpp
@@ -1,43 +1,43 @@
-#include "font-info.h"
-#include "util/file-system.h"
-#include "util/font.h"
-#include "util/configuration.h"
-#include "util/exceptions/exception.h"
+#include "r-tech1/menu/font-info.h"
+#include "r-tech1/file-system.h"
+#include "r-tech1/font.h"
+#include "r-tech1/configuration.h"
+#include "r-tech1/exceptions/exception.h"
namespace Menu{
FontInfo::FontInfo(){
}
FontInfo::~FontInfo(){
}
static bool menuFontAvailable(){
return Configuration::getMenuFont() != NULL;
}
bool RelativeFontInfo::operator==(const FontInfo & who) const {
return who == *this;
}
bool RelativeFontInfo::operator==(const AbsoluteFontInfo & who) const {
return getName() == who.getName();
}
bool RelativeFontInfo::operator==(const RelativeFontInfo & who) const {
return path == who.path;
}
bool AbsoluteFontInfo::operator==(const FontInfo & who) const {
return who == *this;
}
bool AbsoluteFontInfo::operator==(const AbsoluteFontInfo & who) const {
return path == who.path;
}
bool AbsoluteFontInfo::operator==(const RelativeFontInfo & who) const {
return getName() == who.getName();
}
}
diff --git a/src/menu/menu.cpp b/src/menu/menu.cpp
index 1642ec80..bc516d99 100644
--- a/src/menu/menu.cpp
+++ b/src/menu/menu.cpp
@@ -1,1853 +1,1853 @@
-#include "util/graphics/bitmap.h"
-#include "menu.h"
-#include "menu_option.h"
-#include "util/version.h"
-#include "util/funcs.h"
-#include "util/sound/sound.h"
-#include "util/font.h"
-#include "util/token.h"
-#include "util/events.h"
-#include "util/tokenreader.h"
-#include "util/file-system.h"
-#include "util/resource.h"
-#include "util/debug.h"
-#include "util/init.h"
-#include "util/configuration.h"
-#include "util/sound/music.h"
-#include "util/graphics/gradient.h"
-#include "util/exceptions/shutdown_exception.h"
-#include "util/exceptions/exception.h"
-
-#include "optionfactory.h"
-#include "actionfactory.h"
-
-#include "util/input/input-manager.h"
-#include "util/input/input-map.h"
-#include "util/input/input-source.h"
-#include "util/parameter.h"
+#include "r-tech1/graphics/bitmap.h"
+#include "r-tech1/menu/menu.h"
+#include "r-tech1/menu/menu_option.h"
+#include "r-tech1/version.h"
+#include "r-tech1/funcs.h"
+#include "r-tech1/sound/sound.h"
+#include "r-tech1/font.h"
+#include "r-tech1/token.h"
+#include "r-tech1/events.h"
+#include "r-tech1/tokenreader.h"
+#include "r-tech1/file-system.h"
+#include "r-tech1/resource.h"
+#include "r-tech1/debug.h"
+#include "r-tech1/init.h"
+#include "r-tech1/configuration.h"
+#include "r-tech1/sound/music.h"
+#include "r-tech1/graphics/gradient.h"
+#include "r-tech1/exceptions/shutdown_exception.h"
+#include "r-tech1/exceptions/exception.h"
+
+#include "r-tech1/menu/optionfactory.h"
+#include "r-tech1/menu/actionfactory.h"
+
+#include "r-tech1/input/input-manager.h"
+#include "r-tech1/input/input-map.h"
+#include "r-tech1/input/input-source.h"
+#include "r-tech1/parameter.h"
#include <queue>
#include <map>
#include <ostream>
#include <sstream>
-#include "util/gui/context-box.h"
+#include "r-tech1/gui/context-box.h"
using namespace std;
using namespace Gui;
/* the current font is a property of the dynamic execution. so it will
* be modified by various functions that call Parameter::push
*/
static const Font & currentFont(){
return Menu::menuFontParameter.current()->get();
}
Util::Parameter<Util::ReferenceCount<Menu::FontInfo> > Menu::menuFontParameter;
/*
static std::string sharedFont = "fonts/arial.ttf";
static int sharedFontWidth = 24;
static int sharedFontHeight = 24;
*/
Effects::Gradient Menu::standardGradient(){
return Gui::standardGradient(50);
}
Menu::Point::Point():
x(0),
y(0){
}
Menu::Point::Point(int x, int y):
x(x),
y(y){
}
Menu::Point::~Point(){
}
Menu::InfoBox::InfoBox():
state(NotActive),
fadeAlpha(0){
popup.setFadeSpeed(20);
}
Menu::InfoBox::~InfoBox(){
}
void Menu::InfoBox::act(const Font & font){
popup.act(font);
int speed = 9;
switch (state){
case Opening: {
if (fadeAlpha < 255){
fadeAlpha += speed;
}
if (fadeAlpha >= 255){
fadeAlpha = 255;
if (popup.isActive()){
state = Active;
}
}
break;
}
case Closing: {
if (fadeAlpha > 0){
fadeAlpha -= speed;
}
if (fadeAlpha <= 0){
fadeAlpha = 0;
if (!popup.isActive()){
state = NotActive;
}
}
break;
}
case Active:
case NotActive:
default:
break;
}
}
void Menu::InfoBox::render(const Graphics::Bitmap &){
throw MenuException(__FILE__, __LINE__, "Don't call the render(Bitmap) function");
}
void Menu::InfoBox::render(const Graphics::Bitmap & bmp, const Font & vFont){
popup.render(bmp);
// const Font & vFont = Configuration::getMenuFont()->get(*font);
const int x1 = popup.getArea().getX()+(int)(popup.getTransforms().getRadius()/2);
const int y1 = popup.getArea().getY()+2;
const int x2 = popup.getArea().getX2()-(int)(popup.getTransforms().getRadius()/2);
const int y2 = popup.getArea().getY2()-2;
bmp.setClipRect(x1, y1, x2, y2);
// FIXME height is proportionally wrong in a majority of the cases, this is perhaps due to ftalleg.
int sy = location.getY() - vFont.getHeight()/6;// - location.getHeight()/2 - vFont.getHeight()/2;
static Graphics::Color white = Graphics::makeColor(255,255,255);
unsigned int padding_index = 0;
for (vector<string>::iterator it = text.begin(); it != text.end(); it++){
string & str = *it;
if (fadeAlpha < 255){
Graphics::Bitmap::transBlender(0, 0, 0, fadeAlpha);
vFont.printf(location.getX() + padding[padding_index]/2, sy, white, bmp.translucent(), str, 0 );
} else {
vFont.printf(location.getX() + padding[padding_index]/2, sy, white, bmp, str, 0 );
}
sy += vFont.getHeight();
padding_index++;
}
bmp.setClipRect(0, 0, bmp.getWidth(), bmp.getHeight());
}
void Menu::InfoBox::open(){
state = Opening;
popup.location = location;
popup.transforms = transforms;
popup.colors = colors;
popup.open();
fadeAlpha = 0;
}
void Menu::InfoBox::close(){
state = Closing;
popup.close();
}
/* dimensions are computed lazily when we get a font, but only compute once per font */
void Menu::InfoBox::initialize(const Font & font){
int maxWidth = 0;
int height = 0;
for (vector<string>::iterator it = text.begin(); it != text.end(); it++){
// Add the padding
ostringstream pad;
pad << (*it)[0] << (*it)[(*it).size()-1];
padding.push_back(font.textLength(pad.str().c_str()));
int w = font.textLength((*it).c_str()) + padding.back();
if (w > maxWidth){
maxWidth = w;
}
height += font.getHeight();
}
location.setDimensions(maxWidth, height);
}
void Menu::InfoBox::setText(const std::string & info){
if (info.empty()){
return;
}
text.clear();
// const Font & vFont = Configuration::getMenuFont()->get(*font);
size_t start = 0;
size_t last = 0;
start = info.find("\n");
while (start != string::npos){
text.push_back(info.substr(last, start - last));
last = start + 1;
start = info.find("\n", last);
}
text.push_back(info.substr(last));
}
static std::vector<Util::ReferenceCount<ContextItem> > toContextList(const ContextBox & context, const std::vector<Util::ReferenceCount<MenuOption> > & list){
std::vector<Util::ReferenceCount<ContextItem> > contextItems;
for (std::vector<Util::ReferenceCount<MenuOption> >::const_iterator i = list.begin(); i != list.end(); ++i){
const Util::ReferenceCount<MenuOption> & option = *i;
contextItems.push_back(option);
}
return contextItems;
}
static void tryPlaySound(const Filesystem::RelativePath & path){
Util::ReferenceCount<Sound> ok = Resource::getSound(path);
if (ok != NULL){
ok->play();
}
}
/*
* FIXME Exception handling for ValueHolder*/
Menu::MenuException::MenuException(const std::string & file, int line, const std::string reason ):
Exception::Base(file, line),
reason(reason){
}
Menu::MenuException::MenuException(const MenuException & copy):
Exception::Base(copy),
reason(copy.reason){
}
Menu::MenuException::MenuException(const Exception::Base & copy):
Exception::Base(copy),
reason("unknown"){
}
Menu::MenuException::~MenuException() throw(){
}
Exception::Base * Menu::MenuException::copy() const {
return new MenuException(*this);
}
Menu::Reload::Reload(const std::string & file, int line, const std::string reason):
MenuException(file, line, reason){
}
Menu::Reload::~Reload() throw() {
}
Exception::Base * Menu::Reload::copy() const {
return new Reload(*this);
}
Menu::ValueHolder::ValueHolder(const std::string & name):
name(name),
location(0){
}
Menu::ValueHolder::~ValueHolder(){
}
Menu::ValueHolder::ValueHolder(const ValueHolder & copy){
// reset position
this->location = 0;
this->name = copy.name;
this->values = copy.values;
}
Menu::ValueHolder & Menu::ValueHolder::operator=(const ValueHolder & copy){
// reset position
this->location = 0;
this->name = copy.name;
this->values = copy.values;
return *this;
}
Menu::ValueHolder & Menu::ValueHolder::operator<<(const std::string & val){
values.push_back(val);
return *this;
}
Menu::ValueHolder & Menu::ValueHolder::operator<<(bool val){
std::ostringstream o;
o << val;
return *this << o.str();
}
Menu::ValueHolder & Menu::ValueHolder::operator<<(int val){
std::ostringstream o;
o << val;
return *this << o.str();
}
Menu::ValueHolder & Menu::ValueHolder::operator<<(double val){
std::ostringstream o;
o << val;
return *this << o.str();
}
Menu::ValueHolder & Menu::ValueHolder::operator<<(TokenView & view){
std::string temp;
view >> temp;
return *this << temp;
}
Menu::ValueHolder & Menu::ValueHolder::operator>>(std::string & val){
if (values[location].empty()){
throw MenuException(__FILE__, __LINE__, "Empty value.");
}
val = values[location];
next();
return *this;
}
Menu::ValueHolder & Menu::ValueHolder::operator>>(bool & val){
if (values[location].empty()){
throw MenuException(__FILE__, __LINE__, "Empty value.");
}
std::istringstream i(values[location]);
i >> val;
next();
return *this;
}
Menu::ValueHolder & Menu::ValueHolder::operator>>(int & val){
if (values[location].empty()){
throw MenuException(__FILE__, __LINE__, "Empty value.");
}
std::istringstream i(values[location]);
i >> val;
next();
return *this;
}
Menu::ValueHolder & Menu::ValueHolder::operator>>(double & val){
if (values[location].empty()){
throw MenuException(__FILE__, __LINE__, "Empty value.");
}
std::istringstream i(values[location]);
i >> val;
next();
return *this;
}
void Menu::ValueHolder::next(){
location++;
if (location >= values.size()){
location = 0;
}
}
const std::string Menu::ValueHolder::getValues() {
std::string temp;
for (std::vector<std::string>::iterator i = values.begin(); i != values.end(); ++i){
temp += *i + "; ";
}
return temp;
}
static bool parseDisplayList(const Token * token, ContextBox & menu){
if (*token == "display-list"){
TokenView view = token->view();
while (view.hasMore()){
const Token * tok;
view >> tok;
std::string type;
bool wrap = true;
if (tok->match("type", type)){
if (type == "normal"){
menu.setListType(ContextBox::Normal);
} else if (type == "scroll"){
menu.setListType(ContextBox::Scroll);
}
} else if (tok->match("wrap", wrap)){
menu.setListWrap(wrap);
} else if ( *tok == "items"){
Gui::ListValues values;
values.getValues(tok);
menu.setListValues(values);
}
}
return true;
}
return false;
}
Menu::Renderer::Renderer(){
}
Menu::Renderer::~Renderer(){
// Kill info boxes
for (std::vector< ::Menu::InfoBox *>::iterator i = info.begin(); i != info.end();++i){
if (*i){
delete *i;
}
}
}
/*
void Menu::Renderer::setFont(const Util::ReferenceCount<FontInfo> & font){
}
*/
void Menu::Renderer::addInfo(const std::string & text, const Gui::Widget & defaults, Context & context, const Font & font){
if (!info.empty()){
info.back()->close();
}
if (text.empty()){
return;
}
::Menu::InfoBox * temp = new ::Menu::InfoBox();
// temp->setFont(context.getFont());
temp->setText(text);
temp->initialize(font);
const int width = temp->location.getWidth();
const int height = temp->location.getHeight();
temp->location.setPosition(Gui::AbsolutePoint(context.getInfoLocation().getX() - width/2, context.getInfoLocation().getY() - height/2));
// have to pass the dimensions back in to correct proper placement
temp->location.setPosition2(Gui::AbsolutePoint(temp->location.getX() + width,temp->location.getY() + height));
temp->transforms.setRadius(defaults.transforms.getRadius());
temp->colors = defaults.colors;
temp->open();
info.push_back(temp);
}
void Menu::Renderer::actInfo(const Font & font){
for (std::vector< ::Menu::InfoBox *>::iterator i = info.begin(); i != info.end();){
::Menu::InfoBox *box = *i;
box->act(font);
if (!box->isActive()){
delete box;
i = info.erase(i);
} else {
i++;
}
}
}
void Menu::Renderer::renderInfo(const Graphics::Bitmap & work, const Font & font){
for (std::vector< ::Menu::InfoBox *>::iterator i = info.begin(); i != info.end(); ++i){
::Menu::InfoBox *box = *i;
box->render(work, font);
}
}
Menu::DefaultRenderer::DefaultRenderer():
hasOverride(false),
overrideIndex(0){
// Default the menu to a certain size and details
menu.transforms.setRadius(15);
menu.location.set(-.6, -.3, .6, .8);
menu.colors.body = Graphics::makeColor(0,0,0);
menu.colors.bodyAlpha = 128;
menu.colors.border = Graphics::makeColor(200,200,200);
menu.colors.borderAlpha = 255;
}
vector<Util::ReferenceCount<MenuOption> > Menu::DefaultRenderer::getOptions() const {
return options;
}
void Menu::DefaultRenderer::setPosition(const Gui::Coordinate & coordinate){
menu.location = coordinate;
}
void Menu::DefaultRenderer::invokeOverride(const Context & context){
if (hasOverride){
options[overrideIndex]->run(context);
throw Exception::Return(__FILE__, __LINE__);
}
}
Menu::DefaultRenderer::~DefaultRenderer(){
}
Menu::Renderer::Type Menu::DefaultRenderer::getType() const {
return Default;
}
bool Menu::DefaultRenderer::readToken(const Token * token, const OptionFactory & factory){
if( *token == "option" ) {
try{
MenuOption * temp = factory.getOption(menu, token);
if (temp){
// Check for info/name
{
TokenView view = token->view();
while (view.hasMore()){
const Token * tok;
view >> tok;
try{
if (*tok == "info"){
temp->addInfo(tok);
} else if (*tok == "name"){
temp->addName(tok);
}
} catch (const TokenException & ex){
// Output something
}
}
}
options.push_back(Util::ReferenceCount<MenuOption>(temp));
if (!hasOverride){
const Token * tok;
token->view() >> tok;
if (tok->findToken("_/override") != NULL){
overrideIndex = options.size()-1;
hasOverride = true;
}
}
}
} catch (const LoadException & le){
Global::debug(0) << "Could not read option: " << le.getTrace() << endl;
token->print(" ");
}
} else if ( *token == "position" ) {
// This handles the placement of the menu list and surrounding box
menu.setCoordinates(token);
} else if ( *token == "relative-position"){
menu.setCoordinates(token);
} else if ( *token == "coordinate"){
menu.setCoordinates(token);
} else if ( *token == "position-body" ) {
// This handles the body color of the menu box
menu.setColors(token);
} else if ( *token == "position-border" ) {
// This handles the border color of the menu box
menu.setColors(token);
} else if ( *token == "transforms" ) {
// This handles the border color of the menu box
menu.setTransforms(token);
} else if ( *token == "fade-speed" ) {
// Menu fade in speed
int speed;
token->view() >> speed;
menu.setFadeSpeed(speed);
} else if ( parseDisplayList(token, menu) ){
} else {
return false;
}
return true;
}
void Menu::DefaultRenderer::initialize(Context & context){
menu.setList(toContextList(menu, options));
menu.open();
// const Font & font = Configuration::getMenuFont()->get(context.getFont()->get());
const Font & font = currentFont();
// Menu info
if (!context.getMenuInfoText().empty()){
menuInfo.setText(context.getMenuInfoText());
menuInfo.initialize(font);
const int width = menuInfo.location.getWidth();
const int height = menuInfo.location.getHeight();
menuInfo.location.setPosition(Gui::AbsolutePoint(context.getMenuInfoLocation().getX() - width/2, context.getMenuInfoLocation().getY() - height/2));
// have to pass the dimensions back in to correct proper placement
menuInfo.location.setPosition2(Gui::AbsolutePoint(menuInfo.location.getX() + width, menuInfo.location.getY() + height));
menuInfo.transforms.setRadius(menu.transforms.getRadius());
menuInfo.colors = menu.colors;
}
menuInfo.open();
// Add first info option
addInfo(options[menu.getCurrentIndex()]->getInfoText(), menu, context, font);
}
void Menu::DefaultRenderer::finish(){
menu.close();
menuInfo.close();
}
bool Menu::DefaultRenderer::active(){
return menu.isActive();
}
void Menu::DefaultRenderer::act(const Context & context){
// const Font & font = Configuration::getMenuFont()->get(context.getFont()->get());
const Font & font = currentFont();
// FIXME find a better way to get options to update this is a waste
for (std::vector<Util::ReferenceCount<MenuOption> >::iterator i = options.begin(); i != options.end(); ++i){
Util::ReferenceCount<MenuOption> & option = *i;
option->logic();
}
menu.act(font);
menuInfo.act(font);
actInfo(font);
}
void Menu::DefaultRenderer::render(const Graphics::Bitmap & bmp, const Font & font){
menu.render(bmp, font);
menuInfo.render(bmp, font);
renderInfo(bmp, font);
}
void Menu::DefaultRenderer::addOption(MenuOption * opt){
this->options.push_back(Util::ReferenceCount<MenuOption>(opt));
}
void Menu::DefaultRenderer::doAction(const Actions & action, Context & context){
const Font & font = currentFont();
switch(action){
case Up:
if (menu.previous(font)){
context.playSound(Up);
addInfo(options[menu.getCurrentIndex()]->getInfoText(), menu, context, font);
}
break;
case Down:
if (menu.next(font)){
context.playSound(Down);
addInfo(options[menu.getCurrentIndex()]->getInfoText(), menu, context, font);
}
break;
case Left:
if (options[menu.getCurrentIndex()]->leftKey()){
// setFont(context.getFont());
context.playSound(Left);
}
break;
case Right:
if (options[menu.getCurrentIndex()]->rightKey()){
// setFont(context.getFont());
context.playSound(Right);
}
break;
case Select: {
if (options[menu.getCurrentIndex()]->isRunnable()){
try{
context.playSound(Select);
options[menu.getCurrentIndex()]->run(context);
} catch (const Reload & reload){
menu.open();
menuInfo.open();
}
// setFont(context.getFont());
context.playMusic();
/* font might have been recreated */
const Font & font = currentFont();
addInfo(options[menu.getCurrentIndex()]->getInfoText(), menu, context, font);
menuInfo.initialize(font);
}
break;
}
case Cancel:
context.playSound(Cancel);
throw Exception::Return(__FILE__, __LINE__);
break;
default:
break;
}
}
Menu::TabInfo::TabInfo(){
}
Menu::TabInfo::~TabInfo(){
}
void Menu::TabInfo::act(){
// Miguel: FIXME find a better way to get options to update this is a waste
// Jon: Whats wrong with it?
for (std::vector<Util::ReferenceCount<MenuOption> >::iterator i = options.begin(); i != options.end(); ++i){
Util::ReferenceCount<MenuOption> & option = *i;
option->logic();
}
}
Menu::TabRenderer::TabRenderer():
hasOverride(false),
overrideIndex(0){
// Default the menu to a certain size and details
//menu.transforms.setRadius(15);
menu.location.set(-.6, -.3, .6, .8);
menu.colors.body = Graphics::makeColor(0,0,0);
menu.colors.bodyAlpha = 128;
menu.colors.border = Graphics::makeColor(200,200,200);
menu.colors.borderAlpha = 255;
}
Menu::Renderer::Type Menu::TabRenderer::getType() const {
return Tabbed;
}
void Menu::TabRenderer::setPosition(const Gui::Coordinate & coordinate){
menu.location = coordinate;
}
vector<Util::ReferenceCount<MenuOption> > Menu::TabRenderer::getOptions() const {
vector<Util::ReferenceCount<MenuOption> > options;
for (vector<TabInfo *>::const_iterator it = tabs.begin(); it != tabs.end(); ++it){
options.insert(options.end(), (*it)->options.begin(), (*it)->options.end());
}
return options;
}
/* FIXME need to implement override for tabs */
void Menu::TabRenderer::invokeOverride(const Context & context){
if (hasOverride){
//options[overrideIndex]->run(context);
throw Exception::Return(__FILE__, __LINE__);
}
}
Menu::TabRenderer::~TabRenderer(){
// Kill tabs
for (std::vector<TabInfo *>::iterator i = tabs.begin(); i != tabs.end(); ++i){
if (*i){
delete *i;
}
}
}
bool Menu::TabRenderer::readToken(const Token * token, const OptionFactory & factory){
if (*token == "menu"){
TabInfo * tabInfo = new TabInfo();
Gui::Tab * tab = new Gui::Tab();
TokenView view = token->view();
while (view.hasMore()){
const Token * tok;
view >> tok;
try{
if (*tok == "name"){
tok->view() >> tabInfo->name;
tok->view() >> tab->name;
} else if (*tok == "info"){
tok->view() >> tabInfo->info;
} else if (*tok == "menuinfo"){
tok->view() >> tabInfo->menuInfo;
} else if (parseDisplayList(tok, tab->getContext())){
} else if (*tok == "option"){
try {
MenuOption *temp = factory.getOption(tab->getContext(), tok);
if (temp){
// Check for info/name
{
TokenView info = tok->view();
while (info.hasMore()){
const Token * check;
info >> check;
try{
if (*check == "info"){
temp->addInfo(check);
} else if (*check == "name"){
temp->addName(check);
}
} catch (const TokenException & ex){
// Output something
}
}
}
Util::ReferenceCount<MenuOption> ref(temp);
tabInfo->options.push_back(ref);
tab->addOption(ref);
// tab->addOption(ref->getAsScrollItem<ContextItem>(tab->getContext()));
}
} catch (const LoadException & le){
tok->print(" ");
}
}
} catch (const TokenException & ex){
// Output something
}
}
menu.addTab(tab);
tabs.push_back(tabInfo);
} else if ( *token == "position" ) {
// This handles the placement of the menu list and surrounding box
menu.setCoordinates(token);
} else if ( *token == "relative-position"){
menu.setCoordinates(token);
} else if ( *token == "coordinate"){
menu.setCoordinates(token);
} else if ( *token == "position-body" ) {
// This handles the body color of the menu box
menu.setColors(token);
} else if ( *token == "position-border" ) {
// This handles the border color of the menu box
menu.setColors(token);
} else if ( *token == "transforms" ) {
// This handles the border color of the menu box
menu.setTransforms(token);
} else if ( *token == "tab-body" ) {
int r,g,b;
token->view() >> r >> g >> b >> menu.tabColors.bodyAlpha;
menu.tabColors.body = Graphics::makeColor(r,g,b);
} else if ( *token == "tab-border" ) {
int r,g,b;
token->view() >> r >> g >> b >> menu.tabColors.borderAlpha;
menu.tabColors.border = Graphics::makeColor(r,g,b);
} else if ( *token == "selectedtab-body" ) {
int r,g,b;
token->view() >> r >> g >> b >> menu.selectedTabColors.bodyAlpha;
menu.selectedTabColors.body = Graphics::makeColor(r,g,b);
} else if ( *token == "selectedtab-border" ) {
int r,g,b;
token->view() >> r >> g >> b >> menu.selectedTabColors.borderAlpha;
menu.selectedTabColors.border = Graphics::makeColor(r,g,b);
} else if ( *token == "runningtab-body" ) {
int r,g,b;
token->view() >> r >> g >> b >> menu.runningTabColors.bodyAlpha;
menu.runningTabColors.body = Graphics::makeColor(r,g,b);
} else if ( *token == "runningtab-border" ) {
int r,g,b;
token->view() >> r >> g >> b >> menu.runningTabColors.borderAlpha;
menu.runningTabColors.border = Graphics::makeColor(r,g,b);
} else if ( *token == "font-color" ) {
int r,g,b;
token->view() >> r >> g >> b;
menu.setTabFontColor(Graphics::makeColor(r,g,b));
} else if ( *token == "selectedfont-color" ) {
int r,g,b;
token->view() >> r >> g >> b;
menu.setSelectedTabFontColor(Graphics::makeColor(r,g,b));
} else if ( *token == "runningfont-color" ) {
} else if ( *token == "fade-speed" ) {
// Menu fade in speed
int speed;
token->view() >> speed;
//menu.setFadeSpeed(speed);
} else {
return false;
}
return true;
}
void Menu::TabRenderer::initialize(Context & context){
const Font & font = currentFont();
// Menu info
if (!context.getMenuInfoText().empty()){
menuInfo.setText(context.getMenuInfoText());
menuInfo.initialize(font);
const int width = menuInfo.location.getWidth();
const int height = menuInfo.location.getHeight();
menuInfo.location.setPosition(Gui::AbsolutePoint(context.getMenuInfoLocation().getX() - width/2, context.getMenuInfoLocation().getY() - height/2));
// have to pass the dimensions back in to correct proper placement
menuInfo.location.setPosition2(Gui::AbsolutePoint(menuInfo.location.getX() + width,menuInfo.location.getY() + height));
menuInfo.transforms.setRadius(menu.transforms.getRadius());
menuInfo.colors = menu.colors;
}
menuInfo.open();
if (tabs.size() > 0 && tabs[menu.getCurrentTab()]->options.size() > menu.getCurrentIndex()){
// Add first info option
addInfo(tabs[menu.getCurrentTab()]->options[menu.getCurrentIndex()]->getInfoText(), menu, context, font);
}
}
void Menu::TabRenderer::finish(){
//menu.close();
menuInfo.close();
}
bool Menu::TabRenderer::active(){
return true;//menu.isActive();
}
void Menu::TabRenderer::act(const Context & context){
const Font & font = currentFont();
// FIXME find a better way to get options to update this is a waste
for (std::vector<TabInfo *>::iterator i = tabs.begin(); i != tabs.end(); ++i){
TabInfo * tab = *i;
tab->act();
}
menu.act(font);
menuInfo.act(font);
actInfo(font);
}
void Menu::TabRenderer::render(const Graphics::Bitmap & bmp, const Font & font){
menu.render(bmp, font);
menuInfo.render(bmp, font);
renderInfo(bmp, font);
}
void Menu::TabRenderer::addOption(MenuOption * opt){
//this->options.push_back(opt);
}
void Menu::TabRenderer::doAction(const Actions & action, Context & context){
const Font & font = currentFont();
bool updateInfo = false;
switch (action){
case Up:
menu.up(font);
context.playSound(Up);
updateInfo = true;
break;
case Down:
menu.down(font);
context.playSound(Down);
updateInfo = true;
break;
case Left:
menu.left(font);
context.playSound(Up);
updateInfo = true;
break;
case Right:
menu.right(font);
context.playSound(Down);
updateInfo = true;
break;
case Select:
try{
if (!menu.isInTab()){
menu.toggleTabSelect();
} else {
if (menu.getCurrentTab() < tabs.size() &&
menu.getCurrentIndex() < tabs[menu.getCurrentTab()]->options.size() &&
tabs[menu.getCurrentTab()]->options[menu.getCurrentIndex()]->isRunnable()){
tabs[menu.getCurrentTab()]->options[menu.getCurrentIndex()]->run(context);
}
// tabs[menu.getCurrentTab()]->run(menu.getCurrentIndex(), context);
}
context.playSound(Select);
} catch (const Exception::Return & ex){
menuInfo.open();
}
context.playMusic();
updateInfo = true;
break;
case Cancel:
context.playSound(Cancel);
if (menu.isInTab()){
menu.toggleTabSelect();
} else {
throw Exception::Return(__FILE__, __LINE__);
}
break;
default:
break;
}
if (updateInfo){
if (tabs.size() > menu.getCurrentTab() &&
tabs[menu.getCurrentTab()]->options.size() > menu.getCurrentIndex()){
addInfo(tabs[menu.getCurrentTab()]->options[menu.getCurrentIndex()]->getInfoText(), menu, context, font);
}
}
}
Menu::Context::Context():
cleanup(true),
state(NotStarted),
fades(0),
font(NULL),
infoLocation(0, -.5),
menuInfoLocation(0,.95){
}
Menu::Context::Context(const Context & parent, const Context & child):
cleanup(false),
state(NotStarted),
fades(NULL),
font(NULL),
infoLocation(0,-.5),
menuInfoLocation(0,.95),
/* include child's languages?? */
languages(parent.getLanguages()){
// Update with parents info
fades = parent.fades;
background = parent.background;
sounds = parent.sounds;
music = parent.music;
// font = parent.font;
infoLocation = parent.infoLocation;
menuInfoLocation = parent.menuInfoLocation;
// Then overwrite with childs
if (child.fades != NULL){
fades = child.fades;
}
if (!child.background.empty()){
background = child.background;
}
if (!child.sounds.empty()){
sounds = child.sounds;
}
if (Storage::instance().exists(child.music)){
music = child.music;
}
if (child.hasFont()){
font = child.getFontInfo();
} else if (parent.hasFont()){
font = parent.getFontInfo();
}
/* what are these magic numbers -.5 and .95? */
if (child.infoLocation.getRelativeX() != 0 || child.infoLocation.getRelativeY() != -.5){
infoLocation = child.infoLocation;
}
if (child.menuInfoLocation.getRelativeX() != 0 || child.menuInfoLocation.getRelativeY() != .95){
menuInfoLocation = child.menuInfoLocation;
}
if (!child.menuInfo.empty()){
menuInfo = child.menuInfo;
}
}
Menu::Context::~Context(){
// Only delete if required
if (cleanup){
if (fades != NULL){
delete fades;
}
}
}
std::vector<std::string> Menu::Context::getLanguages() const {
return languages;
}
void Menu::Context::setLanguages(const std::vector<std::string> & languages){
this->languages = languages;
}
bool Menu::Context::hasFont() const {
return font != NULL;
}
void Menu::Context::parseToken(const Token * token){
if ( *token != "context" ){
throw LoadException(__FILE__, __LINE__, "Not a menu context");
} else if (!token->hasTokens()){
return;
}
// Token
const Token * tok;
token->view() >> tok;
TokenView view = tok->view();
while (view.hasMore()){
const Token * context;
view >> context;
if (*context == "fade"){
// Fade info
if (!fades){
fades = new Gui::FadeTool();
}
// Set fader default to white
fades->setFadeInColor(Graphics::makeColor(255,255,255));
fades->setFadeOutColor(Graphics::makeColor(255,255,255));
fades->setFadeInTime(25);
fades->setFadeOutTime(12);
// Load defaults
fades->parseDefaults(context);
} else if (*context == "animation" || *context == "background"){
// Backgrounds
addBackground(context);
} else if (*context == ""){
}
}
}
void Menu::Context::addBackground(const Token * token){
// Backgrounds
/*if (background == NULL){
background = new Gui::AnimationManager();
}*/
background.add(Util::ReferenceCount<Gui::Animation>(new Gui::Animation(token)));
}
void Menu::Context::addBackground(const Util::ReferenceCount<Gui::Animation> & animation){
background.add(animation);
}
void Menu::Context::addBackground(const Graphics::Bitmap & image){
/*if (background == NULL){
background = new Gui::AnimationManager();
}*/
background.add(Util::ReferenceCount<Gui::Animation>(new Gui::Animation(Util::ReferenceCount<Graphics::Bitmap>(new Graphics::Bitmap(image)))));
}
void Menu::Context::addBackground(const std::string & image){
// Backgrounds
/*if (background == NULL){
background = new Gui::AnimationManager();
}*/
background.add(Util::ReferenceCount<Gui::Animation>(new Gui::Animation(image)));
}
void Menu::Context::initialize(){
if (fades){
// state
state = Initializing;
// set fader state
fades->setState(FadeTool::FadeIn);
} else {
// Running
state = Running;
}
}
void Menu::Context::finish(){
if (fades){
// state
state = Finishing;
// set fader state
fades->setState(FadeTool::FadeOut);
} else {
// Completed
state = Completed;
}
}
void Menu::Context::playSound(const Actions & sound) const {
map<Actions, Filesystem::RelativePath>::const_iterator find = sounds.find(sound);
if (find != sounds.end() && Storage::instance().exists(find->second)){
tryPlaySound(find->second);
}
}
void Menu::Context::addSound(const Actions & sound, const Filesystem::RelativePath & path){
sounds[sound] = path;
}
void Menu::Context::playMusic(){
if (Storage::instance().exists(music)){
if (Music::loadSong(Storage::instance().find(music).path())){
Music::pause();
Music::play();
}
}
}
void Menu::Context::act(){
// fader
if (fades){
fades->act();
if (state == Initializing){
if(fades->getState() == Gui::FadeTool::NoFade){
state = Running;
}
} else if (state == Finishing){
if(fades->getState() == Gui::FadeTool::EndFade){
state = Completed;
}
}
}
// Backgrounds
background.act();
}
void Menu::Context::renderBackground(const Graphics::Bitmap & bmp) const {
if (!background.empty()){
// background
background.render(Gui::Animation::BackgroundBottom, bmp);
background.render(Gui::Animation::BackgroundMiddle, bmp);
background.render(Gui::Animation::BackgroundTop, bmp);
} else {
bmp.fill(Graphics::makeColor(0,0,0));
}
}
void Menu::Context::renderForeground(const Graphics::Bitmap & bmp) const {
if (!background.empty()){
// foreground
background.render(Gui::Animation::ForegroundBottom, bmp);
background.render(Gui::Animation::ForegroundMiddle, bmp);
background.render(Gui::Animation::ForegroundTop, bmp);
}
}
void Menu::Context::render(const Util::ReferenceCount<Renderer> & renderer, const Graphics::Bitmap & bmp) const {
renderBackground(bmp);
// Menu
if (renderer != NULL){
renderer->render(bmp, currentFont());
}
renderForeground(bmp);
// Fades
if (fades){
fades->draw(bmp);
}
}
void Menu::Context::setFadeTool(Gui::FadeTool *fade){
fades = fade;
}
/*
void Menu::Context::setBackground(Background *bg){
background = bg;
}
*/
/* New Menu */
// Utilizes default renderer
Menu::Menu::Menu(const Renderer::Type & type):
type(type){
setRenderer(type);
}
Menu::Menu::Menu(const Util::ReferenceCount<Renderer> & renderer):
renderer(renderer),
type(renderer->getType()){
}
Menu::Menu::Menu(const Filesystem::AbsolutePath & filename, const Renderer::Type & type):
type(type){
// Load up tokenizer
try{
Global::debug(1,"menu") << "Loading menu " << filename.path() << endl;
TokenReader tr;
Token * token = tr.readTokenFromFile(*Storage::instance().open(filename));
OptionFactory defaultFactory;
load(token, defaultFactory);
} catch (const TokenException & e){
throw LoadException(__FILE__, __LINE__, e, "Error loading menu");
}
}
Menu::Menu::Menu(const Filesystem::AbsolutePath & filename, const OptionFactory & factory, const Renderer::Type & type):
renderer(0),
type(type){
// Load up tokenizer
try{
Global::debug(1,"menu") << "Loading menu " << filename.path() << endl;
TokenReader tr;
Token * token = tr.readTokenFromFile(*Storage::instance().open(filename));
load(token, factory);
} catch (const TokenException & e){
throw LoadException(__FILE__, __LINE__, e, "Error loading menu");
}
}
Menu::Menu::Menu(const Token * token, const Renderer::Type & type):
renderer(0),
type(type){
OptionFactory defaultFactory;
load(token, defaultFactory);
}
Menu::Menu::Menu(const Token * token, const OptionFactory & factory, const Renderer::Type & type):
renderer(0),
type(type){
load(token, factory);
}
Menu::Menu::~Menu(){
// Kill values
for (std::map<string,ValueHolder *>::iterator i = data.begin(); i != data.end(); ++i){
if (i->second){
delete i->second;
}
}
}
void Menu::Menu::setPosition(const Gui::Coordinate & coordinate){
if (renderer != NULL){
renderer->setPosition(coordinate);
}
}
void Menu::Menu::setFont(const Util::ReferenceCount<FontInfo> & font){
context.setFont(font);
/*
if (renderer){
renderer->setFont(font);
}
*/
}
void Menu::Menu::load(const Token * token, const OptionFactory & factory){
// version info;
int major=0, minor=0, micro=0;
if (!token->hasTokens()){
throw LoadException(__FILE__, __LINE__, "Empty Menu");
} else {
const Token *ourToken = token->findToken("_/type");
if (ourToken != NULL){
try {
std::string menuType;
ourToken->view() >> menuType;
if (menuType == "default"){
type = Renderer::Default;
} else if (menuType == "tabbed"){
type = Renderer::Tabbed;
}
} catch (const TokenException & ex){
}
}
ourToken = token->findToken("_/version");
if (ourToken != NULL){
try {
ourToken->view() >> major >> minor >> micro;
} catch (const TokenException & ex){
}
} else {
Global::debug(0, "menu") << "No version indicated, assuming 3.3.1 or below." << endl;
major = 3;
minor = 3;
micro = 1;
}
}
setRenderer(type);
if (Version::getVersion(major, minor, micro) != Version::getVersion()){
// Do compatible translations if necessary
handleCompatibility(token, Version::getVersion(major, minor, micro), factory);
} else {
handleCurrentVersion(token);
}
}
typedef Menu::Menu MenuClass;
class LanguageMenu: public Menu::Menu {
public:
class LanguageOption: public MenuOption {
public:
LanguageOption(const Gui::ContextBox & box, const string & language):
MenuOption(box, NULL){
setText(language);
setInfoText(language);
}
virtual void logic(){
}
virtual void run(const ::Menu::Context & context){
Configuration::setLanguage(getText());
Configuration::saveConfiguration();
throw ::Menu::MenuException(__FILE__, __LINE__);
}
};
static vector<string> findLanguages(const MenuClass & original){
return original.getLanguages();
}
static vector<string> putEnglishFirst(vector<string> languages){
vector<string> out;
bool haveEnglish = false;
for (vector<string>::iterator it = languages.begin(); it != languages.end(); it++){
const string & name = *it;
if (name == "English"){
out.insert(out.begin(), name);
haveEnglish = true;
} else {
out.push_back(name);
}
}
/* We should always have at least english available */
if (!haveEnglish){
out.insert(out.begin(), "English");
}
return out;
}
LanguageMenu(const MenuClass & original){
Util::ReferenceCount< ::Menu::DefaultRenderer > renderer = getRenderer();
vector<string> languages = putEnglishFirst(findLanguages(original));
for (vector<string>::iterator it = languages.begin(); it != languages.end(); it++){
addOption(new LanguageOption(renderer->getBox(), *it));
}
}
};
void Menu::Menu::setupDefaultLanguage(const Context & context, const MenuClass & parent){
LanguageMenu menu(parent);
menu.setFont(Util::ReferenceCount<FontInfo>(new RelativeFontInfo(Font::getDefaultFontPath(), 24, 24)));
Configuration::setLanguage("English");
try{
menu.run(context);
} catch (const ::Menu::MenuException & ignore){
}
}
void Menu::Menu::openOptions(){
vector<Util::ReferenceCount<MenuOption> > options = getRenderer()->getOptions();
for (vector<Util::ReferenceCount<MenuOption> >::iterator it = options.begin(); it != options.end(); it++){
Util::ReferenceCount<MenuOption> & option = *it;
option->open();
}
}
void Menu::Menu::closeOptions(){
vector<Util::ReferenceCount<MenuOption> > options = getRenderer()->getOptions();
for (vector<Util::ReferenceCount<MenuOption> >::iterator it = options.begin(); it != options.end(); it++){
Util::ReferenceCount<MenuOption> & option = *it;
option->close();
}
}
vector<string> Menu::Menu::getLanguages() const {
return languages;
}
void Menu::Menu::run(const Context & parentContext){
/* TODO: replace with Parameter */
Keyboard::pushRepeatState(true);
try{
// Setup context from parent and this menu and initialize
Context localContext(parentContext, context);
Util::Parameter<Util::ReferenceCount<FontInfo> > currentFont(menuFontParameter);
if (context.hasFont()){
currentFont.push(context.getFontInfo());
}
localContext.initialize();
/* Not sure if this is the right place to set the languages.
* For now the semantics is that if a sub-menu specifies a set
* of languages then we will use those, otherwise the
* languages will come from the parentContext.
*
* getLanguages() is supposed to hold at least one language
* which might be English, the default.
*
* This logic is sort of lame.. fix it.
*/
if (getLanguages().size() > 1 || (getLanguages().size() == 1 && getLanguages()[0] != "English")){
localContext.setLanguages(getLanguages());
}
// Setup menu fonts etc
if (renderer != NULL){
renderer->initialize(localContext);
// Invoke Override if available
renderer->invokeOverride(localContext);
}
//Play music
localContext.playMusic();
if (Configuration::getLanguage() == ""){
setupDefaultLanguage(localContext, *this);
}
/* do any lazy loading options want to do */
openOptions();
/* vi keys -- make these optional? */
input.set(Keyboard::Key_J, 0, true, Down);
input.set(Keyboard::Key_K, 0, true, Up);
input.set(Keyboard::Key_H, 0, true, Left);
input.set(Keyboard::Key_L, 0, true, Right);
/* regular keys */
input.set(Configuration::getUp(0), 0, true, Up);
input.set(Configuration::getDown(0), 0, true, Down);
input.set(Configuration::getLeft(0), 0, true, Left);
input.set(Configuration::getRight(0), 0, true, Right);
input.set(Configuration::getAttack1(0), 0, true, Select);
/* FIXME: use configuration keys */
input.set(Keyboard::Key_ENTER, 0, true, Select);
input.set(Keyboard::Key_ESC, 0, true, Cancel);
/* joystick */
input.set(Joystick::Up, 0, true, Up);
input.set(Joystick::Down, 0, true, Down);
input.set(Joystick::Left, 0, true, Left);
input.set(Joystick::Right, 0, true, Right);
/*! FIXME this should be changed to Select/Cancel buttons, all other buttons should be Select */
input.set(Joystick::Button1, 0, true, Select);
input.set(Joystick::Button2, 0, true, Select);
input.set(Joystick::Button3, 0, true, Select);
input.set(Joystick::Button4, 0, true, Select);
input.set(Joystick::Start, 0, true, Select);
input.set(Joystick::Quit, 0, true, Cancel);
class Logic: public Util::Logic {
public:
Logic(Menu & menu, Context & localContext, const Util::ReferenceCount<Renderer> & renderer):
menu(menu),
localContext(localContext),
renderer(renderer){
}
Menu & menu;
Context & localContext;
Util::ReferenceCount<Renderer> renderer;
void run(){
try {
menu.act(localContext);
} catch (const Exception::Return & ex){
// signaled to quit current menu, closing this one out
localContext.finish();
if (renderer != NULL){
renderer->finish();
}
}
}
double ticks(double system){
return system * Global::ticksPerSecond(90);
}
bool done(){
return localContext.getState() == Context::Completed ||
!(renderer != NULL && renderer->active());
}
};
class Draw: public Util::Draw {
public:
Draw(Menu & menu, Context & localContext):
menu(menu),
localContext(localContext){
}
Menu & menu;
Context & localContext;
void draw(const Graphics::Bitmap & buffer){
Graphics::StretchedBitmap work(640, 480, buffer, Graphics::StretchedBitmap::NoClear, Graphics::qualityFilterName(Configuration::getQualityFilter()));
Util::Parameter<Util::ReferenceCount<FontInfo> > currentFont(menuFontParameter);
if (Configuration::hasMenuFont()){
currentFont.push(Configuration::getMenuFont());
}
work.start();
menu.render(localContext, work);
work.finish();
// buffer.BlitToScreen();
}
};
Logic logic(*this, localContext, renderer);
Draw draw(*this, localContext);
Util::standardLoop(logic, draw);
closeOptions();
// FIXME Menu is finished, lets return. Is this even required anymore?
throw Exception::Return(__FILE__, __LINE__);
} catch (...){
Keyboard::popRepeatState();
throw;
}
}
void Menu::Menu::act(Context & ourContext){
InputSource source(true);
// Keys
vector<InputMap<Actions>::InputEvent> events = InputManager::getEvents(input, source);
for (vector<InputMap<Actions>::InputEvent>::iterator it = events.begin(); it != events.end(); it++){
InputMap<Actions>::InputEvent event = *it;
if (!event.enabled){
continue;
}
if (event.out == Cancel){
if (renderer != NULL){
InputManager::waitForRelease(input, source, Cancel);
renderer->doAction(Cancel, ourContext);
} else {
ourContext.playSound(Cancel);
InputManager::waitForRelease(input, source, Cancel);
throw Exception::Return(__FILE__, __LINE__);
}
}
if (renderer != NULL){
switch (event.out){
case Up: renderer->doAction(Up, ourContext); break;
case Down: renderer->doAction(Down, ourContext); break;
case Left: renderer->doAction(Left, ourContext); break;
case Right: renderer->doAction(Right, ourContext); break;
case Select: renderer->doAction(Select, ourContext); break;
default: break;
}
}
}
if (renderer != NULL){
Util::Parameter<Util::ReferenceCount<FontInfo> > currentFont(menuFontParameter);
if (Configuration::hasMenuFont()){
currentFont.push(Configuration::getMenuFont());
}
renderer->act(ourContext);
}
// Act context
ourContext.act();
}
void Menu::Menu::render(const Context & ourContext, const Graphics::Bitmap & bmp) const {
// Render context
ourContext.render(renderer, bmp);
}
std::string Menu::Menu::getName(){
std::string name;
try {
if (data["name"]){
*data["name"] >> name;
}
} catch (const MenuException & ex){
}
return name;
}
std::string Menu::Menu::getInfo(){
std::string name;
try {
if (data["info"]){
*data["info"] >> name;
}
} catch (const MenuException & ex){
}
return name;
}
void Menu::Menu::addData(ValueHolder * item){
std::pair<std::map<std::string,ValueHolder *>::iterator,bool> check;
check = data.insert( std::pair<std::string,ValueHolder *>(item->getName(),item) );
if (check.second == false){
Global::debug(0,"menu") << "Value \"" << check.first->second->getName() << "\" already exists - (" << check.first->second->getValues() << ")." << endl;
Global::debug(0,"menu") << "Replacing with value \"" << item->getName() << "\" - (" << item->getValues() << ")." << endl;
data[item->getName()] = item;
}
}
void Menu::Menu::handleCurrentVersion(const Token * token){
TokenView view = token->view();
while (view.hasMore()){
try{
const Token * tok;
view >> tok;
// Newer items
if (*tok == "val" || *tok == "value"){
const Token * val;
tok->view() >> val;
ValueHolder * value = new ValueHolder(val->getName());
TokenView valueView = val->view();
try {
while (true){
*value << valueView;
}
} catch (const TokenException & ex){
}
addData(value);
} else if (*tok == "context"){
context.parseToken(tok);
} else {
Global::debug(3,"menu") <<"Unhandled menu attribute: "<<endl;
if (Global::getDebug() >= 3){
tok->print(" ");
}
}
} catch ( const TokenException & ex ) {
throw LoadException(__FILE__, __LINE__, ex, "Menu parse error");
} catch (const LoadException & ex){
throw ex;
} catch (const Filesystem::NotFound & ex){
throw LoadException(__FILE__, __LINE__, ex, "Menu parse error");
}
}
}
void Menu::Menu::handleCompatibility(const Token * token, int version, const OptionFactory & factory){
Global::debug(1,"menu") << "Trying version: " << version << endl;
if (version <= Version::getVersion(3, 3, 1)){
const Token * languages = token->findToken("_/languages");
if (languages != NULL){
try{
TokenView view = languages->view();
while (true){
string language;
view >> language;
this->languages.push_back(language);
}
} catch (const TokenException & fail){
}
}
if (this->languages.size() == 0){
this->languages.push_back("English");
}
TokenView view = token->view();
while (view.hasMore()){
try {
const Token * tok;
view >> tok;
if ( *tok == "name" ){
ValueHolder * value = new ValueHolder("name");
TokenView nameView = tok->view();
*value << nameView;
addData(value);
} else if ( *tok == "music" ) {
ValueHolder * value = new ValueHolder("music");
TokenView musicView = tok->view();
*value << musicView;
addData(value);
try {
std::string music;
*value >> music;
context.setMusic(Filesystem::RelativePath(music));
} catch (const MenuException & ex){
}
} else if( *tok == "select-sound" ) {
ValueHolder * value = new ValueHolder("select-sound");
TokenView soundView = tok->view();
*value << soundView;
addData(value);
try{
std::string sound;
*value >> sound;
context.addSound(Up, Filesystem::RelativePath(sound));
context.addSound(Down, Filesystem::RelativePath(sound));
} catch (const MenuException & ex){
}
} else if (*tok == "back-sound"){
ValueHolder * value = new ValueHolder("back-sound");
TokenView soundView = tok->view();
*value << soundView;
addData(value);
try{
std::string sound;
*value >> sound;
context.addSound(Back,Filesystem::RelativePath(sound));
context.addSound(Cancel,Filesystem::RelativePath(sound));
} catch (const MenuException & ex){
}
} else if (*tok == "ok-sound"){
ValueHolder * value = new ValueHolder("ok-sound");
TokenView okView = tok->view();
*value << okView;
addData(value);
try{
std::string sound;
*value >> sound;
context.addSound(Select,Filesystem::RelativePath(sound));
} catch (const MenuException & ex){
}
} else if ( *tok == "background" ) {
std::string temp;
tok->view() >> temp;
context.addBackground(temp);
} else if (*tok == "anim"){
context.addBackground(tok);
} else if ( *tok == "clear-color" ) {
// Not necessary ignore
} else if (renderer != NULL && renderer->readToken(tok, factory)){
// Nothing checks compatible version of renderer
} else if ( *tok == "font" ) {
ValueHolder * value = new ValueHolder("font");
TokenView fontView = tok->view();
*value << fontView << fontView << fontView;
addData(value);
try {
std::string font;
int w = 24, h = 24;
*value >> font >> w >> h;
/*context.setFont(Filesystem::RelativePath(font));
context.setFontWidth(w);
context.setFontHeight(h);*/
context.setFont(Util::ReferenceCount<FontInfo>(new RelativeFontInfo(Filesystem::RelativePath(font), w, h)));
} catch (const MenuException & ex){
}
} else if ( *tok == "action"){
// Set speed
//ActionAct(tok);
} else if ( *tok == "info-position"){
ValueHolder * value = new ValueHolder("info-position");
TokenView infoView = tok->view();
*value << infoView << infoView;
addData(value);
try {
double x=0, y=-.5;
*value >> x >> y;
context.setInfoLocation(x,y);
} catch (const MenuException & ex){
}
} else if (*tok == "menuinfo"){
ValueHolder * value = new ValueHolder("menuinfo");
TokenView infoView = tok->view();
*value << infoView;
addData(value);
try {
std::string info;
*value >> info;
context.setMenuInfoText(info);
} catch (const MenuException & ex){
}
} else if (*tok == "menuinfo-position"){
ValueHolder * value = new ValueHolder("menuinfo-position");
TokenView infoView = tok->view();
*value << infoView << infoView;
addData(value);
try {
double x=0, y=.95;
*value >> x >> y;
context.setMenuInfoLocation(x,y);
} catch (const MenuException & ex){
}
} else {
Global::debug(3,"menu") <<"Unhandled menu attribute: "<<endl;
if (Global::getDebug() >= 3){
tok->print(" ");
}
}
} catch ( const TokenException & ex ) {
throw LoadException(__FILE__, __LINE__, ex, "Menu parse error");
} catch (const LoadException & ex){
throw ex;
} catch (const Filesystem::NotFound & ex){
throw LoadException(__FILE__, __LINE__, ex, "Menu parse error");
}
}
}
}
void Menu::Menu::setRenderer(const Renderer::Type & type){
renderer = rendererType(type);
}
void Menu::Menu::setRenderer(const Util::ReferenceCount<Renderer> & renderer){
this->renderer = renderer;
}
void Menu::Menu::addOption(MenuOption * opt){
if (renderer != NULL){
this->renderer->addOption(opt);
}
}
Util::ReferenceCount<Menu::Renderer> Menu::Menu::rendererType(const Renderer::Type & type){
switch (type){
case Renderer::Tabbed: {
return Util::ReferenceCount<Renderer>(new TabRenderer());
break;
}
case Renderer::Default:
default: {
return Util::ReferenceCount<Renderer>(new DefaultRenderer());
break;
}
}
return Util::ReferenceCount<Renderer>(NULL);
}
diff --git a/src/menu/menu_action.cpp b/src/menu/menu_action.cpp
index 5a4b2769..b9baf5e0 100644
--- a/src/menu/menu_action.cpp
+++ b/src/menu/menu_action.cpp
@@ -1,12 +1,12 @@
-#include "menu_action.h"
+#include "r-tech1/menu/menu_action.h"
MenuAction::MenuAction()
{
}
MenuAction::~MenuAction()
{
- // Nothing
+ // Nothing
}
diff --git a/src/menu/menu_option.cpp b/src/menu/menu_option.cpp
index fedc47dd..d2351c65 100644
--- a/src/menu/menu_option.cpp
+++ b/src/menu/menu_option.cpp
@@ -1,140 +1,140 @@
-#include "util/graphics/bitmap.h"
-#include "util/token.h"
-#include "util/funcs.h"
-#include "util/language-string.h"
-#include "util/debug.h"
-#include "util/exceptions/load_exception.h"
-#include "util/gui/animation.h"
-#include "menu_option.h"
+#include "r-tech1/graphics/bitmap.h"
+#include "r-tech1/token.h"
+#include "r-tech1/funcs.h"
+#include "r-tech1/language-string.h"
+#include "r-tech1/debug.h"
+#include "r-tech1/exceptions/load_exception.h"
+#include "r-tech1/gui/animation.h"
+#include "r-tech1/menu/menu_option.h"
using namespace std;
MenuOption::MenuOption(const Gui::ContextBox & parent, const Token *token):
Gui::ContextItem("", parent),
currentState(Deselected),
text(""),
infoText(""),
runnable(true){
if (token){
const Token & tok = *token;
TokenView view = tok.view();
while (view.hasMore()){
- try{
- const Token * token;
- view >> token;
- if ( *token == "info" ){
+ try{
+ const Token * token;
+ view >> token;
+ if ( *token == "info" ){
readInfo(token);
/*
- // get info text add to option
- std::string temp;
- *token >> temp;
- setInfoText(temp);
+ // get info text add to option
+ std::string temp;
+ *token >> temp;
+ setInfoText(temp);
*/
- } else if( *token == "option-anim" ) {
- } else {
- Global::debug( 3 ) << "Unhandled menu attribute: "<<endl;
- if (Global::getDebug() >= 3){
- token->print(" ");
- }
- }
- } catch ( const TokenException & ex ) {
- throw LoadException(__FILE__, __LINE__, ex, "Menu option parse error");
- } catch ( const LoadException & ex ) {
- throw ex;
- }
+ } else if( *token == "option-anim" ) {
+ } else {
+ Global::debug( 3 ) << "Unhandled menu attribute: "<<endl;
+ if (Global::getDebug() >= 3){
+ token->print(" ");
+ }
+ }
+ } catch ( const TokenException & ex ) {
+ throw LoadException(__FILE__, __LINE__, ex, "Menu option parse error");
+ } catch ( const LoadException & ex ) {
+ throw ex;
+ }
}
}
}
/* tries to read the name for the option. Either use
* - legacy way: (name "foobar") which sets the name to "foobar
* in english
* - new way: (name (language "english" "foobar") ...) which adds
* "foobar" as a name in "english". further uses of `language'
* add new languages for the name.
*
* Using both style is actually allowed but a (language "english" "foo")
* will override the legacy definition.
*
* Expects the parent token to be passed in:
* (whatever (name ...))
*/
void MenuOption::addName(const Token * token){
readName(token, "name");
}
void MenuOption::readName(const Token * token, const std::string & matchType){
try{
LanguageString name;
string temp;
if (token->match(matchType, temp)){
name.add(temp);
}
string language, words;
Token::Matcher matcher = token->getMatcher(matchType + "/language");
while (matcher.match(language, words)){
name.add(words, language);
}
this->setText(name);
if (getText().empty()){
throw LoadException(__FILE__, __LINE__, "No name set, this option should have a name!");
}
} catch (const TokenException & ex){
throw LoadException(__FILE__, __LINE__, ex, "Menu option parse error");
}
}
/* same deal as readName, except this excepts just the info token:
* (info ...)
*/
void MenuOption::addInfo(const Token * token){
readInfo(token);
}
void MenuOption::readInfo(const Token * token){
try{
LanguageString name;
string temp;
if (token->match("info", temp)){
name.add(temp);
}
string language, words;
Token::Matcher matcher = token->getMatcher("info/language");
while (matcher.match(language, words)){
name.add(words, language);
}
this->setInfoText(name);
} catch (const TokenException & ex){
throw LoadException(__FILE__, __LINE__, ex, "Menu option parse error");
}
}
MenuOption::~MenuOption(){
}
/* subclasses can lazily load stuff by overriding this method */
void MenuOption::open(){
}
/* do any dynamic cleanup here */
void MenuOption::close(){
}
// This is to pass paramaters to an option ie a bar or something
bool MenuOption::leftKey(){
return false;
}
bool MenuOption::rightKey(){
return false;
}
const std::string MenuOption::getName() const {
return getText();
}
diff --git a/src/menu/optionfactory.cpp b/src/menu/optionfactory.cpp
index 11c1c850..687e9992 100644
--- a/src/menu/optionfactory.cpp
+++ b/src/menu/optionfactory.cpp
@@ -1,81 +1,81 @@
-#include "util/token.h"
-#include "optionfactory.h"
-#include "util/gui/context-box.h"
-#include "menu_option.h"
-#include "options.h"
-#include "util/debug.h"
+#include "r-tech1/token.h"
+#include "r-tech1/menu/optionfactory.h"
+#include "r-tech1/gui/context-box.h"
+#include "r-tech1/menu/menu_option.h"
+#include "r-tech1/menu/options.h"
+#include "r-tech1/debug.h"
using namespace std;
namespace Menu{
OptionFactory::OptionFactory(){
}
OptionFactory::~OptionFactory(){
}
MenuOption * OptionFactory::getOption(const Gui::ContextBox & parent, const Token *token) const {
const Token * tok;
token->view() >> tok;
if (*tok == "menu"){
// Create a sub menu
const Token * typeToken = tok->findToken("_/type");
if (typeToken != NULL){
std::string type;
typeToken->view() >> type;
if (type == "tabbed"){
return new OptionTabMenu(parent, tok, *this);
}
}
return new OptionMenu(parent, tok, *this);
} else if (*tok == "tabmenu" ){
// Create a tab menu
return new OptionTabMenu(parent, tok, *this);
} else if ( *tok == "key" ){
// Reconfigure a given key
return new OptionKey(parent, tok);
} else if ( *tok == "joystick" ){
// Reconfigure a given joystick button
return new OptionJoystick(parent, tok);
} else if (*tok == "choose-language"){
return new OptionLanguage(parent, tok);
} else if (*tok == "return"){
return new OptionReturn(parent, tok);
} else if (*tok == "continue"){
return new OptionContinue(parent, tok);
} else if (*tok == "sound"){
return new OptionSound(parent, tok);
} else if (*tok == "music"){
return new OptionMusic(parent, tok);
} else if (*tok == "screen-size"){
return new OptionScreenSize(parent, tok);
} else if (*tok == "quality-filter"){
return new OptionQualityFilter(parent, tok);
} else if (*tok == "fps"){
return new OptionFps(parent, tok);
} else if ( *tok == "credits" ){
// Credits mode
return new OptionCredits(parent, tok);
} else if ( *tok == "speed" ){
// Speed
return new OptionSpeed(parent, tok);
} else if ( *tok == "fullscreen" ){
// Full screen Selector
return new OptionFullscreen(parent, tok);
} else if ( *tok == "quit" ){
return new OptionQuit(parent, tok);
} else if ( *tok == "font-select" ){
// Font Selector
return new OptionSelectFont(parent, tok);
} else if ( *tok == "dummy" ){
// Dummy Option
return new OptionDummy(parent, tok);
} else {
Global::debug(0) <<"Unhandled menu attribute: "<<endl;
tok->print(" ");
}
return NULL;
}
}
diff --git a/src/message-queue.cpp b/src/message-queue.cpp
index fe67f46a..297758f5 100644
--- a/src/message-queue.cpp
+++ b/src/message-queue.cpp
@@ -1,84 +1,84 @@
#include <queue>
#include <string>
#include <vector>
-#include "message-queue.h"
-#include "thread.h"
+#include "r-tech1/message-queue.h"
+#include "r-tech1/thread.h"
using std::vector;
using std::string;
Util::Thread::Lock MessageQueue::messageLock;
MessageQueue::MessageQueue(){
Util::Thread::initializeLock(&lock);
}
void MessageQueue::add(const std::string & str){
Util::Thread::acquireLock(&lock);
messages.push(str);
Util::Thread::releaseLock(&lock);
}
bool MessageQueue::hasAny(){
bool any = false;
Util::Thread::acquireLock(&lock);
any = messages.size() > 0;
Util::Thread::releaseLock(&lock);
return any;
}
std::string MessageQueue::get(){
std::string str;
Util::Thread::acquireLock(&lock);
if (messages.size() > 0){
str = messages.front();
messages.pop();
}
Util::Thread::releaseLock(&lock);
return str;
}
MessageQueue::~MessageQueue(){
}
static vector<string> messageBuffer;
/* should support infinite queues eventually */
static MessageQueue * current = NULL;
void MessageQueue::registerInfo(MessageQueue * queue){
Util::Thread::acquireLock(&messageLock);
current = queue;
if (current != NULL){
/* push all saved messages immediately to the queue */
for (vector<string>::iterator it = messageBuffer.begin(); it != messageBuffer.end(); it++){
current->add(*it);
}
messageBuffer.clear();
}
Util::Thread::releaseLock(&messageLock);
}
/* clear any buffered messages */
void MessageQueue::clearInfo(){
Util::Thread::acquireLock(&messageLock);
messageBuffer.clear();
Util::Thread::releaseLock(&messageLock);
}
void MessageQueue::unregisterInfo(MessageQueue * queue){
Util::Thread::acquireLock(&messageLock);
if (current == queue){
current = NULL;
}
Util::Thread::releaseLock(&messageLock);
}
void MessageQueue::info(const std::string & str){
Util::Thread::acquireLock(&messageLock);
if (current != NULL){
current->add(str);
} else {
/* save it for later until a message-queue is registered */
messageBuffer.push_back(str);
}
Util::Thread::releaseLock(&messageLock);
}
diff --git a/src/messages.cpp b/src/messages.cpp
index 1e2a4c47..81fc4a80 100644
--- a/src/messages.cpp
+++ b/src/messages.cpp
@@ -1,107 +1,107 @@
-#include "graphics/bitmap.h"
-#include "messages.h"
-#include "util/font.h"
+#include "r-tech1/graphics/bitmap.h"
+#include "r-tech1/messages.h"
+#include "r-tech1/font.h"
using namespace std;
-
+
Messages::Messages( int width, int height, int opaque ):
width(width),
height(height),
opaque(opaque),
borderColor(Graphics::makeColor(200,200,200)){
}
static vector< string > wrapStrings( const string & left, const string & right, const Font & font, int max, vector< string > accum ){
if (left == ""){
return accum;
}
int length = font.textLength(left.c_str());
if (length >= max){
return wrapStrings(left.substr( 0, left.length() / 2 ), left.substr( left.length() / 2 ) + right, font, max, accum);
} else if (length >= max - font.textLength("E") || right == ""){
accum.push_back(left);
return wrapStrings(right, "", font, max, accum);
} else {
string newleft = left + right.substr(0, 1);
/* edge case where adding one character goes over the limit. in that
* case treat it as the 2nd case.
*/
if (font.textLength(newleft.c_str()) >= max - font.textLength("E")){
accum.push_back(left);
return wrapStrings(right, "", font, max, accum);
}
return wrapStrings(newleft, right.substr(1), font, max, accum);
}
}
/*
static int wrapPrint( const Bitmap & area, int y, int top, const Font & font, const string & left, const string & right ){
- if ( left == "" ){
- return top;
- }
+ if ( left == "" ){
+ return top;
+ }
- int length = font.textLength( left.c_str() );
- int max = area.getWidth();
+ int length = font.textLength( left.c_str() );
+ int max = area.getWidth();
- if ( length >= max ){
- return wrapPrint( area, y - font.getHeight(), top - font.getHeight(), font, left.substr( 0, left.length() / 2 ), left.substr( left.length() / 2 ) + right );
- } else if ( length >= max - font.textLength( "E" ) || right == "" ){
- font.printf( 0, y, Bitmap::makeColor( 255, 255, 255 ), area, left, 0 );
- return wrapPrint( area, y + font.getHeight(), top, font, right, "" );
- } else {
- return wrapPrint( area, y, top, font, left + right.substr( 0, 1 ), right.substr( 1 ) );
- }
+ if ( length >= max ){
+ return wrapPrint( area, y - font.getHeight(), top - font.getHeight(), font, left.substr( 0, left.length() / 2 ), left.substr( left.length() / 2 ) + right );
+ } else if ( length >= max - font.textLength( "E" ) || right == "" ){
+ font.printf( 0, y, Bitmap::makeColor( 255, 255, 255 ), area, left, 0 );
+ return wrapPrint( area, y + font.getHeight(), top, font, right, "" );
+ } else {
+ return wrapPrint( area, y, top, font, left + right.substr( 0, 1 ), right.substr( 1 ) );
+ }
}
*/
void Messages::addMessage( const std::string & s ){
- messages.push_back( s );
+ messages.push_back( s );
}
-
+
void Messages::draw( int x, int y, const Graphics::Bitmap & work, const Font & font ){
// work.drawingMode( Bitmap::MODE_TRANS );
Graphics::Bitmap::transBlender(0, 0, 0, this->opaque);
work.translucent().rectangleFill( x, y, x + width, y + height, Graphics::makeColor( 0, 0, 0 ) );
// work.drawingMode( Bitmap::MODE_SOLID );
// work.rectangle( x, y, x + width-1, y + height-1, Bitmap::makeColor( 255, 255, 255 ) );
work.border(0, 1, borderColor);
/* fast because its a sub-bitmap */
Graphics::Bitmap area(work, x, y, width, height);
int current_y = height - font.getHeight() - 1;
// int max_length = area.getWidth() / font.textLength( "E" );
for ( vector< string >::reverse_iterator it = messages.rbegin(); it != messages.rend(); it++ ){
if ( current_y < 0 - font.getHeight() ){
break;
}
const string & s = *it;
vector< string > all;
all = wrapStrings(s, "", font, area.getWidth() - 3, all);
current_y -= font.getHeight() * (all.size() - 1);
int my = current_y;
for ( vector< string >::iterator str = all.begin(); str != all.end(); str++ ){
font.printf(2, my, Graphics::makeColor( 255, 255, 255 ), area, *str, 0);
my += font.getHeight();
}
// current_y = wrapPrint( area, current_y, current_y, font, s, "" );
/*
int lines = font.textLength( s.c_str() ) / area.getWidth();
current_y -= font.getHeight() * lines;
int my = current_y;
while ( s != "" ){
string sub = s.substr( 0, max_length );
s.erase( 0, max_length );
font.printf( 0, my, Bitmap::makeColor( 255, 255, 255 ), area, sub, 0 );
my += font.getHeight();
}
*/
current_y -= font.getHeight();
}
}
-
+
Messages::~Messages(){
}
diff --git a/src/network/chat.cpp b/src/network/chat.cpp
index f68fa455..8817ff22 100644
--- a/src/network/chat.cpp
+++ b/src/network/chat.cpp
@@ -1,314 +1,314 @@
-#include "chat.h"
+#include "r-tech1/network/chat.h"
#include <stdexcept>
using namespace Network;
using namespace Chat;
Message::Message():
type(Unknown){
}
Message::Message(const Message::Type & type):
type(type){
}
Message::Message(Socket socket):
type(Unknown){
read(socket);
}
Message::Message(const Message::Type & type, const std::string & sender, const std::string & message):
type(type),
sender(sender),
message(message){
}
Message::Message(const Message & copy):
type(copy.type),
sender(copy.sender),
message(copy.message),
parameters(copy.parameters){
}
Message::~Message(){
}
const Message & Message::operator=(const Message & copy){
type = copy.type;
sender = copy.sender;
message = copy.message;
parameters = copy.parameters;
return *this;
}
static std::string convertType(const Message::Type & type){
std::string converted;
switch (type){
case Message::Ping:
converted = "ping";
break;
case Message::Chat:
converted = "chat";
break;
case Message::Command:
converted = "command";
break;
case Message::Unknown:
default:
converted = "unknown";
break;
}
return converted;
}
static Message::Type convertType(const std::string & type){
Message::Type converted = Message::Unknown;
if (type == "ping"){
converted = Message::Ping;
} else if (type == "chat"){
converted = Message::Chat;
} else if (type == "command"){
converted = Message::Command;
} else if (type == "unknown"){
converted = Message::Unknown;
}
return converted;
}
void Message::read(Socket socket){
int16_t size = ::Network::read16(socket);
char * buffer = new char[size];
::Network::readBytes(socket, (uint8_t*) buffer, size);
char * position = buffer;
uint16_t nextSize = 0;
std::string typeString;
position = ::Network::parse16(position, &nextSize);
position = ::Network::parseString(position, &typeString, nextSize + 1);
type = convertType(typeString);
nextSize = 0;
position = ::Network::parse16(position, &nextSize);
position = ::Network::parseString(position, &sender, nextSize + 1);
nextSize = 0;
position = ::Network::parse16(position, &nextSize);
position = ::Network::parseString(position, &message, nextSize + 1);
uint16_t vectorSize = 0;
position = ::Network::parse16(position, &vectorSize);
for (int i = 0; i < vectorSize; ++i){
std::string next;
nextSize = 0;
position = ::Network::parse16(position, &nextSize);
position = ::Network::parseString(position, &next, nextSize + 1);
parameters.push_back(next);
}
delete[] buffer;
}
void Message::send(Socket socket){
// Type
std::string stringType = convertType(type);
int size = sizeof(uint16_t) + stringType.size()+1 +
sizeof(uint16_t) + sender.size()+1 +
sizeof(uint16_t) + message.size()+1 +
sizeof(uint16_t) + parameters.size();
for (std::vector<std::string>::iterator i = parameters.begin(); i != parameters.end(); ++i){
size+=sizeof(uint16_t) + (*i).size()+1;
}
size+=sizeof(uint16_t);
char * buffer = new char[size + sizeof(uint16_t)];
char * position = buffer;
position = ::Network::dump16(position, size);
position = ::Network::dump16(position, stringType.size());
position = ::Network::dumpStr(position, stringType);
position = ::Network::dump16(position, sender.size());
position = ::Network::dumpStr(position, sender);
position = ::Network::dump16(position, message.size());
position = ::Network::dumpStr(position, message);
position = ::Network::dump16(position, parameters.size());
for (std::vector<std::string>::iterator i = parameters.begin(); i != parameters.end(); ++i){
position = ::Network::dump16(position, (*i).size());
position = ::Network::dumpStr(position, (*i));
}
::Network::sendBytes(socket, (uint8_t*) buffer, size + sizeof(uint16_t));
delete[] buffer;
}
const Message::Type & Message::getType() const{
return type;
}
const std::string & Message::getName() const{
return sender;
}
const std::string & Message::getMessage() const{
return message;
}
void Message::setParameters(const std::vector<std::string> & parameters){
this->parameters = parameters;
}
const std::vector<std::string> & Message::getParameters() const{
return parameters;
}
Threadable::Threadable(){
}
Threadable::~Threadable(){
}
static void * run_thread(void * t){
Threadable * thread = (Threadable *)t;
thread->run();
return NULL;
}
void Threadable::start(){
::Util::Thread::createThread(&thread, NULL, (::Util::Thread::ThreadFunction) run_thread, this);
}
void Threadable::join(){
::Util::Thread::joinThread(thread);
}
Client::Client(int id, Network::Socket socket):
id(id),
socket(socket),
end(false),
valid(true){
}
Client::~Client(){
}
void Client::run(){
while (!end){
try {
::Util::Thread::ScopedLock scope(lock);
Message message(socket);
messages.push(message);
} catch (const Network::MessageEnd & ex){
end = true;
}
}
valid = false;
}
int Client::getId() const {
return id;
}
void Client::sendMessage(Message & message){
::Util::Thread::ScopedLock scope(lock);
try{
message.send(socket);
} catch (const ::Network::NetworkException & ex){
valid = false;
}
}
bool Client::hasMessages() const{
::Util::Thread::ScopedLock scope(lock);
return !messages.empty();
}
Message Client::nextMessage() {
::Util::Thread::ScopedLock scope(lock);
Message message = messages.front();
messages.pop();
return message;
}
void Client::shutdown(){
::Util::Thread::ScopedLock scope(lock);
end = true;
Network::close(socket);
join();
}
bool Client::isValid() const {
::Util::Thread::ScopedLock scope(lock);
return valid;
}
Server::Server(int port):
end(false){
remote = Network::openReliable(port);
Network::listen(remote);
Global::debug(0) << "Waiting for a connection on port " << port << std::endl;
}
Server::~Server(){
}
void Server::run(){
int idList = 0;
while (!end){
Util::ReferenceCount<Client> client = Util::ReferenceCount<Client>(new Client(idList++, Network::accept(remote)));
client->start();
clients.push_back(client);
Global::debug(0) << "Got a connection" << std::endl;
}
}
void Server::poll(){
for (std::vector< Util::ReferenceCount<Client> >::iterator i = clients.begin(); i != clients.end(); ++i){
Util::ReferenceCount<Client> client = *i;
while (client->hasMessages()){
Message message = client->nextMessage();
relay(client->getId(), message);
messages.push(message);
}
}
}
void Server::cleanup(){
for (std::vector< Util::ReferenceCount<Client> >::iterator i = clients.begin(); i != clients.end(); ++i){
Util::ReferenceCount<Client> client = *i;
Message ping(Message::Ping);
client->sendMessage(ping);
if (!client->isValid()){
client->shutdown();
i = clients.erase(i);
}
}
}
bool Server::hasMessages() const{
return !messages.empty();
}
Message Server::nextMessage() {
Message message = messages.front();
messages.pop();
return message;
}
void Server::global(Message & message){
for (std::vector< Util::ReferenceCount<Client> >::iterator i = clients.begin(); i != clients.end(); ++i){
Util::ReferenceCount<Client> client = *i;
client->sendMessage(message);
}
}
void Server::relay(int id, Message & message){
for (std::vector< Util::ReferenceCount<Client> >::iterator i = clients.begin(); i != clients.end(); ++i){
Util::ReferenceCount<Client> client = *i;
if (client->getId() != id){
client->sendMessage(message);
}
}
}
void Server::shutdown(){
::Util::Thread::ScopedLock scope(lock);
end = true;
for (std::vector< Util::ReferenceCount<Client> >::iterator i = clients.begin(); i != clients.end(); ++i){
Util::ReferenceCount<Client> client = *i;
client->shutdown();
}
Network::close(remote);
join();
}
diff --git a/src/network/irc-client.cpp b/src/network/irc-client.cpp
index adc5dbe1..a4e02eb8 100644
--- a/src/network/irc-client.cpp
+++ b/src/network/irc-client.cpp
@@ -1,30 +1,30 @@
-#include "irc-client.h"
+#include "r-tech1/network/irc-client.h"
#include <iostream>
#include <vector>
#include <stdexcept>
-#include "util/graphics/bitmap.h"
-#include "util/font.h"
-#include "util/debug.h"
-#include "util/exceptions/load_exception.h"
-#include "util/token_exception.h"
-#include "util/input/input.h"
-#include "util/input/input-manager.h"
-#include "util/sound/sound.h"
-#include "util/exceptions/exception.h"
-#include "util/network/network.h"
-#include "util/network/chat.h"
-#include "util/network/irc.h"
-#include "util/thread.h"
-#include "util/pointer.h"
-#include "util/system.h"
+#include "r-tech1/graphics/bitmap.h"
+#include "r-tech1/font.h"
+#include "r-tech1/debug.h"
+#include "r-tech1/exceptions/load_exception.h"
+#include "r-tech1/token_exception.h"
+#include "r-tech1/input/input.h"
+#include "r-tech1/input/input-manager.h"
+#include "r-tech1/sound/sound.h"
+#include "r-tech1/exceptions/exception.h"
+#include "r-tech1/network/network.h"
+#include "r-tech1/network/chat.h"
+#include "r-tech1/network/irc.h"
+#include "r-tech1/thread.h"
+#include "r-tech1/pointer.h"
+#include "r-tech1/system.h"
#include "mugen/util.h"
#include "mugen/search.h"
#include "mugen/exception.h"
#include "mugen/options.h"
#include "mugen/widgets.h"
-#include <queue>
\ No newline at end of file
+#include <queue>
diff --git a/src/network/irc.cpp b/src/network/irc.cpp
index a6959a6e..2956740b 100644
--- a/src/network/irc.cpp
+++ b/src/network/irc.cpp
@@ -1,1338 +1,1338 @@
-#include "irc.h"
+#include "r-tech1/network/irc.h"
-#include "util/funcs.h"
-#include "util/font.h"
-#include "util/regex.h"
-#include "util/system.h"
-#include "util/graphics/bitmap.h"
-#include "util/configuration.h"
-#include "util/gui/context-box.h"
+#include "r-tech1/funcs.h"
+#include "r-tech1/font.h"
+#include "r-tech1/regex.h"
+#include "r-tech1/system.h"
+#include "r-tech1/graphics/bitmap.h"
+#include "r-tech1/configuration.h"
+#include "r-tech1/gui/context-box.h"
-#include "util/timedifference.h"
+#include "r-tech1/timedifference.h"
#include <stdexcept>
#include <queue>
namespace Network{
namespace IRC{
static Command::Type convertCommand(const std::string & cmd){
Command::Type command = Command::Unknown;
if (cmd == "PASS"){
command = Command::Pass;
} else if (cmd == "NICK"){
command = Command::Nick;
} else if (cmd == "USER"){
command = Command::User;
} else if (cmd == "USERHOST"){
command = Command::Userhost;
} else if (cmd == "SERVER"){
command = Command::Server;
} else if (cmd == "OPER"){
command = Command::Oper;
} else if (cmd == "QUIT"){
command = Command::Quit;
} else if (cmd == "SQUIT"){
command = Command::Squit;
} else if (cmd == "JOIN"){
command = Command::Join;
} else if (cmd == "PART"){
command = Command::Part;
} else if (cmd == "MODE"){
command = Command::Mode;
} else if (cmd == "TOPIC"){
command = Command::Topic;
} else if (cmd == "NAMES"){
command = Command::Names;
} else if (cmd == "LIST"){
command = Command::List;
} else if (cmd == "INVITE"){
command = Command::Invite;
} else if (cmd == "KICK"){
command = Command::Kick;
} else if (cmd == "VERSION"){
command = Command::Version;
} else if (cmd == "STATS"){
command = Command::Stats;
} else if (cmd == "LINKS"){
command = Command::Links;
} else if (cmd == "TIME"){
command = Command::Time;
} else if (cmd == "CONNECT"){
command = Command::Connect;
} else if (cmd == "TRACE"){
command = Command::Trace;
} else if (cmd == "ADMIN"){
command = Command::Admin;
} else if (cmd == "INFO"){
command = Command::Info;
} else if (cmd == "PRIVMSG"){
command = Command::PrivateMessage;
} else if (cmd == "NOTICE"){
command = Command::Notice;
} else if (cmd == "WHO"){
command = Command::Who;
} else if (cmd == "WHOIS"){
command = Command::Whois;
} else if (cmd == "WHOWAS"){
command = Command::Whowas;
} else if (cmd == "KILL"){
command = Command::Kill;
} else if (cmd == "PING"){
command = Command::Ping;
} else if (cmd == "PONG"){
command = Command::Pong;
} else if (cmd == "ERROR"){
command = Command::Error;
} else if (cmd == "433"){
command = Command::ErrorNickInUse;
} else if (cmd == "401"){
command = Command::ErrorNoSuchNick;
} else if (cmd == "403"){
command = Command::ErrorNoSuchChannel;
} else if (cmd == "461"){
command = Command::ErrorNeedMoreParams;
} else if (cmd == "473"){
command = Command::ErrorInviteOnlyChannel;
} else if (cmd == "474"){
command = Command::ErrorBannedFromChannel;
} else if (cmd == "475"){
command = Command::ErrorBadChannelKey;
} else if (cmd == "471"){
command = Command::ErrorChannelIsFull;
} else if (cmd == "302"){
command = Command::ReplyUserhost;
} else if (cmd == "331"){
command = Command::ReplyNoTopic;
} else if (cmd == "332"){
command = Command::ReplyTopic;
} else if (cmd == "333"){
command = Command::ReplyTopicAuthor;
} else if (cmd == "353"){
command = Command::ReplyNames;
} else if (cmd == "366"){
command = Command::ReplyNamesEndOf;
} else if (cmd == "372"){
command = Command::ReplyMOTD;
} else if (cmd == "375"){
command = Command::ReplyMOTDStart;
} else if (cmd == "376"){
command = Command::ReplyMOTDEndOf;
}
return command;
}
static std::string convertCommand(const Command::Type & cmd){
switch (cmd){
case Command::Pass: return "PASS";
case Command::Nick: return "NICK";
case Command::User: return "USER";
case Command::Userhost: return "USERHOST";
case Command::Server: return "SERVER";
case Command::Oper: return "OPER";
case Command::Quit: return "QUIT";
case Command::Squit: return "SQUIT";
case Command::Join: return "JOIN";
case Command::Part: return "PART";
case Command::Mode: return "MODE";
case Command::Topic: return "TOPIC";
case Command::Names: return "NAMES";
case Command::List: return "LIST";
case Command::Invite: return "INVITE";
case Command::Kick: return "KICK";
case Command::Version: return "VERSION";
case Command::Stats: return "STATS";
case Command::Links: return "LINKS";
case Command::Time: return "TIME";
case Command::Connect: return "CONNECT";
case Command::Trace: return "TRACE";
case Command::Admin: return "ADMIN";
case Command::Info: return "INFO";
case Command::PrivateMessage: return "PRIVMSG";
case Command::Notice: return "NOTICE";
case Command::Who: return "WHO";
case Command::Whois: return "WHOIS";
case Command::Whowas: return "WHOAS";
case Command::Kill: return "KILL";
case Command::Ping: return "PING";
case Command::Pong: return "PONG";
case Command::Error: return "ERROR";
case Command::Unknown:
default:
break;
}
return "";
}
static std::vector<std::string> split(std::string str, char splitter){
std::vector<std::string> strings;
size_t next = str.find(splitter);
while (next != std::string::npos){
strings.push_back(str.substr(0, next));
str = str.substr(next+1);
next = str.find(splitter);
}
if (str != ""){
strings.push_back(str);
}
return strings;
}
Command::Command(const std::string & message){
std::vector< std::string > messageSplit = split(message, ' ');
std::vector< std::string >::iterator current = messageSplit.begin();
if (Util::matchRegex(*current, Util::Regex("^:.*"))){
// Found owner (":") indicates the user, otherwise it's going to be the command
// Grab just the username, ignore everything else
try{
owner = split(*current, '!').at(0).substr(1);
} catch (const std::out_of_range & ex){
}
current++;
}
// Next is the actual command
type = convertCommand(*current);
if (type == Unknown){
Global::debug(0) << "Got unhandled response: " << message << std::endl;
}
current++;
// Parameters
bool foundCtcp = false;
bool concactenate = false;
std::string concactenated;
for (std::vector< std::string >::iterator i = current; i != messageSplit.end(); ++i){
const std::string & parameter = *i;
// If there is a colon in the parameter the rest of split string is the whole parameter rejoin
if (Util::matchRegex(parameter, Util::Regex("^:\001.*")) && !foundCtcp){
foundCtcp = true;
// Drop the ':\001'
ctcp.push_back(parameter.substr(2));
continue;
} else if (Util::matchRegex(parameter, Util::Regex(".*\001")) && foundCtcp){
foundCtcp = false;
// Drop the '\001'
ctcp.push_back(parameter.substr(0, parameter.size()-1));
continue;
} else if (Util::matchRegex(parameter, Util::Regex("^:.*")) && !concactenate){
concactenate = true;
// Drop the ':'
concactenated += parameter.substr(1) + " ";
continue;
} else if (Util::matchRegex(parameter, Util::Regex("=")) ||
Util::matchRegex(parameter, Util::Regex("@"))){
// Ignore
continue;
}
if (concactenate){
concactenated += parameter + " ";
} else {
if (!foundCtcp){
parameters.push_back(parameter);
} else {
ctcp.push_back(parameter);
}
}
}
if (concactenate){
parameters.push_back(concactenated);
}
}
Command::Command(const std::string & owner, const Type & type):
owner(owner),
type(type){
}
Command::Command(const Command & copy):
owner(copy.owner),
type(copy.type),
parameters(copy.parameters),
ctcp(copy.ctcp){
}
Command::~Command(){
}
const Command & Command::operator=(const Command & copy){
owner = copy.owner;
type = copy.type;
parameters = copy.parameters;
ctcp = copy.ctcp;
return *this;
}
std::string Command::getSendable() const {
std::string sendable;
// Name
if (!owner.empty()){
sendable += ":" + owner + " ";
}
// Command
sendable += convertCommand(type) + " ";
// Params
for (unsigned int i = 0; i < parameters.size(); ++i){
sendable += parameters[i] + (i < parameters.size()-1 ? " " : "");
}
// End
sendable += "\r\n";
return sendable;
}
std::string Command::getCTCPSendable() const {
std::string sendable;
// Name
if (!owner.empty()){
sendable += ":" + owner + " ";
}
// Command
sendable += convertCommand(type) + " ";
// Params
for (unsigned int i = 0; i < ctcp.size(); ++i){
sendable += ctcp[i] + (i < ctcp.size()-1 ? " " : "");
}
// End
sendable += "\r\n";
return sendable;
}
Channel::Channel(){
}
Channel::Channel(const std::string & name):
name(name){
}
Channel::Channel(const Channel & copy):
name(copy.name),
topic(copy.topic),
topicAuthor(copy.topicAuthor),
topicDate(copy.topicDate),
users(copy.users){
}
Channel::~Channel(){
}
const Channel & Channel::operator=(const Channel & copy){
name = copy.name;
topic = copy.topic;
topicAuthor = copy.topicAuthor;
topicDate = copy.topicDate;
users = copy.users;
return *this;
}
void Channel::addUser(const std::string & user){
// Can't add same user twice
for (std::vector<std::string>::iterator i = users.begin(); i != users.end(); ++i){
const std::string & name = *i;
if (name == user){
return;
}
}
users.push_back(user);
}
void Channel::removeUser(const std::string & user){
for (std::vector<std::string>::iterator i = users.begin(); i != users.end(); ++i){
const std::string & name = *i;
if (name == user){
users.erase(i);
break;
}
}
}
void Channel::replaceUser(const std::string & user, const std::string & newName){
for (std::vector<std::string>::iterator i = users.begin(); i != users.end(); ++i){
const std::string & name = *i;
if (name == user){
users.insert(users.erase(i), newName);
break;
}
}
}
void Channel::addUsers(const std::vector<std::string> & list){
for (std::vector<std::string>::const_iterator i = list.begin(); i != list.end(); ++i){
const std::string & name = *i;
addUser(name);
}
}
Client::Client(const std::string & hostname, int port):
previousUsername("AUTH"),
username("AUTH"),
previousActiveChannel(0),
currentChannel(0),
hostname(hostname),
port(port),
end(false),
disableMessages(true){
}
Client::~Client(){
}
void Client::connect(const std::string & name){
if (username.empty()){
throw NetworkException("Set username first.");
}
Global::debug(0) << "Connecting to " << hostname << " on port " << port << std::endl;
socket = Network::connectReliable(hostname, port);
start();
setName(name);
Command user("AUTH", Command::User);
user.setParameters(username, "*", "0", ":auth");
sendCommand(user);
// ^^^^^^^^ Should get a response from this crap!
Global::debug(0) << "Connected" << std::endl;
}
bool Client::hasCommands() const{
::Util::Thread::ScopedLock scope(lock);
return !commands.empty();
}
Command Client::nextCommand() const {
::Util::Thread::ScopedLock scope(lock);
Command command = commands.front();
commands.pop();
return command;
}
void Client::sendCommand(const Command & command){
const std::string & sendable = command.getSendable();
Network::sendBytes(socket, (uint8_t *) sendable.c_str(), sendable.size());
}
void Client::sendCommand(const Command::Type & type){
Command command(username, type);
sendCommand(command);
}
void Client::sendCommand(const Command::Type & type, const std::string & param1){
Command command(username, type);
command.setParameters(param1);
sendCommand(command);
}
void Client::sendCommand(const Command::Type & type, const std::string & param1, const std::string & param2){
Command command(username, type);
command.setParameters(param1, param2);
sendCommand(command);
}
void Client::sendCommand(const Command::Type & type, const std::string & param1, const std::string & param2, const std::string & param3){
Command command(username, type);
command.setParameters(param1, param2, param3);
sendCommand(command);
}
void Client::sendCommand(const Command::Type & type, const std::string & param1, const std::string & param2, const std::string & param3, const std::string & param4){
Command command(username, type);
command.setParameters(param1, param2, param3, param4);
sendCommand(command);
}
void Client::setName(const std::string & name){
previousUsername = username;
// Update channel list
for (std::vector< ChannelPointer >::iterator i = activeChannels.begin(); i != activeChannels.end(); ++i){
ChannelPointer activeChannel = *i;
activeChannel->removeUser(username);
activeChannel->addUser(name);
}
username = name;
sendCommand(Command::Nick, name);
}
void Client::joinChannel(const std::string & chan){
for (std::vector< ChannelPointer >::iterator i = activeChannels.begin(); i != activeChannels.end(); ++i){
ChannelPointer activeChannel = *i;
if (activeChannel->getName() == chan){
// Already belonging to this channel
return;
}
}
previousActiveChannel = currentChannel;
ChannelPointer newChannel = ChannelPointer(new Channel(chan));
activeChannels.push_back(newChannel);
currentChannel = activeChannels.size()-1;
sendCommand(Command::Join, getChannel()->getName());
}
void Client::partChannel(const std::string & channel){
for (std::vector< ChannelPointer >::iterator i = activeChannels.begin(); i != activeChannels.end(); ++i){
ChannelPointer activeChannel = *i;
if (activeChannel->getName() == channel){
// Remove channel
activeChannels.erase(i);
break;
}
}
currentChannel = previousActiveChannel;
sendCommand(Command::Part, channel);
}
std::string Client::channelListAsString(){
std::string list;
for (std::vector<ChannelPointer>::iterator i = activeChannels.begin(); i != activeChannels.end(); ++i){
ChannelPointer activeChannel = *i;
list += activeChannel->getName() + ", ";
}
return list.substr(0, list.size()-2);
}
unsigned int Client::getChannelIndex(const std::string & channel){
for (unsigned int i = 0; i < activeChannels.size(); ++i){
if (activeChannels[i]->getName() == channel){
return i;
}
}
return 0;
}
bool Client::isCurrentChannel(const std::string & channel){
return (activeChannels[currentChannel]->getName() == channel);
}
void Client::setChannel(unsigned int channel){
if (channel >= activeChannels.size()){
return;
}
currentChannel = channel;
}
void Client::nextChannel(){
currentChannel = (currentChannel + 1) % activeChannels.size();
}
void Client::previousChannel(){
if (currentChannel == 0){
currentChannel = activeChannels.size()-1;
} else {
currentChannel--;
}
}
void Client::removeChannel(const std::string & name){
for (std::vector< ChannelPointer >::iterator i = activeChannels.begin(); i != activeChannels.end(); ++i){
ChannelPointer activeChannel = *i;
if (activeChannel->getName() == name){
activeChannels.erase(i);
return;
}
}
}
ChannelPointer Client::findChannel(const std::string & name){
for (std::vector< ChannelPointer >::iterator i = activeChannels.begin(); i != activeChannels.end(); ++i){
ChannelPointer activeChannel = *i;
if (activeChannel->getName() == name){
return activeChannel;
}
}
return ChannelPointer(NULL);
}
void Client::sendMessage(const std::string & msg){
if (!disableMessages){
sendCommand(Command::PrivateMessage, getChannel()->getName(), ":" + msg);
}
}
void Client::sendPong(const Command & ping){
Command pong(username, Command::Pong);
pong.setParameters(ping.getParameters());
sendCommand(pong);
}
std::string Client::readMessage(){
std::string received;
bool foundReturn = false;
while (true){
try {
char nextCharacter = Network::read8(socket);
/* NOTE the latest RFC says that either \r or \n is the end of the message
* http://www.irchelp.org/irchelp/rfc/chapter8.html
*/
if (nextCharacter == '\r'){
// Found return
foundReturn = true;
continue;
} else if ((nextCharacter == '\n') && foundReturn){
// Should be the end of the message assuming \r is before it
break;
}
received += nextCharacter;
} catch (const Network::MessageEnd & ex){
// end of message get out
throw ex;
}
}
return received;
}
void Client::checkResponseAndHandle(const Command & command){
// Checks for username or channel errors
if (command.getType() == Command::ErrorNickInUse){
::Util::Thread::ScopedLock scope(lock);
// Change the username back to what it was
getChannel()->removeUser(username);
username = previousUsername;
getChannel()->addUser(username);
} else if (command.getType() == Command::ErrorBannedFromChannel ||
command.getType() == Command::ErrorInviteOnlyChannel ||
command.getType() == Command::ErrorBadChannelKey ||
command.getType() == Command::ErrorChannelIsFull ||
command.getType() == Command::ErrorNoSuchChannel){
::Util::Thread::ScopedLock scope(lock);
// Revert old channel
removeChannel(getChannel()->getName());
currentChannel = previousActiveChannel;
} else if (command.getType() == Command::ReplyTopic){
::Util::Thread::ScopedLock scope(lock);
// Set topic
getChannel()->setTopic(command.getParameters().at(2));
} else if (command.getType() == Command::ReplyTopicAuthor){
::Util::Thread::ScopedLock scope(lock);
// Set topic and author
const std::vector<std::string> & params = command.getParameters();
getChannel()->setTopicAuthor(split(params.at(1), '!').at(0), atoi(params.at(2).c_str()));
} else if (command.getType() == Command::ReplyNames){
// Add names
const std::vector<std::string> & params = command.getParameters();
const std::vector<std::string> & names = split(params.at(2), ' ');
::Util::Thread::ScopedLock scope(lock);
ChannelPointer update = findChannel(params.at(1));
if (update != NULL){
update->addUsers(names);
}
} else if (command.getType() == Command::Nick){
const std::vector<std::string> & params = command.getParameters();
::Util::Thread::ScopedLock scope(lock);
if (command.getOwner() != username){
// Replace in all valid channels
for (std::vector<ChannelPointer>::iterator i = activeChannels.begin(); i != activeChannels.end(); i++){
ChannelPointer update = *i;
if (update != NULL){
update->replaceUser(command.getOwner(), params.at(0));
}
}
}
} else if (command.getType() == Command::Join){
const std::vector<std::string> & params = command.getParameters();
::Util::Thread::ScopedLock scope(lock);
ChannelPointer update = findChannel(params.at(0));
if (update != NULL){
update->addUser(command.getOwner());
}
} else if (command.getType() == Command::Part){
const std::vector<std::string> & params = command.getParameters();
::Util::Thread::ScopedLock scope(lock);
ChannelPointer update = findChannel(params.at(0));
if (update != NULL){
update->removeUser(command.getOwner());
}
}
}
void Client::run(){
while (!end){
try {
const std::string & message = readMessage();
// Check if the message is empty it might be because of (\n)
if (!message.empty()){
Command command(message);
//Global::debug(0) << "Got message: " << command.getSendable() << std::endl;
::Util::Thread::ScopedLock scope(lock);
checkResponseAndHandle(command);
commands.push(command);
} else {
}
} catch (const Network::MessageEnd & ex){
end = true;
}
}
}
Message::EventInterface::EventInterface(){
}
Message::EventInterface::~EventInterface(){
}
void Message::EventInterface::EventInterface::localNotify(const std::string &){
}
void Message::EventInterface::EventInterface::localCommand(const std::vector<std::string> &){
}
void Message::EventInterface::EventInterface::remoteNotify(const std::string &){
}
void Message::EventInterface::EventInterface::remoteCommand(const Command &){
}
Message::HandlerInterface::HandlerInterface(){
}
Message::HandlerInterface::~HandlerInterface(){
}
Message::QueueInterface::QueueInterface(){
}
Message::QueueInterface::~QueueInterface(){
}
Message::QueueInterface::FontWrapper::FontWrapper(){
}
Message::QueueInterface::FontWrapper::~FontWrapper(){
}
void Message::QueueInterface::processMessages(Message::QueueInterface::FontWrapper & wrapper, int width, int height){
while (!messages.empty()){
const std::string message = messages.front();
messages.pop();
// Check message if it exceeds the length of the box so we can split it
if (wrapper.getWidth(message) > width-15){
unsigned int marker = 0;
unsigned int length = 0;
while ((marker+length) < message.size()){
//Global::debug(0) << "Substring: " << message.substr(marker, length) << " Marker: " << marker << " and Current length: " << length << std::endl;
if (wrapper.getWidth(message.substr(marker, length)) < width-15){
length++;
continue;
} else {
if (message[marker+length] == ' '){
buffer.push_front(message.substr(marker, length));
marker += length+1;
length = 0;
} else {
// Search for previous space
unsigned int cutoff = marker+length;
while ((marker+length) > marker){
if (message[marker+length] == ' '){
break;
}
length--;
}
if ((marker+length) > marker){
buffer.push_front(message.substr(marker, length));
marker += length+1;
length = 0;
} else {
buffer.push_front(message.substr(marker, cutoff));
marker = cutoff+1;
length = 0;
}
}
}
}
// Add last item
if ((marker+length) > marker){
buffer.push_front(message.substr(marker, length));
}
} else {
buffer.push_front(message);
}
// Drop out of sight
if ((buffer.size() * (wrapper.getHeight()+2)) > (unsigned int)height){
buffer.pop_back();
}
}
}
class UserItem : public Gui::ListItem{
public:
UserItem(const std::string & name, const Util::ReferenceCount<Client> client):
name(name),
client(client){
}
virtual ~UserItem(){
}
virtual bool operator==(const ListItem & comparable){
return (name == ((UserItem *)&comparable)->name);
}
virtual bool equals(Util::ReferenceCount<Gui::ListItem> comparable){
return (name == ((Util::ReferenceCount<UserItem>) comparable)->name);
}
bool equals(const std::string & comparable){
return (name == comparable);
}
virtual int compareTo(Util::ReferenceCount<Gui::ListItem> comparable){
return name.compare(((Util::ReferenceCount<UserItem>) comparable)->name);
}
void act(){
}
void draw(const Font & font, const Graphics::Bitmap & work){
if (client->getName() == name){
font.printf(0, 0, Graphics::makeColor(0,255,255), work, name, 0);
} else {
font.printf(0, 0, Graphics::makeColor(255,255,255), work, name, 0);
}
}
private:
const std::string name;
const Util::ReferenceCount<Client> client;
};
class ChannelTab: public Gui::TabItem, Message::QueueInterface{
public:
ChannelTab(const std::string & name):
TabItem(name),
width(0),
height(0),
changed(false){
}
virtual ~ChannelTab(){
}
void act(const Font & font){
class Wrapper: public Message::QueueInterface::FontWrapper{
public:
Wrapper(const Font & font):
font(font){
}
virtual ~Wrapper(){
}
const Font & font;
int getWidth(const std::string & text){
return font.textLength(text.c_str());
}
int getHeight(){
return font.getHeight();
}
};
Wrapper wrapper(font);
processMessages(wrapper, width, height);
}
void draw(const Font& font, const Graphics::Bitmap & work){
if (!isActive()){
return;
}
work.clear();
int mod = height-(font.getHeight()+2);
for (std::deque<std::string>::iterator i = buffer.begin(); i != buffer.end(); ++i){
const std::string & text = *i;
font.printf(0, mod, Graphics::makeColor(255,255,255), work, text, 0);
mod-=(font.getHeight()+2);
}
}
void addMessage(const std::string & message){
if (!isActive() && !changed){
changed = true;
}
messages.push(message);
}
void addMessage(const std::string & name, const std::string & message){
addMessage("<"+name+"> " + message);
}
void inspectBody(const Graphics::Bitmap & body){
width = body.getWidth();
height = body.getHeight();
}
void toggleActive(){
if (!active){
active = true;
changed = false;
} else {
active = false;
}
}
private:
int width;
int height;
bool changed;
};
static Util::ReferenceCount<ChannelTab> convertTab(ChatInterface * chat, std::string name = ""){
if (!name.empty()){
try{
return chat->getTabByName(name);
} catch (const Gui::TabContainer::NoSuchTab & ex){
}
}
return chat->getCurrentTab();
}
void ChatInterface::submit(void * interface){
ChatInterface * chat = (ChatInterface *)interface;
if (!chat->getInputBox().getText().empty()){
const std::string & text = chat->getInputBox().getText();
// check if it's a command
if (Util::matchRegex(text, Util::Regex("^/.*"))){
const std::vector<std::string> & command = Util::splitString(text.substr(1), ' ');
chat->localCommand(command);
} else {
convertTab(chat)->addMessage(chat->getClient()->getName(), text);
chat->getClient()->sendMessage(text);
chat->localNotify(text);
}
chat->getInputBox().clear();
}
}
ChatInterface::ChatInterface(const std::string & host, int port, const std::string & username):
host(host),
widthRatio(.8),
heightRatio(.95),
width(0),
height(0),
checkWidth(Configuration::getScreenWidth()),
checkHeight(Configuration::getScreenHeight()),
serverTab(Util::ReferenceCount<Gui::TabItem>(new ChannelTab(host))){
client = Util::ReferenceCount< Client >(new Client(host, port));
client->connect(username);
// Setup window size and chat list
updateDimensions();
// Add server tab
chatBox.add(serverTab);
}
ChatInterface::~ChatInterface(){
}
void ChatInterface::act(){
updateDimensions();
// Default size of fonts
const int size = height * (1 - (heightRatio + .01));
// Size is important
const Font & font = Font::getDefaultFont(size, size);
processRemoteCommands();
// Check user list
updateUserList();
chatBox.act(font);
inputBox.act(font);
listBox.act(font);
}
void ChatInterface::draw(const Graphics::Bitmap & work){
checkWidth = work.getWidth();
checkHeight = work.getHeight();
if (width == checkWidth && height == checkHeight){
const int size = height * (1 - (heightRatio + .01));
const Font & font = Font::getDefaultFont(size, size);
chatBox.draw(font, work);
inputBox.draw(font, work);
listBox.draw(font, work);
}
}
void ChatInterface::nextChannel(){
chatBox.next();
const std::string & name = chatBox.getCurrent()->getName();
if (name == host){
client->setMessagesDisabled(true);
listBox.clear();
} else {
client->setMessagesDisabled(false);
client->setChannel(client->getChannelIndex(name));
updateUserList();
}
}
void ChatInterface::previousChannel(){
chatBox.previous();
const std::string & name = chatBox.getCurrent()->getName();
if (chatBox.getCurrent()->getName() == host){
client->setMessagesDisabled(true);
listBox.clear();
} else {
client->setMessagesDisabled(false);
client->setChannel(client->getChannelIndex(name));
updateUserList();
}
}
void ChatInterface::gotoChannel(const std::string & channel){
chatBox.gotoTabByName(channel);
const std::string & name = chatBox.getCurrent()->getName();
if (chatBox.getCurrent()->getName() == host){
client->setMessagesDisabled(true);
listBox.clear();
} else {
client->setMessagesDisabled(false);
client->setChannel(client->getChannelIndex(name));
updateUserList();
}
}
Util::ReferenceCount<Client> ChatInterface::getClient(){
return client;
}
Util::ReferenceCount<Gui::TabItem> ChatInterface::getCurrentTab(){
return chatBox.getCurrent();
}
Util::ReferenceCount<Gui::TabItem> ChatInterface::getTabByName(const std::string & name){
return chatBox.getByName(name);
}
void ChatInterface::addMessageToTab(const std::string & message){
convertTab(this)->addMessage(message);
}
void ChatInterface::addMessageToTab(const std::string & name, const std::string & message){
convertTab(this)->addMessage(name, message);
}
void ChatInterface::updateDimensions(){
if (width == checkWidth && height == checkHeight){
return;
}
width = checkWidth;
height = checkHeight;
chatBox.transforms.setRadius(15);
Gui::ColorInfo colors;
colors.body = Graphics::makeColor(255,255,255);
colors.bodyAlpha = 128;
colors.border = Graphics::makeColor(0,0,255);
colors.borderAlpha = 255;
// chat panel widthRatio% heightRatio%
chatBox.location.setPosition(Gui::AbsolutePoint(0, 0));
chatBox.location.setDimensions(width * widthRatio, height * heightRatio);
chatBox.colors = colors;
// edit box widthRatio% remaining (heightRatio + .01)%
const double inputStart = heightRatio + .01;
inputBox.transforms.setRadius(15);
inputBox.location.setPosition(Gui::AbsolutePoint(0, height * inputStart));
inputBox.location.setDimensions(width * widthRatio, height * (1 - inputStart));
inputBox.addHook(Keyboard::Key_ENTER, submit, this);
inputBox.colors = colors;
// Set the location of user list width * widthRatio and height
const int listStart = width * widthRatio + .01;
listBox.transforms.setRadius(15);
listBox.location.setPosition(Gui::AbsolutePoint(listStart, 1));
listBox.location.setDimensions(width - listStart, height-2);
listBox.colors = colors;
}
void ChatInterface::remoteNotify(const std::string & message){
for (std::vector<NotifyCallback>::iterator i = callbacks.begin(); i != callbacks.end(); ++i){
(*i)(message);
}
for (std::vector<Message::EventInterface *>::iterator i = subscribers.begin(); i != subscribers.end(); ++i){
(*i)->localNotify(message);
}
}
void ChatInterface::processRemoteCommands(){
while (client->hasCommands()){
::Network::IRC::Command command = client->nextCommand();
const std::vector<std::string> & params = command.getParameters();
if (params.size() > 0){
//Global::debug(0) << "Got message: " << command.getSendable() << std::endl;
}
try {
if (command.getType() == ::Network::IRC::Command::Ping){
client->sendPong(command);
((Util::ReferenceCount<ChannelTab>) serverTab)->addMessage(command.getOwner(), "*** Ping!");
} else if (command.getType() == ::Network::IRC::Command::PrivateMessage){
// Check channel
const std::string & channel = params.at(0);
if (channel == client->getName()){
// Private message to user (not channel)
convertTab(this, channel)->addMessage("\""+command.getOwner() + "\" whispered: " + params.at(1));
} else {
// Username and message
convertTab(this, channel)->addMessage(command.getOwner(), params.at(1));
}
// notify
remoteNotify(params.at(1));
} else if (command.getType() == ::Network::IRC::Command::Notice){
// Username and message
((Util::ReferenceCount<ChannelTab>) serverTab)->addMessage(command.getOwner(), params.at(1));
// notify
remoteNotify(params.at(1));
} else if (command.getType() == ::Network::IRC::Command::ReplyMOTD ||
command.getType() == ::Network::IRC::Command::ReplyMOTDStart ||
command.getType() == ::Network::IRC::Command::ReplyMOTDEndOf){
((Util::ReferenceCount<ChannelTab>) serverTab)->addMessage("*** MOTD " + params.at(1));
} else if (command.getType() == ::Network::IRC::Command::Nick){
// Check if user is the owner
if (command.getOwner() == client->getName()){
convertTab(this)->addMessage("*** Nick changed to " + params.at(0) + ".");
} else {
convertTab(this)->addMessage("*** " + command.getOwner() + " is now known as " + params.at(0) + ".");
}
changeUserName(command.getOwner(), params.at(0));
} else if (command.getType() == ::Network::IRC::Command::Join){
// Check if user is the owner otherwise display to that channel
if (command.getOwner() == client->getName()){
((Util::ReferenceCount<ChannelTab>) serverTab)->addMessage("*** You have joined the channel " + params.at(0) + ".");
chatBox.add(Util::ReferenceCount<Gui::TabItem>(new ChannelTab(params.at(0))));
gotoChannel(params.at(0));
} else {
convertTab(this, params.at(0))->addMessage("*** " + command.getOwner() + " has joined the channel.");
listBox.add(Util::ReferenceCount<Gui::ListItem>(new UserItem(command.getOwner(), client)));
}
} else if (command.getType() == ::Network::IRC::Command::Part){
// Check if user is the owner otherwise display to that channel
if (command.getOwner() == client->getName()){
((Util::ReferenceCount<ChannelTab>) serverTab)->addMessage("*** You have parted the channel " + params.at(0) + ".");
} else {
convertTab(this, params.at(0))->addMessage("*** " + command.getOwner() + " has parted the channel.");
removeUser(command.getOwner());
}
} else if (command.getType() == ::Network::IRC::Command::ReplyNoTopic){
((Util::ReferenceCount<ChannelTab>) serverTab)->addMessage("*** The channel " + params.at(1) + " has no topic set.");
} else if (command.getType() == ::Network::IRC::Command::ReplyTopic){
((Util::ReferenceCount<ChannelTab>) serverTab)->addMessage("*** The channel topic for " + params.at(1) + " is: \"" + params.at(2) + "\".");
} else if (command.getType() == ::Network::IRC::Command::ReplyNames){
std::vector<std::string> names = split(params.at(2), ' ');
std::map<std::string, std::vector<std::string> >::iterator check = namesRequest.find(params.at(1));
if (check == namesRequest.end()){
namesRequest[params.at(1)] = std::vector<std::string>();
check = namesRequest.find(params.at(1));
}
check->second.insert(check->second.begin(), names.begin(), names.end());
} else if (command.getType() == ::Network::IRC::Command::ReplyNamesEndOf){
std::map<std::string, std::vector<std::string> >::iterator check = namesRequest.find(params.at(1));
if (check != namesRequest.end()){
((Util::ReferenceCount<ChannelTab>) serverTab)->addMessage("*** Current users on " + params.at(1) + " \"" + Util::joinStrings(check->second) + "\".");
namesRequest.erase(check);
}
} else if (command.getType() == ::Network::IRC::Command::ErrorNickInUse){
((Util::ReferenceCount<ChannelTab>) serverTab)->addMessage("[Error] " + params.at(1) + ": Nick already in use.");
} else if (command.getType() == ::Network::IRC::Command::ErrorNoSuchNick){
((Util::ReferenceCount<ChannelTab>) serverTab)->addMessage("[Error] " + params.at(1) + ": No such nick.");
} else if (command.getType() == ::Network::IRC::Command::ErrorNoSuchChannel){
((Util::ReferenceCount<ChannelTab>) serverTab)->addMessage("[Error] " + params.at(1) + ": No such channel.");
} else if (command.getType() == ::Network::IRC::Command::Error){
Global::debug(0) << "Received Error: " << command.getSendable() << "... Aborting." << std::endl;
throw Exception::Return(__FILE__, __LINE__);
}
} catch (const std::out_of_range & ex){
}
// Check if we got any CTCP delimited messages
if (command.hasCtcp()){
const std::vector<std::string> & ctcp = command.getCtcp();
if (ctcp.size() > 0){
//Global::debug(0) << "Got CTCP: " << command.getCTCPSendable() << std::endl;
}
try {
if (ctcp.at(0) == "PING"){
// Lets check if there is an existing query otherwise send off request
if (command.getType() == ::Network::IRC::Command::Notice){
std::map<std::string, uint64_t>::iterator check = pingReply.find(command.getOwner());
if (check != pingReply.end()){
// there is an existing entry lets display our ping
std::ostringstream difference;
difference << (double)((System::currentMilliseconds() - check->second)/1000000);
((Util::ReferenceCount<ChannelTab>) serverTab)->addMessage("[CTCP] Received CTCP-PING reply from " + check->first + ": " + difference.str() + "second(s)" );
pingReply.erase(check);
}
} else if (command.getType() == ::Network::IRC::Command::PrivateMessage){
client->sendCommand(::Network::IRC::Command::Notice, command.getOwner(), ":\001PING " + ctcp.at(1) + "\001");
((Util::ReferenceCount<ChannelTab>) serverTab)->addMessage("[CTCP] Received CTCP-PING request from " + command.getOwner() + ", sending answer.");
}
}
} catch (const std::out_of_range & ex){
}
}
// Pass out the command to listeners
for (std::vector<Message::EventInterface *>::iterator i = subscribers.begin(); i != subscribers.end(); ++i){
(*i)->remoteCommand(command);
}
}
}
void ChatInterface::localNotify(const std::string & message){
for (std::vector<NotifyCallback>::iterator i = callbacks.begin(); i != callbacks.end(); ++i){
(*i)(message);
}
for (std::vector<Message::EventInterface *>::iterator i = subscribers.begin(); i != subscribers.end(); ++i){
(*i)->localNotify(message);
}
}
void ChatInterface::localCommand(const std::vector<std::string> & command){
if (command.at(0) == "help"){
convertTab(this)->addMessage("* commands: help, nick, whisper, ping, join, part, names, topic, previous, next, channels, quit");
} else if (command.at(0) == "nick"){
try {
const std::string & nick = command.at(1);
if (!nick.empty()){
client->setName(nick);
convertTab(this)->addMessage("* nick changed to " + nick);
}
} catch (const std::out_of_range & ex){
convertTab(this)->addMessage("* /nick [name]");
}
} else if (command.at(0) == "whisper"){
try {
const std::string & who = command.at(1);
const std::string & message = Util::joinStrings(command, 2);
if (!who.empty() && !message.empty()){
client->sendCommand(::Network::IRC::Command::PrivateMessage, who, ":" + message);
convertTab(this)->addMessage("-> " + who + " " + message);
}
} catch (const std::out_of_range & ex){
convertTab(this)->addMessage("* /whisper [nick] [message]");
}
} else if (command.at(0) == "ping"){
try {
const std::string & who = command.at(1);
if (!who.empty()){
std::ostringstream timestamp;
uint64_t time = System::currentMilliseconds();
timestamp << time;
client->sendCommand(::Network::IRC::Command::PrivateMessage, who, ":\001PING " + timestamp.str() + "\001");
convertTab(this)->addMessage("[CTCP] Sending CTCP-PING request to " + who);
// Log user
pingReply[who] = time;
}
} catch (const std::out_of_range & ex){
convertTab(this)->addMessage("* /ping [nick]");
}
} else if (command.at(0) == "join"){
try {
const std::string & channel = command.at(1);
if (!channel.empty()){
client->joinChannel(channel);
}
} catch (const std::out_of_range & ex){
convertTab(this)->addMessage("* /join [channel]");
}
} else if (command.at(0) == "part"){
if (client->getChannel() != NULL){
chatBox.removeCurrent();
gotoChannel(host);
client->partChannel(client->getChannel()->getName());
}
} else if (command.at(0) == "names"){
try {
const std::string & channel = command.at(1);
if (!channel.empty()){
client->sendCommand(::Network::IRC::Command::Names, channel);
namesRequest[channel] = std::vector<std::string>();
}
} catch (const std::out_of_range & ex){
convertTab(this)->addMessage("* /names [channel]");
}
} else if (command.at(0) == "topic"){
try {
const std::string & channel = command.at(1);
if (!channel.empty()){
client->sendCommand(::Network::IRC::Command::Topic, channel);
}
} catch (const std::out_of_range & ex){
client->sendCommand(::Network::IRC::Command::Topic, client->getChannel()->getName());
}
} else if (command.at(0) == "previous"){
client->previousChannel();
} else if (command.at(0) == "next"){
client->nextChannel();
} else if (command.at(0) == "channels"){
convertTab(this)->addMessage("* Current Channels: " + client->channelListAsString());
} else if (command.at(0) == "quit"){
const std::string & message = Util::joinStrings(command, 1);
if (!message.empty()){
client->sendCommand(::Network::IRC::Command::Quit, ":" + message);
Global::debug(0) << "Quit (" + message + "). Waiting for server to close connection..." << std::endl;
} else {
client->sendCommand(::Network::IRC::Command::Quit);
Global::debug(0) << "Quit. Waiting for server to close connection..." << std::endl;
}
} else {
//convertTab(this)->addMessage("* Uknown command.");
}
// pass local commands out to listeners
for (std::vector<Message::EventInterface *>::iterator i = subscribers.begin(); i != subscribers.end(); ++i){
(*i)->localCommand(command);
}
}
static bool inList(const std::vector< Util::ReferenceCount<Gui::ListItem> > & list, const std::string & name){
for (std::vector< Util::ReferenceCount<Gui::ListItem> >::const_iterator i = list.begin(); i != list.end(); i++){
Util::ReferenceCount<UserItem> item = *i;
if (item->equals(name)){
return true;
}
}
return false;
}
void ChatInterface::updateUserList(){
const ChannelPointer channel = client->getChannel();
if (channel == NULL){
return;
}
const std::vector<std::string> & users = channel->getUsers();
if (listBox.getList().empty() && chatBox.getCurrent()->getName() != host){
// populate
for (std::vector<std::string>::const_iterator i = users.begin(); i != users.end(); i++){
listBox.add(Util::ReferenceCount<Gui::ListItem>(new UserItem(*i, client)));
}
} else if (chatBox.getCurrent()->getName() != host){
if (listBox.getList().size() != users.size()){
listBox.clear();
for (std::vector<std::string>::const_iterator i = users.begin(); i != users.end(); i++){
listBox.add(Util::ReferenceCount<Gui::ListItem>(new UserItem(*i, client)));
}
}
}
}
void ChatInterface::removeUser(const std::string & name){
const std::vector< Util::ReferenceCount<Gui::ListItem> > & userlist = listBox.getList();
for (std::vector< Util::ReferenceCount<Gui::ListItem> >::const_iterator i = userlist.begin(); i != userlist.end(); i++){
Util::ReferenceCount<UserItem> user = *i;
if (user->equals(name)){
// remove him from list
listBox.remove(*i);
break;
}
}
}
void ChatInterface::changeUserName(const std::string & name, const std::string & newName){
const std::vector< Util::ReferenceCount<Gui::ListItem> > & userlist = listBox.getList();
for (std::vector< Util::ReferenceCount<Gui::ListItem> >::const_iterator i = userlist.begin(); i != userlist.end(); i++){
Util::ReferenceCount<UserItem> user = *i;
if (user->equals(name)){
// remove him from list
listBox.remove(*i);
listBox.add(Util::ReferenceCount<Gui::ListItem>(new UserItem(newName, client)));
break;
}
}
}
}
}
diff --git a/src/network/network.cpp b/src/network/network.cpp
index f069acbd..7c3ba7c0 100644
--- a/src/network/network.cpp
+++ b/src/network/network.cpp
@@ -1,401 +1,401 @@
#ifdef HAVE_NETWORKING
-#include "hawknl/nl.h"
+#include "libs/hawknl/nl.h"
#endif
-#include "network.h"
-#include "util/debug.h"
+#include "r-tech1/network/network.h"
+#include "r-tech1/debug.h"
#include <string>
#include <sstream>
#include <string.h>
-#include "util/system.h"
-#include "util/compress.h"
-#include "util/thread.h"
+#include "r-tech1/system.h"
+#include "r-tech1/compress.h"
+#include "r-tech1/thread.h"
#ifdef HAVE_NETWORKING
#ifdef WII
#include <network.h>
#elif defined(WINDOWS)
#include <winsock.h>
#else
#include <arpa/inet.h>
#endif
#else
#ifndef htonl
#define htonl(x) x
#endif
#ifndef htons
#define htons(x) x
#endif
#ifndef ntohl
#define ntohl(x) x
#endif
#ifndef ntohs
#define ntohs(x) x
#endif
#endif
using namespace std;
/* TODO: Wrap open_sockets with a mutex */
namespace Network{
NetworkException::~NetworkException() throw (){
}
MessageEnd::MessageEnd(){
}
-
+
InvalidPortException::InvalidPortException( int port, const string message ):
NetworkException(""){
- ostringstream num;
- num << port;
- num << ". ";
- num << message;
- this->setMessage( "Invalid port " + num.str() );
+ ostringstream num;
+ num << port;
+ num << ". ";
+ num << message;
+ this->setMessage( "Invalid port " + num.str() );
}
/*
template <typename M>
int messageSize(const M& message);
*/
/*
template <>
int messageSize<Message>(Message const & message){
return message.size();
}
template <>
int messageSize<Message*>(Message* const & message){
return message->size();
}
*/
/*
template <class M>
uint8_t * messageDump(const M& message, uint8_t * buffer);
template <>
uint8_t * messageDump<Message>(const Message & message, uint8_t * buffer){
return message.dump(buffer);
}
template <>
uint8_t * messageDump<Message*>(Message* const & message, uint8_t * buffer){
return message->dump(buffer);
}
*/
#ifdef HAVE_NETWORKING
static string getHawkError(){
- return string(" HawkNL error: '") +
- string(nlGetErrorStr(nlGetError())) +
- string("' HawkNL system error: '") +
- string(nlGetSystemErrorStr(nlGetSystemError()));
+ return string(" HawkNL error: '") +
+ string(nlGetErrorStr(nlGetError())) +
+ string("' HawkNL system error: '") +
+ string(nlGetSystemErrorStr(nlGetSystemError()));
}
template<typename X>
static X readX(Socket socket){
X data;
readBytes(socket, (uint8_t*) &data, sizeof(X));
return data;
}
int8_t read8(Socket socket){
return readX<uint8_t>(socket);
}
int16_t read16(Socket socket){
return ntohs(readX<uint16_t>(socket));
}
int32_t read32(Socket socket){
return ntohl(readX<uint32_t>(socket));
}
void send16(Socket socket, int16_t bytes){
bytes = htons(bytes);
sendBytes(socket, (uint8_t *) &bytes, sizeof(bytes));
}
char * dump16(char * where, int16_t bytes){
bytes = htons(bytes);
*(uint16_t*) where = bytes;
return where + sizeof(uint16_t);
}
char * parse16(char * where, uint16_t * out){
*out = ntohs(*(uint16_t*) where);
return where + sizeof(uint16_t);
}
char * dump32(char * where, uint32_t bytes){
bytes = htonl(bytes);
*(uint32_t*) where = bytes;
return where + sizeof(uint32_t);
}
char * parse32(char * where, uint32_t * out){
*out = ntohl(*(uint32_t*) where);
return where + sizeof(uint32_t);
}
char * parseString(char * where, string * out, uint16_t length){
*out = string(where);
return where + length;
}
char * dumpStr(char * where, const std::string & str){
memcpy(where, str.c_str(), str.size() + 1);
return where + str.size() + 1;
}
string readStr(Socket socket, const uint16_t length){
char buffer[length + 1];
NLint bytes = nlRead(socket, buffer, length);
if (bytes == NL_INVALID){
throw NetworkException(string("Could not read string.") + getHawkError());
}
buffer[length] = 0;
bytes += 1;
return string(buffer);
}
void sendStr(Socket socket, const string & str){
if (nlWrite(socket, str.c_str(), str.length() + 1) != (signed)(str.length() + 1)){
throw NetworkException( string("Could not write string.") + getHawkError() );
}
}
void sendAllBytes(Socket socket, const uint8_t * data, int length){
int sent = nlWrite(socket, data, length);
if (sent != length){
throw NetworkException(string("Could not send bytes.") + getHawkError());
}
}
void sendBytes(Socket socket, const uint8_t * data, int length){
const uint8_t * position = data;
int written = 0;
while ( written < length ){
int bytes = nlWrite(socket, position, length - written);
if (bytes == NL_INVALID){
throw NetworkException(string("Could not send bytes.") + getHawkError());
}
written += bytes;
position += bytes;
}
}
int readUptoBytes(Socket socket, uint8_t * data, int length){
return nlRead(socket, data, length);
}
void readBytes(Socket socket, uint8_t * data, int length){
uint8_t * position = data;
int read = 0;
while (read < length){
int bytes = nlRead(socket, position, length - read);
if (bytes == NL_INVALID){
switch (nlGetError()){
case NL_MESSAGE_END : throw MessageEnd();
default : throw NetworkException(string("Could not read bytes.") + getHawkError());
}
}
read += bytes;
position += bytes;
}
}
Util::Thread::Lock socketsLock;
Socket openReliable(int port){
// NLsocket server = nlOpen( port, NL_RELIABLE_PACKETS );
Global::debug(1, "network") << "Attemping to open reliable port " << port << endl;
Socket server = nlOpen(port, NL_RELIABLE);
/* server will either be NL_INVALID (-1) or some low integer. hawknl
* sockets are mapped internally to real sockets, so don't be surprised
* if you get a socket back like 0.
*/
if (server == NL_INVALID){
throw InvalidPortException(port, nlGetSystemErrorStr(nlGetSystemError()));
}
Global::debug(1, "network") << "Successfully opened a socket: " << server << endl;
Util::Thread::acquireLock(&socketsLock);
open_sockets.push_back(server);
Util::Thread::releaseLock(&socketsLock);
return server;
}
Socket openUnreliable(int port){
// NLsocket server = nlOpen( port, NL_RELIABLE_PACKETS );
Global::debug(1, "network") << "Attemping to open unreliable port " << port << endl;
Socket server = nlOpen(port, NL_UNRELIABLE);
/* server will either be NL_INVALID (-1) or some low integer. hawknl
* sockets are mapped internally to real sockets, so don't be surprised
* if you get a socket back like 0.
*/
if (server == NL_INVALID){
throw InvalidPortException(port, nlGetSystemErrorStr(nlGetSystemError()));
}
Global::debug(1, "network") << "Successfully opened a socket: " << server << endl;
Util::Thread::acquireLock(&socketsLock);
open_sockets.push_back(server);
Util::Thread::releaseLock(&socketsLock);
return server;
}
Socket connectReliable(string server, int port){
NLaddress address;
nlGetAddrFromName(server.c_str(), &address);
nlSetAddrPort(&address, port);
/* The port that this socket has opened will be immediately rebound to some
* other port by sock_connect, but we still need to call openReliable to get
* an NL_RELIABLE socket.
*/
Socket socket = openReliable(0);
if (nlConnect(socket, &address) == NL_FALSE){
close(socket);
throw NetworkException("Could not connect");
}
return socket;
}
Socket connectUnreliable(string server, int port){
NLaddress address;
nlGetAddrFromName(server.c_str(), &address);
nlSetAddrPort(&address, port);
/* The port that this socket has opened will be immediately rebound to some
* other port by sock_connect, but we still need to call openReliable to get
* an NL_RELIABLE socket.
*/
Socket socket = openUnreliable(0);
if (nlConnect(socket, &address) == NL_FALSE){
close(socket);
throw NetworkException("Could not connect");
}
return socket;
}
void close(Socket s){
Util::Thread::acquireLock(&socketsLock);
for (vector< Socket >::iterator it = open_sockets.begin(); it != open_sockets.end(); ){
if ( *it == s ){
Global::debug(1, "network") << "Closing socket " << s << endl;
nlClose(*it);
Global::debug(1, "network") << "Closed" << endl;
it = open_sockets.erase(it);
} else {
it++;
}
}
Util::Thread::releaseLock(&socketsLock);
}
void closeAll(){
Global::debug(1, "network") << "Closing all sockets" << std::endl;
Util::Thread::acquireLock(&socketsLock);
for (vector<Socket>::iterator it = open_sockets.begin(); it != open_sockets.end(); it++ ){
nlClose(*it);
}
open_sockets.clear();
Util::Thread::releaseLock(&socketsLock);
}
void init(){
nlInit();
nlSelectNetwork(NL_IP);
nlEnable(NL_BLOCKING_IO);
Util::Thread::initializeLock(&socketsLock);
// nlDisable( NL_BLOCKING_IO );
}
void reuseSockets(bool what){
if (what){
nlEnable(NL_REUSE_ADDRESS);
} else {
nlDisable(NL_REUSE_ADDRESS);
}
}
bool blocking(Socket s, bool b){
return nlSetSocketOpt(s, NL_BLOCKING_IO, b) == NL_TRUE;
}
void blocking(bool b){
if (b){
nlEnable(NL_BLOCKING_IO);
} else {
nlDisable(NL_BLOCKING_IO);
}
}
bool noDelay(Socket s, bool b){
return nlSetSocketOpt(s, NL_TCP_NO_DELAY, b) == NL_TRUE;
}
void listen( Socket s ) throw( NetworkException ){
- if ( nlListen( s ) == NL_FALSE ){
- throw CannotListenException( string(nlGetSystemErrorStr( nlGetSystemError() )) );
- }
+ if ( nlListen( s ) == NL_FALSE ){
+ throw CannotListenException( string(nlGetSystemErrorStr( nlGetSystemError() )) );
+ }
}
Socket accept( Socket s ) throw( NetworkException ){
Socket connection = nlAcceptConnection(s);
if ( connection == NL_INVALID ){
/*
if ( nlGetError() == NL_NO_PENDING ){
error = NO_CONNECTIONS_PENDING;
} else {
error = NETWORK_ERROR;
}
return s;
*/
if ( nlGetError() == NL_NO_PENDING ){
throw NoConnectionsPendingException();
}
throw NetworkException("Could not accept connection");
}
Util::Thread::acquireLock(&socketsLock);
open_sockets.push_back(connection);
Util::Thread::releaseLock(&socketsLock);
return connection;
}
void shutdown(){
nlShutdown();
}
#else
/* Dummy implementations */
char * dump16(char * where, int16_t length){
return where;
}
int8_t read8(Socket socket){
return 0;
}
int16_t read16(Socket socket){
return 0;
}
char * dumpStr(char * where, const std::string & str){
return where;
}
void readBytes(Socket socket, uint8_t * data, int length){
}
void sendBytes(Socket socket, const uint8_t * data, int length){
}
char * parseString(char * where, std::string * out, uint16_t length){
return where;
}
#endif
}
diff --git a/src/regex.cpp b/src/regex.cpp
index 9a2cba53..4355f646 100644
--- a/src/regex.cpp
+++ b/src/regex.cpp
@@ -1,72 +1,72 @@
#include <string>
#include <map>
#include <string.h>
/* gnu/posix's regex header */
// #include <regex.h>
// #include "trex/trex.h"
-#include "pcre/pcre.h"
+#include "libs/pcre/pcre.h"
/* our regex header */
-#include "regex.h"
+#include "r-tech1/regex.h"
using namespace std;
namespace Util{
static map<string, pcre*> cachedPatterns;
Regex::Regex(const string & data):
data(data){
}
const std::string & Regex::get() const {
return data;
}
/* http://www.gnu.org/s/libc/manual/html_node/Regular-Expressions.html */
bool matchRegex(const string & str, const Regex & pattern){
pcre * regex;
const char * error;
int errorOffset;
int count;
regex = cachedPatterns[pattern.get()];
if (regex == NULL){
regex = pcre_compile(pattern.get().c_str(), 0, &error, &errorOffset, NULL);
if (regex == NULL){
return false;
}
cachedPatterns[pattern.get()] = regex;
}
count = pcre_exec(regex, NULL, str.c_str(), str.size(), 0, 0, NULL, 0);
// pcre_free(regex);
return count >= 0;
}
string captureRegex(const string & str, const Regex & pattern, int capture){
pcre * regex;
const char * error;
int errorOffset;
int count;
const int captureMax = 100;
int captures[captureMax];
regex = cachedPatterns[pattern.get()];
if (regex == NULL){
regex = pcre_compile(pattern.get().c_str(), 0, &error, &errorOffset, NULL);
if (regex == NULL){
return "";
}
cachedPatterns[pattern.get()] = regex;
}
count = pcre_exec(regex, NULL, str.c_str(), str.size(), 0, 0, captures, captureMax);
// pcre_free(regex);
if (count >= 0 && capture < count){
int start = captures[(capture + 1) * 2];
int end = captures[(capture + 1) * 2 + 1];
return str.substr(start, end - start);
}
return "";
}
} // namespace
diff --git a/src/resource.cpp b/src/resource.cpp
index c5e45e5f..48f9360b 100644
--- a/src/resource.cpp
+++ b/src/resource.cpp
@@ -1,68 +1,68 @@
-#include "graphics/bitmap.h"
-#include "resource.h"
+#include "r-tech1/graphics/bitmap.h"
+#include "r-tech1/resource.h"
// #include "factory/collector.h"
-#include "funcs.h"
-#include "sound/sound.h"
-#include "file-system.h"
-#include "thread.h"
+#include "r-tech1/funcs.h"
+#include "r-tech1/sound/sound.h"
+#include "r-tech1/file-system.h"
+#include "r-tech1/thread.h"
#include <string>
#include <vector>
using namespace std;
Resource * Resource::resource = NULL;
Util::ReferenceCount<Sound> Resource::getSound(const Filesystem::RelativePath & path){
return getResource()->_getSound(Storage::instance().find(path));
}
Util::ReferenceCount<Graphics::Bitmap> Resource::getBitmap(const Filesystem::RelativePath & path){
return getResource()->_getBitmap(Storage::instance().find(path));
}
static Util::Thread::Lock resourceLock;
void Resource::initialize(){
Util::Thread::initializeLock(&resourceLock);
}
void Resource::destroy(){
Util::Thread::acquireLock(&resourceLock);
delete resource;
resource = NULL;
Util::Thread::releaseLock(&resourceLock);
}
Resource * Resource::getResource(){
Util::Thread::acquireLock(&resourceLock);
if (resource == NULL){
resource = new Resource();
}
Resource * out = resource;
Util::Thread::releaseLock(&resourceLock);
return out;
}
/* the resource is created in the Collector */
Resource::Resource(){
resource = this;
}
Resource::~Resource(){
}
Util::ReferenceCount<Sound> Resource::_getSound(const Filesystem::AbsolutePath & path){
Util::Thread::ScopedLock locked(lock);
if (sounds[path.path()] == NULL){
sounds[path.path()] = Util::ReferenceCount<Sound>(new Sound(path.path()));
}
return sounds[path.path()];
}
Util::ReferenceCount<Graphics::Bitmap> Resource::_getBitmap(const Filesystem::AbsolutePath & path){
Util::Thread::ScopedLock locked(lock);
if (bitmaps[path.path()] == NULL){
bitmaps[path.path()] = Util::ReferenceCount<Graphics::Bitmap>(new Graphics::Bitmap(path.path()));
}
return bitmaps[path.path()];
}
diff --git a/src/system.cpp b/src/system.cpp
index f8859876..d55d493b 100644
--- a/src/system.cpp
+++ b/src/system.cpp
@@ -1,129 +1,129 @@
#include <string>
-#include "system.h"
+#include "r-tech1/system.h"
#include <stdint.h>
#include <stdio.h>
#include <fstream>
#ifdef USE_SDL
#include <SDL/SDL.h>
#endif
#ifndef WINDOWS
#include <unistd.h>
#include <sys/stat.h>
#include <sys/time.h>
#endif
#ifndef WINDOWS
/* devkitpro doesn't have an implementation of access() yet. if it gets one this function
* can be removed.
*/
#if defined(WII) || defined(PS3)
int access(const char * path, int mode){
struct stat information;
int ok = stat(path, &information);
// printf("stat of '%s' is %d\n", path.c_str(), ok);
if (ok == 0){
if (mode == R_OK){
if (((information.st_mode & S_IRUSR) == S_IRUSR) ||
((information.st_mode & S_IRGRP) == S_IRGRP) ||
((information.st_mode & S_IROTH) == S_IROTH)){
return 0;
} else {
/* handle other modes if they become useful to us */
return -1;
}
} else {
return -1;
}
} else {
// perror("stat");
return -1;
}
}
#endif
static bool isReadable(const std::string & path){
return access(path.c_str(), R_OK) == 0;
}
bool System::isDirectory(const std::string & path){
struct stat info;
if (stat(path.c_str(), &info) == 0){
if (S_ISDIR(info.st_mode) == 1){
return true;
} else {
return false;
}
}
return false;
}
bool System::readableFile(const std::string & path){
return isReadable(path) && ! isDirectory(path);
}
bool System::readable(const std::string & path){
return isReadable(path);
}
void System::makeDirectory(const std::string & path){
mkdir(path.c_str(), 0777);
}
/*
uint64_t System::currentMicroseconds(){
struct timeval hold;
gettimeofday(&hold, NULL);
return hold.tv_sec * 1000 * 1000 + hold.tv_usec;
}
*/
uint64_t System::currentMilliseconds(){
#ifdef USE_SDL
return SDL_GetTicks();
#else
struct timeval hold;
gettimeofday(&hold, NULL);
return (hold.tv_sec * 1000 * 1000 + hold.tv_usec) / 1000;
#endif
}
uint64_t System::getModificationTime(const std::string & path){
struct stat data;
if (stat(path.c_str(), &data) == 0){
return data.st_mtime;
}
return 0;
}
static void * start_memory = 0;
unsigned long System::memoryUsage(){
void * here = sbrk(0);
/* hopefully the heap is growing up */
return (char*) here - (char*) start_memory;
}
void System::startMemoryUsage(){
start_memory = sbrk(0);
}
#endif
void System::makeAllDirectory(const std::string & path){
size_t last = path.find('/');
while (last != std::string::npos){
std::string sofar = path.substr(0, last);
if (sofar != ""){
makeDirectory(sofar);
}
last = path.find('/', last + 1);
}
makeDirectory(path);
}
uint64_t System::currentSeconds(){
return currentMilliseconds() / 1000;
}
diff --git a/src/system/allegro5/init.cpp b/src/system/allegro5/init.cpp
new file mode 100644
index 00000000..20db3987
--- /dev/null
+++ b/src/system/allegro5/init.cpp
@@ -0,0 +1,28 @@
+#ifdef USE_ALLEGRO5
+
+#include <allegro5/allegro.h>
+#include <allegro5/allegro_image.h>
+#include <allegro5/allegro_primitives.h>
+#include "../init.h"
+#include "util/debug.h"
+
+namespace System{
+
+void initSystem(const Global::InitConditions & conditions, Global::stream_type & out){
+ out << "Allegro5 initialize " << (al_init() ? "Ok" : "Failed") << std::endl;
+ uint32_t version = al_get_allegro_version();
+ int major = version >> 24;
+ int minor = (version >> 16) & 255;
+ int revision = (version >> 8) & 255;
+ int release = version & 255;
+ out << "Allegro5 version " << major << "." << minor << "." << revision << "." << release << std::endl;
+ out << "Init image: " << (al_init_image_addon() ? "Ok" : "Failed") << std::endl;
+ out << "Init primitives " << (al_init_primitives_addon() ? "Ok" : "Failed") << std::endl;
+ out << "Init keyboard " << (al_install_keyboard() ? "Ok" : "Failed") << std::endl;
+ out << "Init joystick " << (al_install_joystick() ? "Ok" : "Failed") << std::endl;
+ al_set_app_name("Paintown");
+}
+
+}
+
+#endif
diff --git a/src/system/allegro5/timer.cpp b/src/system/allegro5/timer.cpp
new file mode 100644
index 00000000..bb79ec94
--- /dev/null
+++ b/src/system/allegro5/timer.cpp
@@ -0,0 +1,72 @@
+#include "system/timer.h"
+#include "util/init.h"
+
+#ifdef USE_ALLEGRO5
+#include <allegro5/allegro.h>
+
+using std::vector;
+
+namespace System{
+
+struct TimerInfo{
+ TimerInfo(void (*x)(), ALLEGRO_TIMER * y):
+ tick(x), timer(y){}
+
+ void (*tick)();
+ ALLEGRO_TIMER * timer;
+};
+
+static void * do_timer(void * info){
+ TimerInfo * timerInfo = (TimerInfo*) info;
+
+ ALLEGRO_EVENT_SOURCE * source = al_get_timer_event_source(timerInfo->timer);
+ ALLEGRO_EVENT_QUEUE * queue = al_create_event_queue();
+ al_register_event_source(queue, source);
+ while (run_timer_guard.get()){
+ ALLEGRO_EVENT event;
+ /* Wait a maximum of 50ms in case we need to restart the timers */
+ if (al_wait_for_event_timed(queue, &event, 0.05)){
+ timerInfo->tick();
+ }
+ }
+
+ al_destroy_event_queue(queue);
+ al_destroy_timer(timerInfo->timer);
+
+ delete timerInfo;
+ return NULL;
+}
+
+static Util::Thread::Id start_timer(void (*func)(), int frequency){
+ ALLEGRO_TIMER * timer = al_create_timer(ALLEGRO_BPS_TO_SECS(frequency));
+ if (timer == NULL){
+ Global::debug(0) << "Could not create timer" << std::endl;
+ }
+ al_start_timer(timer);
+ TimerInfo * info = new TimerInfo(func, timer);
+ Util::Thread::Id thread;
+ Util::Thread::createThread(&thread, NULL, (Util::Thread::ThreadFunction) do_timer, (void*) info);
+ return thread;
+}
+
+static void inc_speed_counter(){
+ /* probably put input polling here, InputManager::poll(). no, don't do that.
+ * polling is done in the standardLoop now.
+ */
+ Global::speed_counter4 += 1;
+}
+
+/* if you need to count seconds for some reason.. */
+static void inc_second_counter() {
+ Global::second_counter += 1;
+}
+
+void startTimers(){
+ run_timer_guard.set(true);
+ running_timers.push_back(start_timer(inc_speed_counter, Global::TICS_PER_SECOND));
+ running_timers.push_back(start_timer(inc_second_counter, 1));
+}
+
+}
+
+#endif
diff --git a/src/system/timer.cpp b/src/system/timer.cpp
new file mode 100644
index 00000000..93150acf
--- /dev/null
+++ b/src/system/timer.cpp
@@ -0,0 +1,21 @@
+#include "timer.h"
+
+using std::vector;
+
+namespace System{
+
+volatile bool run_timer;
+Util::Thread::Lock run_timer_lock;
+Util::ThreadBoolean run_timer_guard(run_timer, run_timer_lock);
+std::vector<Util::Thread::Id> running_timers;
+
+void closeTimers(){
+ run_timer_guard.set(false);
+ for (vector<Util::Thread::Id>::iterator it = running_timers.begin(); it != running_timers.end(); it++){
+ Util::Thread::Id timer = *it;
+ Util::Thread::joinThread(timer);
+ }
+ running_timers.clear();
+}
+
+}
diff --git a/src/thread.cpp b/src/thread.cpp
index 28a578ac..8e8d18ac 100644
--- a/src/thread.cpp
+++ b/src/thread.cpp
@@ -1,448 +1,448 @@
-#include "thread.h"
+#include "r-tech1/thread.h"
#ifdef WII
/* So we can call ogc's create thread directly */
#include <ogc/lwp.h>
#endif
namespace Util{
namespace Thread{
LockObject::LockObject(){
initializeLock(&lock);
// initializeCondition(&condition);
// Global::debug(0) << "Created lock " << lock << std::endl;
// Global::debug(0) << "Created condition " << condition << std::endl;
}
int LockObject::acquire() const {
/* quick hack to get around annoying constness */
return acquireLock((Lock*) &lock);
}
int LockObject::release() const {
return releaseLock((Lock*) &lock);
}
#if 0
void LockObject::wait() const {
int ok = 1;
while (ok != 0){
/* if conditionWait succeeds then ok will be 0 */
ok = conditionWait((Condition*) &condition, (Lock*) &lock);
}
}
void LockObject::wait(volatile bool & check) const {
int ok = 0;
/* only wait if check is false. if so then keep waiting until the condition
* was successful as well.
*/
while (!check || ok != 0){
if (ok != 0){
// Global::debug(0) << "Wait failed: " << SDL_GetError() << std::endl;
}
ok = conditionWait((Condition*) &condition, (Lock*) &lock);
}
}
void LockObject::signal() const {
conditionSignal((Condition*) &condition);
}
void LockObject::lockAndSignal(volatile bool & check, bool what) const {
acquire();
check = what;
signal();
release();
}
#endif
LockObject::~LockObject(){
destroyLock(&lock);
// destroyCondition(&condition);
}
ScopedLock::ScopedLock(const LockObject & lock):
lock(lock){
lock.acquire();
}
ScopedLock::~ScopedLock(){
lock.release();
}
bool isUninitialized(Id thread){
return thread == uninitializedValue;
}
ThreadObject::ThreadObject(void * data, void * (function)(void * arg)):
data(data),
function(function),
thread(uninitializedValue){
}
bool ThreadObject::start(){
if (thread == uninitializedValue){
return createThread(&thread, NULL, (Thread::ThreadFunction) function, data);
} else {
return false;
}
}
ThreadObject::~ThreadObject(){
if (thread != uninitializedValue){
joinThread(thread);
thread = uninitializedValue;
}
}
#if defined(USE_SDL) && !defined(USE_NACL)
Id uninitializedValue = NULL;
bool initializeLock(Lock * lock){
*lock = SDL_CreateMutex();
return *lock != NULL;
}
int acquireLock(Lock * lock){
return SDL_LockMutex(*lock);
}
int releaseLock(Lock * lock){
return SDL_UnlockMutex(*lock);
}
void destroyLock(Lock * lock){
SDL_DestroyMutex(*lock);
}
#if 0
void initializeCondition(Condition * condition){
*condition = SDL_CreateCond();
if (condition == NULL){
Global::debug(0) << "Could not create condition" << std::endl;
}
}
void destroyCondition(Condition * condition){
SDL_DestroyCond(*condition);
}
int conditionWait(Condition * condition, Lock * lock){
return SDL_CondWait(*condition, *lock);
}
int conditionSignal(Condition * condition){
return SDL_CondBroadcast(*condition);
}
#endif
/*
void initializeSemaphore(Semaphore * semaphore, unsigned int value){
*semaphore = SDL_CreateSemaphore(value);
}
void destroySemaphore(Semaphore * semaphore){
SDL_DestroySemaphore(*semaphore);
}
void semaphoreDecrease(Semaphore * semaphore){
SDL_SemWait(*semaphore);
}
void semaphoreIncrease(Semaphore * semaphore){
SDL_SemPost(*semaphore);
}
*/
#ifdef WII
struct LwpThread{
lwp_t thread;
char * stack;
};
/* We use libogc's LWP_CreateThread directly because SDL's thread api doesnt let us
* explicitly specify the stack size.
* MUGEN in particular needs a relatively large stack (somewhere around 32kb-64kb)
* to run the parsers. We allocate a little more than that just to be safe (128kb).
* It is easier to use libogc directly than hack SDL each time.
*/
bool wiiCreateThread(Id * thread, void * attributes, ThreadFunction function, void * arg){
LwpThread * lwp = new LwpThread();
int size = 128 * 1024;
lwp->stack = new char[size];
if (LWP_CreateThread(&lwp->thread, (void * (*)(void*)) function, arg, lwp->stack, size, 80) != 0){
delete[] lwp->stack;
delete lwp;
return false;
}
*thread = (Id) lwp;
return true;
}
void wiiJoinThread(Id thread){
LwpThread * lwp = (LwpThread*) thread;
if (LWP_JoinThread(lwp->thread, NULL) == 0){
delete[] lwp->stack;
delete lwp;
} else {
/* Now what?? */
}
}
#endif
bool createThread(Id * thread, void * attributes, ThreadFunction function, void * arg){
#ifdef WII
return wiiCreateThread(thread, attributes, function, arg);
#else
*thread = SDL_CreateThread(function, arg);
return *thread != NULL;
#endif
}
void joinThread(Id thread){
if (!isUninitialized(thread)){
#ifdef WII
wiiJoinThread(thread);
#else
SDL_WaitThread(thread, NULL);
#endif
}
}
void cancelThread(Id thread){
#if !SDL_VERSION_ATLEAST(1, 3, 0)
SDL_KillThread(thread);
#endif
}
#elif USE_ALLEGRO5
Id uninitializedValue = 0;
bool initializeLock(Lock * lock){
*lock = al_create_mutex();
return *lock != NULL;
}
int acquireLock(Lock * lock){
al_lock_mutex(*lock);
return 0;
}
int releaseLock(Lock * lock){
al_unlock_mutex(*lock);
return 0;
}
#if 0
void initializeCondition(Condition * condition){
*condition = al_create_cond();
}
void destroyCondition(Condition * condition){
al_destroy_cond(*condition);
}
int conditionWait(Condition * condition, Lock * lock){
al_wait_cond(*condition, *lock);
return 0;
}
int conditionSignal(Condition * condition){
al_broadcast_cond(*condition);
return 0;
}
#endif
struct AllegroThreadStuff{
AllegroThreadStuff(const ThreadFunction & function, void * arg):
function(function),
arg(arg){
}
ThreadFunction function;
void * arg;
};
static void * allegro_start_thread(ALLEGRO_THREAD * self, void * _stuff){
AllegroThreadStuff * stuff = (AllegroThreadStuff*) _stuff;
ThreadFunction function = stuff->function;
void * arg = stuff->arg;
delete stuff;
return function(arg);
}
bool createThread(Id * thread, void * attributes, ThreadFunction function, void * arg){
AllegroThreadStuff * stuff = new AllegroThreadStuff(function, arg);
*thread = al_create_thread(allegro_start_thread, stuff);
if (*thread != NULL){
al_start_thread(*thread);
return true;
} else {
delete stuff;
return false;
}
}
void joinThread(Id thread){
if (!isUninitialized(thread)){
al_join_thread(thread, NULL);
}
}
void cancelThread(Id thread){
al_destroy_thread(thread);
}
void destroyLock(Lock * lock){
al_destroy_mutex(*lock);
}
#else
Id uninitializedValue = 0;
bool initializeLock(Lock * lock){
return pthread_mutex_init(lock, NULL) == 0;
}
int acquireLock(Lock * lock){
return pthread_mutex_lock(lock);
}
int releaseLock(Lock * lock){
return pthread_mutex_unlock(lock);
}
#if 0
void initializeCondition(Condition * condition){
pthread_cond_init(condition, NULL);
}
void destroyCondition(Condition * condition){
pthread_cond_destroy(condition);
}
int conditionWait(Condition * condition, Lock * lock){
return pthread_cond_wait(condition, lock);
}
int conditionSignal(Condition * condition){
return pthread_cond_broadcast(condition);
}
#endif
#if 0
void initializeSemaphore(Semaphore * semaphore, unsigned int value){
sem_init(semaphore, 0, value);
}
void destroySemaphore(Semaphore * semaphore){
/* nothing */
}
void semaphoreDecrease(Semaphore * semaphore){
sem_wait(semaphore);
}
void semaphoreIncrease(Semaphore * semaphore){
sem_post(semaphore);
}
#endif
bool createThread(Id * thread, void * attributes, ThreadFunction function, void * arg){
return pthread_create(thread, (pthread_attr_t*) attributes, function, arg) == 0;
}
void joinThread(Id thread){
if (!isUninitialized(thread)){
pthread_join(thread, NULL);
}
}
void cancelThread(Id thread){
/* FIXME: cancel is not implemented for libogc, find another way.
* thread suspend/resume is there, though.
*/
#if !defined(WII) && !defined(USE_NACL)
pthread_cancel(thread);
#endif
}
void destroyLock(Lock * lock){
/* nothing */
}
#endif
}
WaitThread::WaitThread():
done(false){
Thread::initializeLock(&doneLock);
}
WaitThread::WaitThread(Thread::ThreadFunction thread, void * arg){
Thread::initializeLock(&doneLock);
start(thread, arg);
}
static void * do_thread(void * arg){
WaitThread * thread = (WaitThread *) arg;
thread->doRun();
return NULL;
}
void WaitThread::doRun(){
this->function(this->arg);
Thread::acquireLock(&doneLock);
this->done = true;
Thread::releaseLock(&doneLock);
}
void WaitThread::start(Thread::ThreadFunction thread, void * arg){
done = false;
this->arg = arg;
this->function = thread;
Thread::createThread(&this->thread, NULL, (Thread::ThreadFunction) do_thread, this);
}
bool WaitThread::isRunning(){
Thread::acquireLock(&doneLock);
bool what = done;
Thread::releaseLock(&doneLock);
return what;
}
void WaitThread::kill(){
Thread::cancelThread(thread);
Thread::joinThread(thread);
}
WaitThread::~WaitThread(){
/* FIXME: Should we join the thread? */
/* pthread_join(thread); */
Thread::joinThread(thread);
}
ThreadBoolean::ThreadBoolean(volatile bool & what, Thread::Lock & lock):
what(what),
lock(lock){
}
bool ThreadBoolean::get(){
Thread::acquireLock(&lock);
bool b = what;
Thread::releaseLock(&lock);
return b;
}
void ThreadBoolean::set(bool value){
Thread::acquireLock(&lock);
what = value;
Thread::releaseLock(&lock);
}
}
diff --git a/src/timedifference.cpp b/src/timedifference.cpp
index aca8609b..ba4095f7 100644
--- a/src/timedifference.cpp
+++ b/src/timedifference.cpp
@@ -1,86 +1,86 @@
-#include "timedifference.h"
+#include "r-tech1/timedifference.h"
#include <sstream>
#include <iostream>
#include <string>
#include <math.h>
-#include "system.h"
-#include "debug.h"
+#include "r-tech1/system.h"
+#include "r-tech1/debug.h"
using namespace std;
TimeDifference::TimeDifference():
start(0),
end(0){
}
void TimeDifference::startTime(){
start = System::currentMilliseconds();
}
void TimeDifference::endTime(){
end = System::currentMilliseconds();
}
const string TimeDifference::printTime(){
return this->printTime("Function took");
}
unsigned long long int TimeDifference::getTime(){
unsigned long long int g = end - start;
return g;
}
static double roundit(double number, int digits){
return (long long) (number * pow((double) 10.0, digits)) / pow((double) 10.0, digits);
}
const string TimeDifference::printAverageTime(const std::string & description, int runs){
return printTime(description, runs);
}
const string TimeDifference::printTime(const string & description, int runs){
double total = getTime() / (double) runs;
string units = "milliseconds";
int unit_times[] = {1000, 60};
string unit_descriptions[] = {"seconds", "minutes"};
for (unsigned int index = 0; index < sizeof(unit_times) / sizeof(int); index++){
if (total > unit_times[index]){
total /= unit_times[index];
units = unit_descriptions[index];
} else {
break;
}
}
ostringstream o;
o << description << " " << roundit(total, 3) << " " << units;
return o.str();
/*
- unsigned long long int micro = (end.tv_sec*1000000+end.tv_usec) - (start.tv_sec*1000000 + start.tv_usec );
- unsigned long long int milli = micro / 1000;
- unsigned long long int sec = milli / 1000;
+ unsigned long long int micro = (end.tv_sec*1000000+end.tv_usec) - (start.tv_sec*1000000 + start.tv_usec );
+ unsigned long long int milli = micro / 1000;
+ unsigned long long int sec = milli / 1000;
- //cout<<s<<" took "<<micro<<" microseconds / "<< milli << " milliseconds / " <<sec<< " seconds "<< endl;
- ostringstream o;
- o << s <<" took "<<micro<<" microseconds / "<< milli << " milliseconds / " <<sec<< " seconds";
- return o.str();
+ //cout<<s<<" took "<<micro<<" microseconds / "<< milli << " milliseconds / " <<sec<< " seconds "<< endl;
+ ostringstream o;
+ o << s <<" took "<<micro<<" microseconds / "<< milli << " milliseconds / " <<sec<< " seconds";
+ return o.str();
*/
}
TimeDifference::~TimeDifference(){
}
TimeCheck::TimeCheck(const std::string & description):
description(description){
time.startTime();
}
TimeCheck::~TimeCheck(){
time.endTime();
Global::debug(0) << time.printTime(description) << std::endl;
}
diff --git a/src/timer.cpp b/src/timer.cpp
index 23adca5d..079e0a7b 100644
--- a/src/timer.cpp
+++ b/src/timer.cpp
@@ -1,43 +1,43 @@
#include <time.h>
-#include "timer.h"
-#include "init.h"
-#include "funcs.h"
-#include "thread.h"
+#include "r-tech1/timer.h"
+#include "r-tech1/init.h"
+#include "r-tech1/funcs.h"
+#include "r-tech1/thread.h"
namespace Util{
void * do_wait(void * timer_){
Timer * timer = (Timer *) timer_;
unsigned int now = Global::second_counter;
/* add 1 because the current time is in between X and X+1 */
while (Global::second_counter - now < timer->wait+1){
Util::rest(50);
bool do_stop = false;
Thread::acquireLock(&timer->lock);
do_stop = timer->stopped;
Thread::releaseLock(&timer->lock);
if (do_stop){
return NULL;
}
}
timer->func(timer->arg);
return NULL;
}
Timer::Timer(unsigned int seconds_to_wait, timeout func, void * arg):
wait(seconds_to_wait),
func(func),
arg(arg),
stopped(false){
Thread::initializeLock(&lock);
Thread::createThread(&timer, NULL, (Util::Thread::ThreadFunction) do_wait, this);
}
void Timer::stop(){
Thread::acquireLock(&lock);
stopped = true;
Thread::releaseLock(&lock);
Thread::joinThread(timer);
}
}
diff --git a/src/token.cpp b/src/token.cpp
index c856c9c7..07166f53 100644
--- a/src/token.cpp
+++ b/src/token.cpp
@@ -1,792 +1,792 @@
-#include "token.h"
-#include "token_exception.h"
+#include "r-tech1/token.h"
+#include "r-tech1/token_exception.h"
#include <string>
#include <vector>
#include <ostream>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <string.h>
-#include "debug.h"
+#include "r-tech1/debug.h"
using namespace std;
static bool needQuotes(const std::string & what){
/* if it begins with a " and ends with " then it doesnt need more quotes */
if (what.size() > 0 && what[0] == '"' && what[what.size() - 1] == '"'){
return false;
}
/* ripped from tokenreader.cpp, maybe use a variable for nice sharing.. */
const char * alpha = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./-_!:";
for (unsigned int position = 0; position < what.size(); position++){
if (strchr(alpha, what[position]) == NULL){
return true;
}
/*
if (what[position] == '"' ||
what[position] == ' ' ||
(unsigned char) what[position] > 127){
return true;
}
*/
}
return false;
}
/* put quotes around a string if there are spaces in it */
static string quoteify(const string & rhs){
if (needQuotes(rhs)){
return string("\"") + rhs + string("\"");
}
return rhs;
}
Token::Token():
num_token(1),
parent( NULL ),
own(true){
name = "HEAD";
}
Token::Token(string tok, bool parse):
num_token( 1 ),
parent( NULL ),
own(true){
/* legacy code, not used much */
if (!parse){
name = tok;
while (name.find(' ') == 0){
name.erase(0, 1);
}
/*
if (name.find(' ') != string::npos){
name = string("\"") + name + string("\"");
}
*/
}
}
Token::Token(Token const & copy):
num_token(1),
parent(copy.parent),
own(false){
this->tokens = copy.tokens;
this->name = copy.name;
this->filename = copy.filename;
}
/* Dump token to the screen */
void Token::print( const string space ) const {
Global::debug(0) <<space<<"Token: "<< getName() << endl;
for ( signed int i = 0; i < numTokens(); i++ ){
Token * x = getToken( i );
x->print( space + " |--" );
}
}
void Token::toStringCompact(ostream & stream) const {
if (numTokens() == -1){
stream << quoteify(getName());
} else {
stream << "(" << quoteify(getName());
for (signed int i = 0; i < numTokens(); i++){
Token * x = getToken(i);
stream << " ";
x->toStringCompact(stream);
}
stream << ")";
}
}
void Token::toString(ostream & stream, const string & space) const {
if (numTokens() == -1){
stream << quoteify(getName());
} else {
stream << endl;
stream << space << "(" << quoteify(getName());
for ( signed int i = 0; i < numTokens(); i++ ){
Token * x = getToken(i);
stream << " ";
x->toString( stream, space + " " );
}
stream << ")";
}
}
std::string Token::toString() const {
std::ostringstream out;
toString(out, "");
return out.str();
}
std::string Token::toStringCompact() const {
std::ostringstream out;
toStringCompact(out);
return out.str();
}
/* helper function */
string Token::lowerCase( const string & s ) const {
string ret = s;
for ( unsigned int q = 0; q < s.length(); q++ ){
if ( s[q] >= 'A' && s[q] <= 'Z' ){
ret[q] = s[q] - 'A' + 'a';
} else {
// ret[q] = s[q];
}
}
return ret;
}
-
+
/* Return next token and increment the internal position
* of the current token
*/
Token * Token::readToken(){
if ( num_token < tokens.size() ){
return tokens[ num_token++ ];
}
return NULL;
}
-
+
bool Token::hasTokens() const {
return num_token < tokens.size();
}
/*
vector<Token*> Token::findTokens(const string & path){
vector<Token*> whoba;
cout << "whoba has " << whoba.size() << endl;
whoba.push_back(this);
if (whoba[0] != this){
cout << "complete failure!!!" << endl;
}
int x = 2;
x = x + 12;
return whoba;
}
*/
vector<const Token *> Token::findTokens(const string & path) const {
vector<const Token *> found;
if (path == ""){
return found;
}
size_t find = path.find('/');
string self;
if (find == string::npos){
self = path;
} else {
self = path.substr(0, find);
}
/* a name of `_' means succeed with the current token no matter
* what its called.
* `*' means test all children. this is useful if you dont know where in the
* tree a given node lives.
* (... (... (... (foo ...))))
* *\foo would find the foo token (I used backslash because forward slash will
* kill the current c++ comment)
*/
if (self == "*"){
/* `*' and 'blah/stuff', test the current token for 'blah/stuff' */
string rest = path.substr(find+1);
vector<const Token*> more = findTokens(rest);
found.insert(found.end(), more.begin(), more.end());
/* then test all children for the original path */
for (int i = 0; i < numTokens(); i++){
Token * next = getToken(i);
if (next != NULL){
vector<const Token *> more = next->findTokens(path);
found.insert(found.end(), more.begin(), more.end());
}
}
} else if (self == "_" || *this == self){
if (find == string::npos){
found.push_back(this);
if (found[0] != this){
Global::debug(0) << "internal consistency error!!!!" << endl;
throw exception();
}
} else {
string rest = path.substr(find+1);
for (int i = 0; i < numTokens(); i++){
Token * next = getToken(i);
if (next != NULL){
vector<const Token *> more = next->findTokens(rest);
found.insert(found.end(), more.begin(), more.end());
}
}
}
}
return found;
}
TokenMatcher Token::getMatcher(const std::string & subject) const {
TokenMatcher matcher(findTokens(subject));
return matcher;
}
Token * Token::findToken(const string & path){
vector<const Token *> all = findTokens(path);
if (all.size() == 0){
return NULL;
}
return (Token*) all[0];
}
const Token * Token::findToken(const string & path) const {
vector<const Token *> all = findTokens(path);
if (all.size() == 0){
return NULL;
}
return all[0];
}
/*
Token * Token::findToken(const string & path){
if (path == ""){
return NULL;
}
size_t find = path.find('/');
string self;
if (find == string::npos){
self = path;
} else {
self = path.substr(0, find);
}
if (*this == self){
if (find == string::npos){
return this;
} else {
for (int i = 0; i < numTokens(); i++){
Token * next = getToken(i);
if (next != NULL){
Token * ok = next->findToken(path.substr(find+1));
if (ok != NULL){
return ok;
}
}
}
}
}
return NULL;
}
*/
-
+
Token * Token::getToken( unsigned int n ) const {
- int q = numTokens();
- if ( q == -1 ) return NULL;
- if ( (signed int)n < q )
- return tokens[n+1];
- return NULL;
+ int q = numTokens();
+ if ( q == -1 ) return NULL;
+ if ( (signed int)n < q )
+ return tokens[n+1];
+ return NULL;
}
-
+
/* If the token has children then the name of this token
* is the name of the first child token.
* Otherwise, the name is this token's name
*/
const string & Token::getName() const {
if (numTokens() != -1){
return tokens[0]->_getName();
}
// cout<<"No tokens!!"<<endl;
return name;
}
const Token * Token::getParent() const {
return this->parent;
}
Token * Token::getParent(){
return parent;
}
const Token * Token::getRootParent() const {
if (getParent() != NULL){
return getParent()->getRootParent();
}
return this;
}
const string Token::getLineage() const {
if (getParent() != NULL){
return getParent()->getLineage() + " -> " + getName();
}
return getName();
}
/* A token's identity is its name
*/
bool Token::operator== (const string & rhs) const {
return lowerCase(getName()) == lowerCase(rhs);
}
bool Token::operator!=(const string & rhs) const {
return !(*this == rhs);
}
void Token::setFile(const string & s){
filename = s;
}
void Token::removeToken(Token * token){
for (vector<Token*>::iterator it = tokens.begin(); it != tokens.end(); it++){
Token * what = *it;
if (token == what){
/* Found the token. If we own it then delete it, otherwise just
* remove it from the list and return.
*/
if (own){
delete what;
}
it = tokens.erase(it);
return;
}
}
}
const string Token::getFileName() const {
if (parent){
return parent->getFileName();
} else {
return filename;
}
}
/*
Token & Token::operator>>( Token * & rhs ) throw( TokenException ){
Token * x = readToken();
if ( x == NULL ){
throw TokenException(__FILE__, __LINE__, getFileName() + ": " + string("Tried to read a token from ") + this->getName() + string(" but there are no more elements") );
}
rhs = x;
return *this;
}
Token & Token::operator>>( string & rhs ) throw( TokenException ){
Token * token = readToken();
if (token == NULL){
throw TokenException(__FILE__, __LINE__, getFileName() + ":" + string("Tried to read a string from '") + this->getLineage() + string("' but there no more elements") );
}
if (!token->isData()){
ostringstream out;
out << getFileName() << ": Element is not a string '";
token->toString(out, "");
// throw TokenException(__FILE__, __LINE__, getFileName() + ":" + string(" Element is not a string: "));
throw TokenException(__FILE__, __LINE__, out.str());
}
rhs = token->getName();
// rhs = getName();
return *this;
}
-
+
Token & Token::operator>>( int & rhs ) throw( TokenException ){
- Token * l = readToken();
- if ( l == NULL ){
- throw TokenException(__FILE__, __LINE__, getFileName() + ": " + string("Tried to read an int from ") + this->getLineage() + string(" but there are no more elements") );
- }
+ Token * l = readToken();
+ if ( l == NULL ){
+ throw TokenException(__FILE__, __LINE__, getFileName() + ": " + string("Tried to read an int from ") + this->getLineage() + string(" but there are no more elements") );
+ }
if (!l->isData()){
throw TokenException(__FILE__, __LINE__, getFileName() + ":" + string(" Element is not a string"));
}
- istringstream is ( l->getName() );
- is >> rhs;
- return *this;
+ istringstream is ( l->getName() );
+ is >> rhs;
+ return *this;
}
Token & Token::operator>>( double & rhs ) throw( TokenException ){
- Token * l = readToken();
- if ( l == NULL ){
- throw TokenException(__FILE__, __LINE__, getFileName() + ": " + string("Tried to read a double from ") + this->getLineage() + string(" but there no more elements") );
- }
+ Token * l = readToken();
+ if ( l == NULL ){
+ throw TokenException(__FILE__, __LINE__, getFileName() + ": " + string("Tried to read a double from ") + this->getLineage() + string(" but there no more elements") );
+ }
if (!l->isData()){
throw TokenException(__FILE__, __LINE__, getFileName() + ":" + string(" Element is not a string"));
}
- istringstream is ( l->getName() );
- is >> rhs;
- return *this;
+ istringstream is ( l->getName() );
+ is >> rhs;
+ return *this;
}
Token & Token::operator>>( bool & rhs ) throw( TokenException ){
- Token * l = readToken();
- if ( l == NULL ){
- throw TokenException(__FILE__, __LINE__, getFileName() + ": " + string("Tried to read a bool from ") + this->getLineage() + string(" but there no more elements") );
- }
+ Token * l = readToken();
+ if ( l == NULL ){
+ throw TokenException(__FILE__, __LINE__, getFileName() + ": " + string("Tried to read a bool from ") + this->getLineage() + string(" but there no more elements") );
+ }
if (!l->isData()){
throw TokenException(__FILE__, __LINE__, getFileName() + ":" + string(" Element is not a string"));
}
- istringstream is ( l->getName() );
- is >> rhs;
- return *this;
+ istringstream is ( l->getName() );
+ is >> rhs;
+ return *this;
}
*/
void Token::addToken(Token * t){
/*
if (!own){
throw TokenException(__FILE__, __LINE__, "This token does not own its own tokens, so you cannot add tokens to it");
}
*/
t->setParent(this);
tokens.push_back(t);
}
Token * Token::newToken(){
Token * token = new Token();
addToken(token);
return token;
}
TokenView Token::view() const {
vector<const Token*> out;
out.insert(out.end(), tokens.begin(), tokens.end());
return TokenView(out);
}
Token & Token::operator<<(Token * token){
if (!own){
throw TokenException(__FILE__, __LINE__, "Cannot add tokens to a token you don't own");
}
this->addToken(token);
return *this;
}
Token & Token::operator<<(const string & rhs){
if (!own){
throw TokenException(__FILE__, __LINE__, "Cannot add raw strings to a token you don't own");
}
// Token * n = new Token(quoteify(rhs), false);
Token * n = new Token(rhs, false);
this->addToken(n);
return *this;
}
#ifdef XENON
Token & Token::operator<<(const int rhs){
if (!own){
throw TokenException(__FILE__, __LINE__, "Cannot add raw integers to a token you don't own");
}
ostringstream o;
o << rhs;
return *this << o.str();
}
#else
Token & Token::operator<<(const int32_t rhs){
if (!own){
throw TokenException(__FILE__, __LINE__, "Cannot add raw integers to a token you don't own");
}
ostringstream o;
o << rhs;
return *this << o.str();
}
#endif
Token & Token::operator<<(const int64_t rhs){
if (!own){
throw TokenException(__FILE__, __LINE__, "Cannot add raw integers to a token you don't own");
}
ostringstream o;
o << rhs;
return *this << o.str();
}
Token & Token::operator<<(const uint32_t rhs){
if (!own){
throw TokenException(__FILE__, __LINE__, "Cannot add raw integers to a token you don't own");
}
ostringstream o;
o << rhs;
return *this << o.str();
}
Token & Token::operator<<(const uint64_t rhs){
if (!own){
throw TokenException(__FILE__, __LINE__, "Cannot add raw integers to a token you don't own");
}
ostringstream o;
o << rhs;
return *this << o.str();
}
Token & Token::operator<<( const double rhs ){
if (!own){
throw TokenException(__FILE__, __LINE__, "Cannot add raw doubles to a token you don't own");
}
ostringstream o;
o << setprecision(6) << fixed << rhs;
return *this << o.str();
}
Token * Token::copy() const {
Token * token = new Token();
token->filename = this->filename;
token->name = this->name;
for (vector<Token *>::const_iterator it = this->tokens.begin(); it != this->tokens.end(); it++){
Token * him = (*it)->copy();
him->setParent(token);
token->addToken(him);
}
return token;
}
/* Delete tokens that are commented.
* A commented token has a '!' character as the first
* character in the name, e.g:
* (!a_token (child_token 2))
*/
/*
void Token::finalize(){
for ( vector< Token * >::iterator it = tokens.begin(); it != tokens.end(); ){
Token * t = *it;
if ( t->getName().find('!') == 0 ){
delete t;
it = tokens.erase( it );
} else {
t->finalize();
it++;
}
}
}
*/
Token::~Token(){
if (own){
for (vector<Token * >::iterator it = tokens.begin(); it != tokens.end(); it++){
delete *it;
}
}
}
TokenMatcher::TokenMatcher(){
throw TokenException(__FILE__, __LINE__, "Cannot instantiate a token matcher");
}
TokenMatcher & TokenMatcher::operator=(const TokenMatcher & matcher){
tokens = matcher.tokens;
current = tokens.begin();
return *this;
}
TokenMatcher::TokenMatcher(std::vector<const Token*> tokens):
tokens(tokens){
current = this->tokens.begin();
}
TokenView::TokenView(std::vector<const Token *> tokens):
tokens(tokens){
current = this->tokens.begin();
if (current != this->tokens.end()){
current++;
}
}
TokenView::TokenView(const TokenView & view):
tokens(view.tokens){
/* FIXME: should this start at the same place the view.current is at? */
current = this->tokens.begin();
if (current != this->tokens.end()){
current++;
}
}
bool TokenView::hasMore() const {
return current != tokens.end();
}
TokenView & TokenView::operator=(const TokenView & view){
tokens = view.tokens;
current = tokens.begin();
if (current != tokens.end()){
current++;
}
return *this;
}
TokenView & TokenView::operator>>(string & item){
if (current == tokens.end()){
throw TokenException(__FILE__, __LINE__, "No more elements");
}
const Token * child = *current;
if (!child->isData()){
throw TokenException(__FILE__, __LINE__, "Token is not a datum");
}
item = child->getName();
current++;
return *this;
}
TokenView & TokenView::operator>>(int & item){
if (current == tokens.end()){
throw TokenException(__FILE__, __LINE__, "No more elements");
}
const Token * child = *current;
if (!child->isData()){
throw TokenException(__FILE__, __LINE__, "Token is not a datum");
}
istringstream out(child->getName());
out >> item;
current++;
return *this;
}
TokenView & TokenView::operator>>(unsigned char & item){
if (current == tokens.end()){
throw TokenException(__FILE__, __LINE__, "No more elements");
}
const Token * child = *current;
if (!child->isData()){
throw TokenException(__FILE__, __LINE__, "Token is not a datum");
}
istringstream out(child->getName());
out >> item;
current++;
return *this;
}
TokenView & TokenView::operator>>(uint64_t & item){
if (current == tokens.end()){
throw TokenException(__FILE__, __LINE__, "No more elements");
}
const Token * child = *current;
if (!child->isData()){
throw TokenException(__FILE__, __LINE__, "Token is not a datum");
}
istringstream out(child->getName());
out >> item;
current++;
return *this;
}
TokenView & TokenView::operator>>(uint32_t & item){
if (current == tokens.end()){
throw TokenException(__FILE__, __LINE__, "No more elements");
}
const Token * child = *current;
if (!child->isData()){
throw TokenException(__FILE__, __LINE__, "Token is not a datum");
}
istringstream out(child->getName());
out >> item;
current++;
return *this;
}
TokenView & TokenView::operator>>(double & item){
if (current == tokens.end()){
throw TokenException(__FILE__, __LINE__, "No more elements");
}
const Token * child = *current;
if (!child->isData()){
throw TokenException(__FILE__, __LINE__, "Token is not a datum");
}
istringstream out(child->getName());
out >> item;
current++;
return *this;
}
static bool isTrue(const string & name){
return name == "true" ||
name == "1" ||
name == "on" ||
name == "enable";
}
static bool isFalse(const string & name){
return name == "false" ||
name == "0" ||
name == "off" ||
name == "disable";
}
TokenView & TokenView::operator>>(bool & item){
if (current == tokens.end()){
throw TokenException(__FILE__, __LINE__, "No more elements");
}
const Token * child = *current;
if (!child->isData()){
throw TokenException(__FILE__, __LINE__, "Token is not a datum");
}
string what = child->getName();
if (isTrue(what)){
item = true;
} else if (isFalse(what)){
item = false;
} else {
ostringstream fail;
fail << "Not a true/false value: " << what << ". True values are 'true', '1', 'on', 'enable'. False values are 'false', 0', 'off', 'disable'";
throw TokenException(__FILE__, __LINE__, fail.str());
}
current++;
return *this;
}
TokenView & TokenView::operator>>(const Token* & item){
if (current == tokens.end()){
throw TokenException(__FILE__, __LINE__, "No more elements");
}
const Token * child = *current;
/*
if (!child->isData()){
throw TokenException(__FILE__, __LINE__, "Token is not a datum");
}
*/
item = child;
current++;
return *this;
}
const Token * TokenView::next(){
if (current == tokens.end()){
throw TokenException(__FILE__, __LINE__, "No more elements");
}
const Token * child = *current;
current++;
return child;
}
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/src/tokenreader.cpp b/src/tokenreader.cpp
index fedf0444..36159062 100644
--- a/src/tokenreader.cpp
+++ b/src/tokenreader.cpp
@@ -1,343 +1,343 @@
#include <fstream>
#include <iostream>
#include <string>
#include <cstring>
#include <sstream>
#include <vector>
-#include "file-system.h"
-#include "token.h"
-#include "token_exception.h"
-#include "tokenreader.h"
-#include "pointer.h"
+#include "r-tech1/file-system.h"
+#include "r-tech1/token.h"
+#include "r-tech1/token_exception.h"
+#include "r-tech1/tokenreader.h"
+#include "r-tech1/pointer.h"
using namespace std;
/* tokenreader reads a file formatted with s-expressions. examples:
* (hello)
* (hello world)
* (hello "world")
* (hello (world))
* (hello (world hi))
*/
TokenReader::TokenReader(){
}
TokenReader::TokenReader(const char * file){
readTokenFromFile(file);
}
TokenReader::TokenReader(const string & file){
readTokenFromFile(file);
}
Token * TokenReader::readTokenFromFile(const std::string & path){
/*
ifstream file(path.c_str());
if (!file){
ostringstream out;
out << "Could not open '" << path << "'";
throw TokenException(__FILE__, __LINE__, out.str());
}
file >> noskipws;
*/
Filesystem::AbsolutePath realPath(path);
Util::ReferenceCount<Storage::File> file = Storage::instance().open(realPath);
if (file == NULL || !file->good()){
throw TokenException(__FILE__, __LINE__, string("Could not read ") + realPath.path());
}
readTokens(*file.raw());
// file.close();
if (my_tokens.size() > 0){
my_tokens[0]->setFile(path);
return my_tokens[0];
}
ostringstream out;
out << "No tokens read from " << path;
throw TokenException(__FILE__, __LINE__, out.str());
}
Token * TokenReader::readTokenFromFile(Storage::File & file){
readTokens(file);
// file.close();
if (my_tokens.size() > 0){
my_tokens[0]->setFile("");
return my_tokens[0];
}
ostringstream out;
out << "No tokens read from file";
throw TokenException(__FILE__, __LINE__, out.str());
}
Token * TokenReader::readToken(){
if (my_tokens.size() > 0){
return my_tokens[0];
}
throw TokenException(__FILE__, __LINE__, "No tokens read");
}
Token * TokenReader::readToken(const string & path){
return readTokenFromFile(path);
}
Token * TokenReader::readToken(const char * path){
return readTokenFromFile(path);
}
Token * TokenReader::readTokenFromString(const string & stuff){
/*
istringstream input(stuff);
input >> noskipws;
*/
Storage::StringFile input(stuff);
readTokens(input);
if (my_tokens.size() > 0){
return my_tokens[0];
}
throw TokenException(__FILE__, __LINE__, "No tokens read");
}
TokenReader::~TokenReader(){
// ifile.close();
/* tokenreader giveth, and tokenreader taketh */
for ( vector< Token * >::iterator it = my_tokens.begin(); it != my_tokens.end(); it++ ){
delete *it;
}
}
static inline bool is_alpha(char c){
// const char * alpha = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./-_!:*";
const char * alpha = "./-_!:*";
return (c >= 'a' && c <= 'z') ||
(c >= 'A' && c <= 'Z') ||
(c >= '0' && c <= '9') ||
strchr(alpha, c) != NULL;
}
static inline bool is_nonalpha(char c){
const char * nonalpha = " ;()#\"";
return strchr(nonalpha, c) != NULL;
}
class BufferedStream{
public:
BufferedStream(Storage::File & input):
data(NULL),
position(0),
size(input.getSize()){
if (input.getSize() == 0){
throw TokenException(__FILE__, __LINE__, "File has size 0");
}
data = new unsigned char[size];
input.readLine((char*) data, size);
}
BufferedStream & operator>>(unsigned char & n){
if (position < size){
n = data[position];
position += 1;
}
return *this;
}
bool eof(){
return position >= size;
}
~BufferedStream(){
delete[] data;
}
unsigned char * data;
int position;
int size;
};
void TokenReader::readTokens(Storage::File & input){
/*
if ( !ifile ){
ostringstream out;
out << "Could not open '" << myfile << "'";
throw TokenException(__FILE__, __LINE__, out.str());
}
*/
// Token * t;
// string token_string;
// char open_paren = 'x';
int parens = 0;
// int position = 0;
/*
while (input.good() && open_paren != '('){
input >> open_paren;
position += 1;
}
*/
// token_string += '(';
BufferedStream buffer(input);
Token * currentToken = NULL;
// Token * cur_token = new Token();
// cur_token->setFile(myfile);
// my_tokens.push_back(cur_token);
// Token * first = cur_token;
vector<Token *> token_stack;
/* tokens that were ignored using ;@, and should be deleted */
vector<Util::ReferenceCount<Token> > ignore_list;
// token_stack.push_back(cur_token);
/* when a ;@ is seen, read the next s-expression but throw it away */
bool do_ignore = false;
unsigned char n = 0;
string cur_string = "";
/* in_quote is true if a " is read and before another " is read */
bool in_quote = false;
/* escaped unconditionally adds the next character to the string */
bool escaped = false;
while (!buffer.eof()){
// char n;
// slow as we go
buffer >> n;
// position += 1;
// printf("Read character '%c' %d at %d\n", n, n, input.tellg());
// cout << "Read character '" << n << "' " << (int) n << " at " << input.tellg() << endl;
// cout<<"Alpha char: "<<n<<endl;
if (escaped){
switch (n){
case 'n' : {
cur_string += "\n";
break;
}
default : {
cur_string += n;
break;
}
}
escaped = false;
continue;
}
if (n == '\\'){
escaped = true;
continue;
}
if (in_quote){
if (n == '"'){
in_quote = false;
Token * sub = new Token(cur_string, false);
if (currentToken != NULL){
sub->setParent(currentToken);
if (do_ignore){
ignore_list.push_back(Util::ReferenceCount<Token>(sub));
do_ignore = false;
} else {
currentToken->addToken(sub);
}
cur_string = "";
} else {
delete sub;
}
} else {
cur_string += n;
}
} else {
/* not in a quote */
if (n == '"'){
in_quote = true;
} else if (is_alpha(n)){
cur_string += n;
} else if (cur_string != "" && is_nonalpha(n)){
// cout<<"Made new token "<<cur_string<<endl;
Token * sub = new Token(cur_string, false);
if (currentToken != NULL){
sub->setParent(currentToken);
if (do_ignore){
do_ignore = false;
ignore_list.push_back(Util::ReferenceCount<Token>(sub));
} else {
currentToken->addToken(sub);
}
} else {
delete sub;
}
cur_string = "";
}
if (n == '#' || n == ';'){
buffer >> n;
/* if the next character is a @ then ignore the next entire s-expression
* otherwise just ignore the current line
*/
if (n == '@'){
do_ignore = true;
} else {
while (n != '\n' && !buffer.eof()){
buffer >> n;
}
continue;
}
} else if (n == '('){
Token * another = new Token();
if (currentToken != NULL){
another->setParent(currentToken);
}
if (do_ignore){
ignore_list.push_back(Util::ReferenceCount<Token>(another));
do_ignore = false;
} else {
if (currentToken != NULL){
currentToken->addToken(another);
} else {
/* top level token */
my_tokens.push_back(another);
}
}
parens += 1;
currentToken = another;
token_stack.push_back(currentToken);
} else if (n == ')'){
parens -= 1;
if (token_stack.empty()){
throw TokenException(__FILE__, __LINE__, "Saw a ) but there is no corresponding (");
}
token_stack.pop_back();
if (! token_stack.empty()){
currentToken = token_stack.back();
} else {
currentToken = NULL;
}
}
}
}
if (!token_stack.empty()){
ostringstream failure;
failure << "Wrong number of parentheses. Open parens is " << parens;
throw TokenException(__FILE__, __LINE__, failure.str());
}
/*
for (vector<Token*>::iterator it = my_tokens.begin(); it != my_tokens.end(); it++){
Token * token = *it;
token->finalize();
}
*/
}
diff --git a/src/utf.cpp b/src/utf.cpp
index cfa8ea83..2ff49834 100644
--- a/src/utf.cpp
+++ b/src/utf.cpp
@@ -1,168 +1,168 @@
-#include "utf.h"
+#include "r-tech1/utf.h"
#include <string>
#include <sstream>
using std::string;
using std::ostringstream;
namespace Utf{
/* utf8 decoding. reads a utf8 string and returns a unicode code point.
* position should be a pointer to an integer that stores the current
* place in the input string where the next character is to be read.
* FIXME: handle the case when `position' runs out of bytes
*/
long readUtf8CodePoint(const std::string & input, unsigned int * position){
unsigned char byte1 = (unsigned char) input[*position];
/* one byte - ascii */
if (byte1 >> 7 == 0){
return byte1;
}
if (byte1 >> 5 == 6){
*position += 1;
if (*position >= input.size()){
return 0;
}
unsigned char byte2 = (unsigned char) input[*position];
int top = byte1 & 31;
int bottom = byte2 & 63;
return (top << 6) + bottom;
}
if (byte1 >> 4 == 14){
*position += 1;
if (*position >= input.size()){
return 0;
}
unsigned char byte2 = (unsigned char) input[*position];
*position += 1;
if (*position >= input.size()){
return 0;
}
unsigned char byte3 = (unsigned char) input[*position];
int top4 = byte1 & 15;
int middle6 = byte2 & 63;
int bottom6 = byte3 & 63;
return (top4 << (6+6)) + (middle6 << 6) + bottom6;
}
if (byte1 >> 3 == 30){
*position += 1;
if (*position >= input.size()){
return 0;
}
unsigned char byte2 = (unsigned char) input[*position];
*position += 1;
if (*position >= input.size()){
return 0;
}
unsigned char byte3 = (unsigned char) input[*position];
*position += 1;
if (*position >= input.size()){
return 0;
}
unsigned char byte4 = (unsigned char) input[*position];
int unit1 = byte1 & 7;
int unit2 = byte2 & 63;
int unit3 = byte3 & 63;
int unit4 = byte4 & 63;
return (unit1 << 18) + (unit2 << 12) + (unit3 << 6) + unit4;
}
return 0;
}
string codePointToUtf8(long unicode){
ostringstream out;
if (unicode <= 0x7f){
out << (char) unicode;
} else if (unicode <= 0x7ff){
/* 110xxxxx 10xxxxxx */
unsigned char byte1 = ((unicode >> (1 * 6)) & 0x1f) | (6 << 5);
unsigned char byte2 = (unicode & 0x3f) | (2 << 6);
out << byte1 << byte2;
} else if (unicode <= 0xffff){
/* 1110xxxx 10xxxxxx 10xxxxxx */
unsigned char byte1 = ((unicode >> (2 * 6)) & 0xf) | (0xe << 4);
unsigned char byte2 = ((unicode >> (1 * 6)) & 0x3f) | (2 << 6);
unsigned char byte3 = (unicode & 0x3f) | (2 << 6);
out << byte1 << byte2 << byte3;
} else if (unicode <= 0x1fffff){
/* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
unsigned char byte1 = ((unicode >> (3 * 6)) & 0x7) | (0x1e << 3);
unsigned char byte2 = ((unicode >> (2 * 6)) & 0x3f) | (2 << 6);
unsigned char byte3 = ((unicode >> (1 * 6)) & 0x3f) | (2 << 6);
unsigned char byte4 = (unicode & 0x3f) | (2 << 6);
out << byte1 << byte2 << byte3 << byte4;
} else if (unicode <= 0x3ffffff){
/* 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */
unsigned char byte1 = ((unicode >> (4 * 6)) & 0x3) | (0x3e << 2);
unsigned char byte2 = ((unicode >> (3 * 6)) & 0x3f) | (2 << 6);
unsigned char byte3 = ((unicode >> (2 * 6)) & 0x3f) | (2 << 6);
unsigned char byte4 = ((unicode >> (1 * 6)) & 0x3f) | (2 << 6);
unsigned char byte5 = (unicode & 0x3f) | (2 << 6);
out << byte1 << byte2 << byte3 << byte4 << byte5;
} else if (unicode <= 0x7fffffff){
/* 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */
unsigned char byte1 = ((unicode >> (5 * 6)) & 0x1) | (0x7e << 1);
unsigned char byte2 = ((unicode >> (4 * 6)) & 0x3f) | (2 << 6);
unsigned char byte3 = ((unicode >> (3 * 6)) & 0x3f) | (2 << 6);
unsigned char byte4 = ((unicode >> (2 * 6)) & 0x3f) | (2 << 6);
unsigned char byte5 = ((unicode >> (1 * 6)) & 0x3f) | (2 << 6);
unsigned char byte6 = (unicode & 0x3f) | (2 << 6);
out << byte1 << byte2 << byte3 << byte4 << byte5 << byte6;
}
return out.str();
}
/* Reads a code point from a utf16 string made up of uint16_t integers */
/* FIXME: add length for input */
long readUtf16CodePoint(const uint16_t * input, unsigned int * position){
uint16_t word1 = input[*position];
*position += 1;
/* 1) If W1 < 0xD800 or W1 > 0xDFFF, the character value U is the value
* of W1. Terminate.
*/
if (word1 < 0xd800 || word1 > 0xdfff){
return word1;
}
/* 2) Determine if W1 is between 0xD800 and 0xDBFF. If not, the sequence
* is in error and no valid character can be obtained using W1.
* Terminate.
*/
if (word1 >= 0xd800 && word1 <= 0xdbff){
/* 3) If there is no W2 (that is, the sequence ends with W1), or if W2
* is not between 0xDC00 and 0xDFFF, the sequence is in error.
* Terminate.
*/
uint16_t word2 = input[*position];
if (word2 >= 0xdc00 && word2 <= 0xdfff){
*position += 1;
/* 4) Construct a 20-bit unsigned integer U', taking the 10 low-order
* bits of W1 as its 10 high-order bits and the 10 low-order bits of
* W2 as its 10 low-order bits.
*/
/* 5) Add 0x10000 to U' to obtain the character value U. Terminate. */
return (((word1 & 0x3ff) << 10) |
(word2 & 0x3ff)) + 0x10000;
}
}
return 0;
}
std::string utf16_to_utf8(const uint16_t * utf16){
ostringstream out;
unsigned int position = 0;
while (utf16[position] != 0){
out << codePointToUtf8(readUtf16CodePoint(utf16, &position));
}
return out.str();
}
}
diff --git a/src/version.cpp b/src/version.cpp
index 8dff518f..580ef6cc 100644
--- a/src/version.cpp
+++ b/src/version.cpp
@@ -1,32 +1,32 @@
-#include "version.h"
+#include "r-tech1/version.h"
#include <sstream>
using std::string;
namespace Version{
static int major_version = 1;
static int minor_version = 0;
static int micro_version = 0;
void setVersion(int major, int minor, int micro){
major_version = major;
minor_version = minor;
micro_version = micro;
}
int getVersion(int major, int minor, int micro){
return major * 1000 + minor * 100 + micro;
}
int getVersion(){
return getVersion(major_version, minor_version, micro_version);
}
string getVersionString(){
std::ostringstream str;
str << major_version << "." << minor_version << "." << micro_version;
return str.str();
}
}

File Metadata

Mime Type
text/x-diff
Expires
Tue, Jun 16, 1:28 AM (2 w, 19 h ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
70136
Default Alt Text
(248 KB)

Event Timeline