+ std::string prefix = inputBuffer.str();
+ addLines("> "+prefix);
+
+ std::list<std::string> cmds;
+
+ // append all known CCRs to list
+ for (std::map<std::string, std::list<ConsoleCommandReceiver*> >::iterator i = commands.begin(); i != commands.end(); i++) {
+ std::string cmdKnown = i->first;
+ if (cmdKnown.substr(0, prefix.length()) == prefix) {
+ cmds.push_back(cmdKnown);
+ }
+ }
+
+ ready_vm();
+
+ // append all keys of the current root table to list
+ sq_pushroottable(vm); // push root table
+ while(true) {
+ // check all keys (and their children) for matches
+ sq_insert_commands(cmds, vm, "", prefix);
+
+ // cycle through parent(delegate) table
+ SQInteger oldtop = sq_gettop(vm);
+ if(SQ_FAILED(sq_getdelegate(vm, -1)) || oldtop == sq_gettop(vm)) {
+ break;
+ }
+ sq_remove(vm, -2); // remove old table
+ }
+ sq_pop(vm, 1); // remove table
+
+ // depending on number of hits, show matches or autocomplete
+ if (cmds.size() == 0) addLines("No known command starts with \""+prefix+"\"");
+ if (cmds.size() == 1) {
+ inputBuffer.str(cmds.front());
+ inputBuffer.pubseekoff(0, std::ios_base::end, std::ios_base::out);
+ }
+ if (cmds.size() > 1) {
+ while (cmds.begin() != cmds.end()) {
+ addLines(cmds.front());
+ cmds.pop_front();
+ }
+ }
+}
+
+void
+Console::addLines(std::string s)
+{
+ std::istringstream iss(s);
+ std::string line;
+ while (std::getline(iss, line, '\n')) addLine(line);
+}
+
+void
+Console::addLine(std::string s)
+{
+ // output line to stderr
+ std::cerr << s << std::endl;
+
+ // wrap long lines
+ std::string overflow;
+ do {
+ lines.push_front(Font::wrap_to_chars(s, 99, &overflow));
+ s = overflow;
+ } while (s.length() > 0);
+
+ // trim scrollback buffer
+ while (lines.size() >= 1000)
+ lines.pop_back();
+
+ // increase console height if necessary
+ if (height < 64) {
+ if(height < 4)
+ height = 4;
+ height += fontheight;
+ }
+
+ // reset console to full opacity
+ alpha = 1.0;
+
+ // increase time that console stays open
+ if(stayOpen < 6)
+ stayOpen += 1.5;
+}
+
+void
+Console::parse(std::string s)
+{
+ // make sure we actually have something to parse
+ if (s.length() == 0) return;
+
+ // add line to history
+ history.push_back(s);
+ history_position = history.end();
+
+ // split line into list of args
+ std::vector<std::string> args;
+ size_t start = 0;
+ size_t end = 0;
+ while (1) {
+ start = s.find_first_not_of(" ,", end);
+ end = s.find_first_of(" ,", start);
+ if (start == s.npos) break;
+ args.push_back(s.substr(start, end-start));
+ }
+
+ // command is args[0]
+ if (args.size() == 0) return;
+ std::string command = args.front();
+ args.erase(args.begin());
+
+ // ignore if it's an internal command
+ if (consoleCommand(command,args)) return;
+
+ // look up registered ccr
+ std::map<std::string, std::list<ConsoleCommandReceiver*> >::iterator i = commands.find(command);
+ if ((i == commands.end()) || (i->second.size() == 0)) {
+ try {
+ execute_script(s);
+ } catch(std::exception& e) {
+ addLines(e.what());
+ }
+ return;
+ }
+
+ // send command to the most recently registered ccr
+ ConsoleCommandReceiver* ccr = i->second.front();
+ if (ccr->consoleCommand(command, args) != true) log_warning << "Sent command to registered ccr, but command was unhandled" << std::endl;
+}
+
+bool
+Console::consoleCommand(std::string command, std::vector<std::string> arguments)
+{
+ if (command == "ccrs") {
+ if (arguments.size() != 1) {
+ log_info << "Usage: ccrs <command>" << std::endl;
+ return true;
+ }
+ std::map<std::string, std::list<ConsoleCommandReceiver*> >::iterator i = commands.find(arguments[0]);
+ if ((i == commands.end()) || (i->second.size() == 0)) {
+ log_info << "unknown command: \"" << arguments[0] << "\"" << std::endl;
+ return true;
+ }
+
+ std::ostringstream ccr_list;
+ std::list<ConsoleCommandReceiver*> &ccrs = i->second;
+ std::list<ConsoleCommandReceiver*>::iterator j;
+ for (j = ccrs.begin(); j != ccrs.end(); j++) {
+ if (j != ccrs.begin()) ccr_list << ", ";
+ ccr_list << "[" << *j << "]";
+ }
+
+ log_info << "registered ccrs for \"" << arguments[0] << "\": " << ccr_list.str() << std::endl;
+ return true;
+ }
+
+ return false;