TriloBot Simulator (C++, Qt4, Flex, Readline, Boost)
File detail
Source code
/*
* Copyright (C) 2008 Kamil Dudka <xdudka00@stud.fit.vutbr.cz>
*
* This file is part of rob08
*
* rob08 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 3 of the License, or
* any later version.
*
* rob08 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 rob08. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "robIO.h"
#include "term.h"
#ifndef BUILDING_DOX
# include <errno.h>
# include <readline/readline.h>
# include <readline/history.h>
# include <signal.h>
# include <sstream>
# include <stdlib.h>
# include <string>
# include <strings.h>
#endif
using namespace StreamDecorator;
using std::string;
/// stty(1) command
static const char *stty = "stty";
/// stty(1) tty init argument
static const char *sttyInitString = "5:4:800004bf:a30:3:1c:7f:15:4:0:1:0:11:13:1a:0:12:f:17:16:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0";
/// timeout per read begin
static const int dtPingTimeout = 1000;
/// timeout per read of char
static const int dtCharTimeout = 100;
/// readline history file
static const char *histFile = ".rob08_terminal_history";
/**
* print application usage in usual way
* @param path path to application
*/
void printUsage(string path) {
std::cout << "Usage: " << path << " PTY_DEVICE" << std::endl;
}
/// write datat to terminal
void termWrite(IWriter *writer, const string &data) {
std::cerr
<< Color(C_YELLOW) << "send: " << Color(C_NO_COLOR)
<< data << std::flush;
writer->writeText(data);
std::cerr << std::endl;
}
/// read data from terminal
bool termRead(ICharReader *reader) {
if (!reader->hasInput(dtPingTimeout))
return false;
std::cerr << Color(C_LIGHT_BLUE) << "recv: " << Color(C_NO_COLOR) << std::flush;
char c;
while (reader->hasInput(dtCharTimeout) && reader->getChar(c))
std::cout << c << std::flush;
std::cerr << std::endl;
return true;
}
int main(int argc, char *argv[]) {
#if CONSOLE_COLOR_OUTPUT
Color::enable(true);
#endif
if (argc != 2) {
// invalid count of arguments
if (argc > 0)
printUsage(argv[0]);
return -1;
}
std::string fileName(argv[1]);
if (fileName == string("--help")) {
// --help
printUsage(argv[0]);
return 0;
}
// open terminal
ITerm *term = TermFactory::createTerm(fileName);
if (!term)
return -1;
// run stty to initialize PTY slave
string initCmd(stty);
initCmd += " -F ";
initCmd += fileName;
initCmd += " ";
initCmd += sttyInitString;
int rc = system(initCmd.c_str());
if (rc)
std::cerr << Error(E_ERROR, fileName, "stty command failed: ") << "system(" << initCmd << ") = " << rc << std::endl;
// determine terminal mode
bool interactiveMode = ttyname(STDIN_FILENO);
if (interactiveMode)
std::cerr << Error(E_NOTE, "terminal", "working in interactive mode") << std::endl;
else
std::cerr << Error(E_NOTE, "terminal", "working in batch mode") << std::endl;
if (interactiveMode) {
// set signal handler
struct sigaction sa;
bzero(&sa, sizeof(sa));
sa.sa_handler = SIG_IGN;
if (0!= sigaction(SIGINT, &sa, NULL))
std::cerr << Error(E_WARNING, argv[0], "can't set SIGINT signal handler to SIG_IGN") << std::endl;
}
// check connection (FIXME: not tested)
if (term->hasInput(0)) {
std::cerr << Error(E_WARNING, fileName, "reading data from input:") << std::flush;
char c;
while (term->hasInput(0) && term->getChar(c))
std::cout << c << std::flush;
std::cerr << std::endl;
}
// ping TriloBot
termWrite(term, "!1GY1");
if (!termRead(term))
std::cerr << Error(E_ERROR, fileName, "no response, TriloBot seems to be dead") << std::endl;
else
std::cerr << std::endl;
if (interactiveMode) {
// interactive mode
read_history(histFile);
std::ostringstream tmp;
tmp << Color(C_LIGHT_GREEN) << "TriloBot" << Color(C_NO_COLOR) << " >>> " << std::flush;
string prompt(tmp.str());
const char *line;
while ((line = readline(prompt.c_str()))) {
if (!*line)
continue;
add_history(line);
termWrite(term, line);
termRead(term);
std::cout << std::endl;
}
std::cout << std::endl;
if (write_history(histFile))
std::cerr << Error(E_WARNING, histFile, "unable to save history, errno = ") << errno << std::endl;
clear_history();
} else {
// batch mode
string line;
while (getline(std::cin, line)) {
termWrite(term, line);
termRead(term);
}
}
// check for lexical errors
bool bErr = false;
if (term -> hasError()) {
bErr = true;
std::cerr << Error(E_NOTE, fileName, "terminal error(s) detected") << std::endl;
}
// destroy objects in reverse order
delete term;
// final application exit code
return bErr ? -1 : 0;
}