English
Kamil Dudka

TriloBot Simulator (C++, Qt4, Flex, Readline, Boost)

Detail souboru

Jméno:Stáhnoutchat.cc [Stáhnout]
Umístění: rob08 > src
Velikost:5.4 KB
Poslední změna:2022-09-09 13:06

Zdrojový kód

/*
 * 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;
}