Merge pull request #5342 from heliclei/console-user-command

closed #4063 :revise CCConsole to support more easily for adding custom command.
This commit is contained in:
James Chen 2014-02-18 16:54:56 +08:00
commit 58d3311da0
3 changed files with 76 additions and 83 deletions

View File

@ -30,8 +30,8 @@
#include <cctype> #include <cctype>
#include <locale> #include <locale>
#include <sstream> #include <sstream>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <time.h> #include <time.h>
#include <fcntl.h> #include <fcntl.h>
@ -61,7 +61,7 @@
NS_CC_BEGIN NS_CC_BEGIN
//TODO: these general utils should be in a seperate class
// //
// Trimming functions were taken from: http://stackoverflow.com/a/217605 // Trimming functions were taken from: http://stackoverflow.com/a/217605
// //
@ -82,6 +82,22 @@ static std::string &trim(std::string &s) {
return ltrim(rtrim(s)); return ltrim(rtrim(s));
} }
std::vector<std::string> &split(const std::string &s, char delim, std::vector<std::string> &elems) {
std::stringstream ss(s);
std::string item;
while (std::getline(ss, item, delim)) {
elems.push_back(item);
}
return elems;
}
std::vector<std::string> split(const std::string &s, char delim) {
std::vector<std::string> elems;
split(s, delim, elems);
return elems;
}
// helper free functions // helper free functions
@ -229,8 +245,6 @@ Console::Console()
: _listenfd(-1) : _listenfd(-1)
, _running(false) , _running(false)
, _endThread(false) , _endThread(false)
, _userCommands(nullptr)
, _maxUserCommands(0)
, _sendDebugStrings(false) , _sendDebugStrings(false)
{ {
// VS2012 doesn't support initializer list, so we create a new array and assign its elements to '_command'. // VS2012 doesn't support initializer list, so we create a new array and assign its elements to '_command'.
@ -262,10 +276,10 @@ Console::Console()
{ "texture", "Flush or print the TextureCache info. Args: [flush | ] ", std::bind(&Console::commandTextures, this, std::placeholders::_1, std::placeholders::_2) }, { "texture", "Flush or print the TextureCache info. Args: [flush | ] ", std::bind(&Console::commandTextures, this, std::placeholders::_1, std::placeholders::_2) },
}; };
_maxCommands = sizeof(commands)/sizeof(commands[0]); ;
for (int i = 0; i < _maxCommands; ++i) for (int i = 0; i < sizeof(commands)/sizeof(commands[0]); ++i)
{ {
_commands[i] = commands[i]; _commands.insert ( std::pair<std::string,Command>(commands[i].name,commands[i]) );
} }
} }
@ -282,7 +296,6 @@ bool Console::listenOnTCP(int port)
char serv[30]; char serv[30];
snprintf(serv, sizeof(serv)-1, "%d", port ); snprintf(serv, sizeof(serv)-1, "%d", port );
serv[sizeof(serv)-1]=0;
bzero(&hints, sizeof(struct addrinfo)); bzero(&hints, sizeof(struct addrinfo));
hints.ai_flags = AI_PASSIVE; hints.ai_flags = AI_PASSIVE;
@ -364,13 +377,11 @@ void Console::stop()
} }
} }
void Console::setUserCommands(Command *commands, int numberOfCommands) void Console::addCommand(const Command& cmd)
{ {
_userCommands = commands; _commands[cmd.name]=cmd;
_maxUserCommands = numberOfCommands;
} }
// //
// commands // commands
// //
@ -379,26 +390,17 @@ void Console::commandHelp(int fd, const std::string &args)
{ {
const char help[] = "\nAvailable commands:\n"; const char help[] = "\nAvailable commands:\n";
write(fd, help, sizeof(help)); write(fd, help, sizeof(help));
for(int i=0; i<_maxCommands; ++i) { for(auto it=_commands.begin();it!=_commands.end();++it)
mydprintf(fd, "\t%s", _commands[i].name); {
ssize_t tabs = strlen(_commands[i].name) / 8; auto cmd = it->second;
mydprintf(fd, "\t%s", cmd.name);
ssize_t tabs = strlen(cmd.name) / 8;
tabs = 3 - tabs; tabs = 3 - tabs;
for(int j=0;j<tabs;j++){ for(int j=0;j<tabs;j++){
mydprintf(fd, "\t"); mydprintf(fd, "\t");
} }
mydprintf(fd,"%s\n", _commands[i].help); mydprintf(fd,"%s\n", cmd.help);
} }
// User commands
for(int i=0; i<_maxUserCommands; ++i) {
mydprintf(fd, "\t%s", _userCommands[i].name);
ssize_t tabs = strlen(_userCommands[i].name) / 8;
tabs = 3 - tabs;
for(int j=0;j<tabs;j++){
mydprintf(fd, "\t");
}
mydprintf(fd,"%s\n", _userCommands[i].help);
}
} }
void Console::commandExit(int fd, const std::string &args) void Console::commandExit(int fd, const std::string &args)
@ -437,6 +439,7 @@ void Console::commandConfig(int fd, const std::string& args)
Scheduler *sched = Director::getInstance()->getScheduler(); Scheduler *sched = Director::getInstance()->getScheduler();
sched->performFunctionInCocosThread( [&](){ sched->performFunctionInCocosThread( [&](){
mydprintf(fd, "%s", Configuration::getInstance()->getInfo().c_str()); mydprintf(fd, "%s", Configuration::getInstance()->getInfo().c_str());
sendPrompt(fd);
} }
); );
} }
@ -467,7 +470,6 @@ void Console::commandResolution(int fd, const std::string& args)
(int)visibleRect.origin.x, (int)visibleRect.origin.y, (int)visibleRect.origin.x, (int)visibleRect.origin.y,
(int)visibleRect.size.width, (int)visibleRect.size.height (int)visibleRect.size.width, (int)visibleRect.size.height
); );
sendPrompt(fd);
} else { } else {
int width, height, policy; int width, height, policy;
@ -554,46 +556,45 @@ void Console::commandTextures(int fd, const std::string& args)
bool Console::parseCommand(int fd) bool Console::parseCommand(int fd)
{ {
auto r = readline(fd); char buf[512];
auto r = readline(fd, buf, sizeof(buf)-1);
if(r < 1) if(r < 1)
{
const char err[] = "Unknown error!\n";
sendPrompt(fd);
write(fd, err, sizeof(err));
return false; return false;
}
std::string cmdLine;
bool found=false; std::vector<std::string> args;
for(int i=0; i < _maxCommands; ++i) { cmdLine = std::string(buf);
ssize_t commandLen = strlen(_commands[i].name);
if( strncmp(_buffer, _commands[i].name,commandLen) == 0 ) { args = split(cmdLine, ' ');
// XXX TODO FIXME if(args.empty())
// Ideally this loop should execute the function in the cocos2d according to a variable {
// But clang crashes in runtime when doing that (bug in clang, not in the code). const char err[] = "Unknown command. Type 'help' for options\n";
// So, unfortunately, the only way to fix it was to move that logic to the callback itself write(fd, err, sizeof(err));
sendPrompt(fd);
std::string args; return false;
if(strlen(_buffer) >= commandLen+2) {
args = std::string(&_buffer[commandLen]+1);
args = trim(args);
}
_commands[i].callback(fd, args);
found = true;
break;
}
} }
// user commands auto it = _commands.find(trim(args[0]));
for(int i=0; i < _maxUserCommands && !found; ++i) { if(it != _commands.end())
ssize_t commandLen = strlen(_userCommands[i].name); {
if( strncmp(_buffer, _userCommands[i].name,commandLen) == 0 ) { std::string args2;
std::string args; for(int i = 1; i < args.size(); ++i)
if(strlen(_buffer) >= commandLen+2) { {
args = std::string(&_buffer[commandLen]+1); if(i > 1)
args = trim(args); {
args2 += ' ';
} }
_userCommands[i].callback(fd, args); args2 += trim(args[i]);
found = true;
break;
} }
} auto cmd = it->second;
cmd.callback(fd, args2);
if(!found && strcmp(_buffer, "\r\n")!=0) { }else if(strcmp(buf, "\r\n") != 0) {
const char err[] = "Unknown command. Type 'help' for options\n"; const char err[] = "Unknown command. Type 'help' for options\n";
write(fd, err, sizeof(err)); write(fd, err, sizeof(err));
} }
@ -608,19 +609,17 @@ bool Console::parseCommand(int fd)
// //
ssize_t Console::readline(int fd) ssize_t Console::readline(int fd, char* ptr, int maxlen)
{ {
int maxlen = sizeof(_buffer)-1;
ssize_t n, rc; ssize_t n, rc;
char c, *ptr; char c;
ptr = _buffer; for( n=1; n<maxlen-1; n++ ) {
for( n=1; n<maxlen; n++ ) {
if( (rc = read(fd, &c, 1 )) ==1 ) { if( (rc = read(fd, &c, 1 )) ==1 ) {
*ptr++ = c; *ptr++ = c;
if( c=='\n' ) if(c == '\n') {
break; break;
}
} else if( rc == 0 ) { } else if( rc == 0 ) {
return 0; return 0;
} else if( errno == EINTR ) { } else if( errno == EINTR ) {

View File

@ -39,10 +39,10 @@ typedef int ssize_t;
#include <thread> #include <thread>
#include <vector> #include <vector>
#include <map>
#include <functional> #include <functional>
#include <string> #include <string>
#include <mutex> #include <mutex>
#include <stdarg.h> #include <stdarg.h>
#include "ccMacros.h" #include "ccMacros.h"
@ -92,16 +92,16 @@ public:
/** stops the Console. 'stop' will be called at destruction time as well */ /** stops the Console. 'stop' will be called at destruction time as well */
void stop(); void stop();
/** sets user tokens */ /** add custom command */
void setUserCommands( Command* commands, int numberOfCommands); void addCommand(const Command& cmd);
/** log something in the console */ /** log something in the console */
void log(const char *buf); void log(const char *buf);
protected: protected:
void loop(); void loop();
ssize_t readline(int fd); ssize_t readline(int fd, char *buf, int maxlen);
bool parseCommand(int fd); bool parseCommand(int fd);
void addClient(); void addClient();
// Add commands here // Add commands here
@ -125,13 +125,7 @@ protected:
bool _running; bool _running;
bool _endThread; bool _endThread;
char _buffer[512]; std::map<std::string, Command> _commands;
struct Command _commands[64];
int _maxCommands;
struct Command *_userCommands;
int _maxUserCommands;
// strings generated by cocos2d sent to the remote console // strings generated by cocos2d sent to the remote console
bool _sendDebugStrings; bool _sendDebugStrings;

View File

@ -175,7 +175,7 @@ ConsoleCustomCommand::ConsoleCustomCommand()
write(fd, "\n",1); write(fd, "\n",1);
}}, }},
}; };
_console->setUserCommands(&commands[0],1); _console->addCommand(commands[0]);
} }
ConsoleCustomCommand::~ConsoleCustomCommand() ConsoleCustomCommand::~ConsoleCustomCommand()