/* * Jingle call example * Copyright 2004--2005, Google Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ extern "C" { #include #include #include #include #include } #include #include #include #include #include "talk/examples/call/console.h" namespace { void PError(const char* desc) { perror(desc); exit(1); } CConsole* gConsole = NULL; const uint32 MSG_UPDATE = 1; } // namespace void InitConsole(cricket::PhysicalSocketServer* ss) { assert(gConsole == NULL); assert(ss); gConsole = new CConsole(ss); } CConsole* Console() { assert(gConsole); return gConsole; } CConsole::CConsole(cricket::PhysicalSocketServer* ss) : prompting_(false), prompt_dirty_(false) { stdin_ = ss->CreateFile(0); stdin_->SignalReadEvent.connect(this, &CConsole::OnReadInput); tasks_ = new std::vector; } CConsole::~CConsole() { delete stdin_; delete tasks_; } void CConsole::Push(ConsoleTask* task) { task->set_console(this); task->SignalDone.connect(this, &CConsole::OnTaskDone); tasks_->push_back(task); task->Start(); UpdatePrompt(); } void CConsole::Remove(ConsoleTask* task) { int index = -1; for (size_t i = 0; i < tasks_->size(); ++i) { if ((*tasks_)[i] == task) index = i; } assert(index >= 0); tasks_->erase(tasks_->begin() + index); if (static_cast(tasks_->size()) == index) UpdatePrompt(); delete task; if (tasks_->size() == 0) exit(0); } void CConsole::Print(const char* str) { if (prompting_) printf("\r"); printf("%s\n", str); prompting_ = false; UpdatePrompt(); } void CConsole::Print(const std::string& str) { Print(str.c_str()); } void CConsole::Printf(const char* format, ...) { va_list ap; va_start(ap, format); char buf[4096]; int size = vsnprintf(buf, sizeof(buf), format, ap); assert(size >= 0); assert(size < static_cast(sizeof(buf))); buf[size] = '\0'; Print(buf); va_end(ap); } void CConsole::OnTaskDone(ConsoleTask* task) { Remove(task); } void CConsole::OnReadInput(cricket::AsyncFile* file) { assert(file == stdin_); char buf[4096]; int size = read(0, buf, sizeof(buf)); if (size < 0) PError("read"); prompting_ = (buf[size-1] != '\n'); int start = 0; for (int i = 0; i < size; ++i) { if (buf[i] == '\n') { std::string line = input_; line.append(buf + start, i + 1 - start); input_.clear(); assert(tasks_->size() > 0); tasks_->back()->ProcessLine(line); start = i + 1; } } input_.append(buf + start, size - start); } void CConsole::OnMessage(cricket::Message* pmsg) { assert(pmsg->message_id == MSG_UPDATE); assert(tasks_->size() > 0); if (prompting_) printf("\n"); printf("%s: %s", tasks_->back()->GetPrompt().c_str(), input_.c_str()); fflush(stdout); prompting_ = true; prompt_dirty_ = false; } void CConsole::UpdatePrompt() { if (!prompt_dirty_) { prompt_dirty_ = true; cricket::Thread::Current()->Post(this, MSG_UPDATE); } } void ConsoleTask::ParseLine(const std::string& line, std::vector* words) { assert(line.size() > 0); assert(line[line.size() - 1] == '\n'); int start = -1; int state = 0; for (int index = 0; index <= static_cast(line.size()); ++index) { if (state == 0) { if (!isspace(line[index])) { start = index; state = 1; } } else { assert(state == 1); assert(start >= 0); if (isspace(line[index])) { std::string word(line, start, index - start); words->push_back(word); start = -1; state = 0; } } } }