mirror of
https://github.com/eddyem/tty_term.git
synced 2026-02-01 04:45:09 +03:00
add input data types (text/raw/hex), TODO: output types & fix \r bug
This commit is contained in:
parent
934cbc04fd
commit
84bfe8b499
4
main.c
4
main.c
@ -29,7 +29,7 @@ static chardevice conndev = {.dev = NULL, .mutex = PTHREAD_MUTEX_INITIALIZER, .n
|
|||||||
|
|
||||||
void signals(int signo){
|
void signals(int signo){
|
||||||
signal(signo, SIG_IGN);
|
signal(signo, SIG_IGN);
|
||||||
closedev(&conndev);
|
closedev();
|
||||||
deinit_ncurses();
|
deinit_ncurses();
|
||||||
deinit_readline();
|
deinit_readline();
|
||||||
DBG("Exit");
|
DBG("Exit");
|
||||||
@ -84,7 +84,7 @@ int main(int argc, char **argv){
|
|||||||
while(1){
|
while(1){
|
||||||
if(0 == pthread_mutex_lock(&conndev.mutex)){
|
if(0 == pthread_mutex_lock(&conndev.mutex)){
|
||||||
int l;
|
int l;
|
||||||
char *buf = ReadData(&conndev, &l);
|
char *buf = ReadData(&l);
|
||||||
if(buf && l > 0){
|
if(buf && l > 0){
|
||||||
char *eol = NULL, *estr = buf + l;
|
char *eol = NULL, *estr = buf + l;
|
||||||
do{
|
do{
|
||||||
|
|||||||
@ -26,7 +26,6 @@
|
|||||||
#include <readline/history.h>
|
#include <readline/history.h>
|
||||||
#include <readline/readline.h>
|
#include <readline/readline.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -34,11 +33,14 @@
|
|||||||
#include "dbg.h"
|
#include "dbg.h"
|
||||||
#include "ttysocket.h"
|
#include "ttysocket.h"
|
||||||
#include "ncurses_and_readline.h"
|
#include "ncurses_and_readline.h"
|
||||||
|
#include "popup_msg.h"
|
||||||
|
#include "string_functions.h"
|
||||||
|
|
||||||
enum { // using colors
|
enum { // using colors
|
||||||
BKG_NO = 1,
|
BKG_NO = 1,
|
||||||
NORMAL_NO = 2,
|
BKGMARKED_NO = 2,
|
||||||
MARKED_NO = 3
|
NORMAL_NO = 3,
|
||||||
|
MARKED_NO = 4
|
||||||
};
|
};
|
||||||
#define COLOR(x) COLOR_PAIR(x ## _NO)
|
#define COLOR(x) COLOR_PAIR(x ## _NO)
|
||||||
|
|
||||||
@ -48,6 +50,10 @@ static bool visual_mode = false;
|
|||||||
static bool insert_mode = true;
|
static bool insert_mode = true;
|
||||||
static bool should_exit = false;
|
static bool should_exit = false;
|
||||||
|
|
||||||
|
static disptype disp_type = DISP_TEXT; // type of displaying data
|
||||||
|
static disptype input_type = DISP_TEXT; // parsing type of input data
|
||||||
|
const char *dispnames[] = {"TEXT", "RAW", "HEX"};
|
||||||
|
|
||||||
static chardevice *dtty = NULL;
|
static chardevice *dtty = NULL;
|
||||||
|
|
||||||
static void fail_exit(const char *msg){
|
static void fail_exit(const char *msg){
|
||||||
@ -94,26 +100,54 @@ static void forward_to_readline(char c){
|
|||||||
rl_callback_read_char();
|
rl_callback_read_char();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// functions to modify output data
|
||||||
|
static char *text_putchar(char *next){
|
||||||
|
char c = *next++;
|
||||||
|
DBG("put 0x%02X (%c)", c, c);
|
||||||
|
if(c < 31 || c > 126){
|
||||||
|
wattron(msg_win, COLOR(MARKED));
|
||||||
|
//waddch(msg_win, c);
|
||||||
|
wprintw(msg_win, "%02X", (uint8_t)c);
|
||||||
|
wattroff(msg_win, COLOR(MARKED));
|
||||||
|
}else{
|
||||||
|
//wprintw(msg_win, "%c" COLOR_GREEN "green" COLOR_RED "red" COLOR_OLD, c);
|
||||||
|
waddch(msg_win, c);
|
||||||
|
}
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
static char *raw_putchar(char *next){
|
||||||
|
waddch(msg_win, *next);
|
||||||
|
return next+1;
|
||||||
|
}
|
||||||
|
static char *hex_putchar(char *next){
|
||||||
|
waddch(msg_win, *next);
|
||||||
|
return next+1;
|
||||||
|
}
|
||||||
|
|
||||||
static void msg_win_redisplay(bool for_resize){
|
static void msg_win_redisplay(bool for_resize){
|
||||||
werase(msg_win);
|
werase(msg_win);
|
||||||
Line *l = firstline;
|
Line *l = firstline;
|
||||||
static char *buf = NULL;
|
//static char *buf = NULL;
|
||||||
int nlines = 0; // total amount of lines @ output
|
int nlines = 0; // total amount of lines @ output
|
||||||
for(; l && (nlines < LINES - 2); l = l->next){
|
int linemax = LINES - 2;
|
||||||
|
char *(*putfn)(char *);
|
||||||
|
switch(disp_type){
|
||||||
|
case DISP_RAW:
|
||||||
|
putfn = raw_putchar;
|
||||||
|
break;
|
||||||
|
case DISP_HEX:
|
||||||
|
putfn = hex_putchar;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
putfn = text_putchar;
|
||||||
|
}
|
||||||
|
for(; l && (nlines < linemax); l = l->next){
|
||||||
wmove(msg_win, nlines, 0);
|
wmove(msg_win, nlines, 0);
|
||||||
size_t contlen = strlen(l->contents) + 128;
|
//size_t contlen = strlen(l->contents) + 128;
|
||||||
buf = realloc(buf, contlen);
|
//buf = realloc(buf, contlen);
|
||||||
int sz = strlen(l->contents);
|
|
||||||
char *ptr = l->contents;
|
char *ptr = l->contents;
|
||||||
for(int i = 0; i < sz; ++i, ++ptr){
|
while((ptr = putfn(ptr)) && *ptr && nlines < linemax){
|
||||||
char c = *ptr;
|
nlines = msg_win->_cury;
|
||||||
if(c <'a' || c > 'z'){
|
|
||||||
wattron(msg_win, COLOR(MARKED));
|
|
||||||
waddch(msg_win, c);
|
|
||||||
wattroff(msg_win, COLOR(MARKED));
|
|
||||||
}else{
|
|
||||||
waddch(msg_win, c);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
++nlines;
|
++nlines;
|
||||||
}
|
}
|
||||||
@ -122,7 +156,7 @@ static void msg_win_redisplay(bool for_resize){
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void cmd_win_redisplay(bool for_resize){
|
static void cmd_win_redisplay(bool for_resize){
|
||||||
int cursor_col = 2 + rl_point; // "> " width is 2
|
int cursor_col = 3 + strlen(dispnames[input_type]) + rl_point; // " > " width is 3
|
||||||
werase(cmd_win);
|
werase(cmd_win);
|
||||||
int x = 0, maxw = COLS-2;
|
int x = 0, maxw = COLS-2;
|
||||||
if(cursor_col > maxw){
|
if(cursor_col > maxw){
|
||||||
@ -130,7 +164,7 @@ static void cmd_win_redisplay(bool for_resize){
|
|||||||
cursor_col = maxw;
|
cursor_col = maxw;
|
||||||
}
|
}
|
||||||
char abuf[4096];
|
char abuf[4096];
|
||||||
snprintf(abuf, 4096, "> %s", rl_line_buffer);
|
snprintf(abuf, 4096, "%s > %s", dispnames[input_type], rl_line_buffer);
|
||||||
waddstr(cmd_win, abuf+x);
|
waddstr(cmd_win, abuf+x);
|
||||||
wmove(cmd_win, 0, cursor_col);
|
wmove(cmd_win, 0, cursor_col);
|
||||||
if(for_resize) wnoutrefresh(cmd_win);
|
if(for_resize) wnoutrefresh(cmd_win);
|
||||||
@ -145,26 +179,27 @@ static void readline_redisplay(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void show_mode(bool for_resize){
|
static void show_mode(bool for_resize){
|
||||||
|
static const char *insmodetext = "INSERT (F1 - help)";
|
||||||
wclear(sep_win);
|
wclear(sep_win);
|
||||||
char buf[128];
|
char buf[128];
|
||||||
if(insert_mode){
|
if(insert_mode){
|
||||||
if(dtty){
|
if(dtty){
|
||||||
switch(dtty->type){
|
switch(dtty->type){
|
||||||
case DEV_NETSOCKET:
|
case DEV_NETSOCKET:
|
||||||
snprintf(buf, 127, "INSERT (TAB to switch, ctrl+D to quit) HOST: %s, ENDLINE: %s, PORT: %s",
|
snprintf(buf, 127, "%s HOST: %s, ENDLINE: %s, PORT: %s",
|
||||||
dtty->name, dtty->seol, dtty->port);
|
insmodetext, dtty->name, dtty->seol, dtty->port);
|
||||||
break;
|
break;
|
||||||
case DEV_UNIXSOCKET:
|
case DEV_UNIXSOCKET:
|
||||||
if(*dtty->name)
|
if(*dtty->name)
|
||||||
snprintf(buf, 127, "INSERT (TAB to switch, ctrl+D to quit) PATH: %s, ENDLINE: %s",
|
snprintf(buf, 127, "%s PATH: %s, ENDLINE: %s",
|
||||||
dtty->name, dtty->seol);
|
insmodetext, dtty->name, dtty->seol);
|
||||||
else // name starting from \0
|
else // name starting from \0
|
||||||
snprintf(buf, 127, "INSERT (TAB to switch, ctrl+D to quit) PATH: \\0%s, ENDLINE: %s",
|
snprintf(buf, 127, "%s PATH: \\0%s, ENDLINE: %s",
|
||||||
dtty->name+1, dtty->seol);
|
insmodetext, dtty->name+1, dtty->seol);
|
||||||
break;
|
break;
|
||||||
case DEV_TTY:
|
case DEV_TTY:
|
||||||
snprintf(buf, 127, "INSERT (TAB to switch, ctrl+D to quit) DEV: %s, ENDLINE: %s, SPEED: %d, FORMAT: %s",
|
snprintf(buf, 127, "%s DEV: %s, ENDLINE: %s, SPEED: %d, FORMAT: %s",
|
||||||
dtty->name, dtty->seol, dtty->speed, dtty->port);
|
insmodetext, dtty->name, dtty->seol, dtty->speed, dtty->port);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -172,8 +207,11 @@ static void show_mode(bool for_resize){
|
|||||||
snprintf(buf, 127, "INSERT (TAB to switch, ctrl+D to quit) NOT INITIALIZED");
|
snprintf(buf, 127, "INSERT (TAB to switch, ctrl+D to quit) NOT INITIALIZED");
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
snprintf(buf, 127, "SCROLL (TAB to switch, q to quit) ENDLINE: %s", dtty?dtty->seol:"n");
|
snprintf(buf, 127, "SCROLL (F1 - help) ENDLINE: %s", dtty?dtty->seol:"n");
|
||||||
}
|
}
|
||||||
|
wattron(sep_win, COLOR(BKGMARKED));
|
||||||
|
wprintw(sep_win, "%s ", dispnames[disp_type]);
|
||||||
|
wattroff(sep_win, COLOR(BKGMARKED));
|
||||||
wprintw(sep_win, "%s", buf);
|
wprintw(sep_win, "%s", buf);
|
||||||
if(for_resize) wnoutrefresh(sep_win);
|
if(for_resize) wnoutrefresh(sep_win);
|
||||||
else wrefresh(sep_win);
|
else wrefresh(sep_win);
|
||||||
@ -253,6 +291,7 @@ void init_ncurses(){
|
|||||||
fail_exit("Failed to allocate windows");
|
fail_exit("Failed to allocate windows");
|
||||||
if(has_colors()){
|
if(has_colors()){
|
||||||
init_pair(BKG_NO, COLOR_WHITE, COLOR_BLUE);
|
init_pair(BKG_NO, COLOR_WHITE, COLOR_BLUE);
|
||||||
|
init_pair(BKGMARKED_NO, 1, COLOR_BLUE); // COLOR_RED used in my usefull_macros
|
||||||
init_pair(NORMAL_NO, COLOR_WHITE, COLOR_BLACK);
|
init_pair(NORMAL_NO, COLOR_WHITE, COLOR_BLACK);
|
||||||
init_pair(MARKED_NO, COLOR_CYAN, COLOR_BLACK);
|
init_pair(MARKED_NO, COLOR_CYAN, COLOR_BLACK);
|
||||||
wbkgd(sep_win, COLOR(BKG));
|
wbkgd(sep_win, COLOR(BKG));
|
||||||
@ -271,16 +310,18 @@ void deinit_ncurses(){
|
|||||||
endwin();
|
endwin();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char *previous_line = NULL; // previous line in readline input
|
||||||
static void got_command(char *line){
|
static void got_command(char *line){
|
||||||
if(!line) // Ctrl-D pressed on empty line
|
if(!line) // Ctrl-D pressed on empty line
|
||||||
should_exit = true;
|
should_exit = true;
|
||||||
else{
|
else{
|
||||||
if(!*line) return; // zero length
|
if(!*line) return; // zero length
|
||||||
add_history(line);
|
if(!previous_line || strcmp(previous_line, line)) add_history(line); // omit repeats
|
||||||
if(SendData(dtty, line) == -1){
|
FREE(previous_line);
|
||||||
|
if(convert_and_send(input_type, line) == -1){
|
||||||
ERRX("Device disconnected");
|
ERRX("Device disconnected");
|
||||||
}
|
}
|
||||||
FREE(line);
|
previous_line = line;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -293,7 +334,22 @@ void init_readline(){
|
|||||||
rl_getc_function = readline_getc;
|
rl_getc_function = readline_getc;
|
||||||
rl_input_available_hook = readline_input_avail;
|
rl_input_available_hook = readline_input_avail;
|
||||||
rl_redisplay_function = readline_redisplay;
|
rl_redisplay_function = readline_redisplay;
|
||||||
rl_callback_handler_install("> ", got_command);
|
rl_callback_handler_install("", got_command);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief change_disp - change input or output data types (text/raw/hex)
|
||||||
|
* @param in, out - types for input and display
|
||||||
|
*/
|
||||||
|
static void change_disp(disptype in, disptype out){
|
||||||
|
if(in >= DISP_TEXT && in < DISP_UNCHANGED){
|
||||||
|
input_type = in;
|
||||||
|
DBG("input -> %s", dispnames[in]);
|
||||||
|
}
|
||||||
|
if(out >= DISP_TEXT && out < DISP_UNCHANGED){
|
||||||
|
disp_type = out;
|
||||||
|
}
|
||||||
|
show_mode(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void deinit_readline(){
|
void deinit_readline(){
|
||||||
@ -318,6 +374,33 @@ static void rollup(){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *help[] = {
|
||||||
|
"Common commands:",
|
||||||
|
" F1 - show this help",
|
||||||
|
" F2 - text mode",
|
||||||
|
" F3 - raw mode (all symbols in hex codes)",
|
||||||
|
" F4 - hexdump mode (like hexdump output)",
|
||||||
|
" mouse scroll - scroll text output",
|
||||||
|
" q,^c,^d - quit",
|
||||||
|
" TAB - switch between scroll and edit modes",
|
||||||
|
" to change display/input (text/raw/hex) press Fx when scroll/edit",
|
||||||
|
" in scroll mode keys are almost the same like for this help"
|
||||||
|
" Text mode: in input and output all special symbols are like \\code",
|
||||||
|
" Raw mode: output only in hex, input in dec, 0xhex, 0bbin, 0oct (space separated)",
|
||||||
|
" Hexdump mode: output like hexdump, input only hex (with or without spaces)",
|
||||||
|
"",
|
||||||
|
"This help:",
|
||||||
|
" ^p,<Up> - scroll the viewport up by one row",
|
||||||
|
" ^n,<Down> - scroll the viewport down by one row",
|
||||||
|
" ^l,<Left> - scroll the viewport left by one column",
|
||||||
|
" ^r,<Right> - scroll the viewport right by one column",
|
||||||
|
" h,<Home> - scroll the viewport to top of file",
|
||||||
|
" ^F,<PageDn> - scroll to the next page",
|
||||||
|
" ^B,<PageUp> - scroll to the previous page",
|
||||||
|
" e,<End> - scroll the viewport to end of file",
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief cmdline - console reading process; runs as separate thread
|
* @brief cmdline - console reading process; runs as separate thread
|
||||||
* @param arg - tty/socket device to write strings entered by user
|
* @param arg - tty/socket device to write strings entered by user
|
||||||
@ -331,7 +414,24 @@ void *cmdline(void* arg){
|
|||||||
int c = wgetch(cmd_win);
|
int c = wgetch(cmd_win);
|
||||||
bool processed = true;
|
bool processed = true;
|
||||||
//DBG("wgetch got %d", c);
|
//DBG("wgetch got %d", c);
|
||||||
|
disptype dt = DISP_UNCHANGED;
|
||||||
switch(c){ // common keys for both modes
|
switch(c){ // common keys for both modes
|
||||||
|
case KEY_F(1): // help
|
||||||
|
DBG("\n\nASK for help\n\n");
|
||||||
|
popup_msg(msg_win, help);
|
||||||
|
break;
|
||||||
|
case KEY_F(2): // TEXT mode
|
||||||
|
DBG("\n\nIN TEXT mode\n\n");
|
||||||
|
dt = DISP_TEXT;
|
||||||
|
break;
|
||||||
|
case KEY_F(3): // RAW mode
|
||||||
|
DBG("\n\nIN RAW mode\n\n");
|
||||||
|
dt = DISP_RAW;
|
||||||
|
break;
|
||||||
|
case KEY_F(4): // HEX mode
|
||||||
|
DBG("\n\nIN HEX mode\n\n");
|
||||||
|
dt = DISP_HEX;
|
||||||
|
break;
|
||||||
case KEY_MOUSE:
|
case KEY_MOUSE:
|
||||||
if(getmouse(&event) == OK){
|
if(getmouse(&event) == OK){
|
||||||
if(event.bstate & (BUTTON4_PRESSED)) rolldown(); // wheel up
|
if(event.bstate & (BUTTON4_PRESSED)) rolldown(); // wheel up
|
||||||
@ -348,6 +448,10 @@ void *cmdline(void* arg){
|
|||||||
default:
|
default:
|
||||||
processed = false;
|
processed = false;
|
||||||
}
|
}
|
||||||
|
if(dt != DISP_UNCHANGED){
|
||||||
|
if(insert_mode) change_disp(dt, DISP_UNCHANGED);
|
||||||
|
else change_disp(DISP_UNCHANGED, dt);
|
||||||
|
}
|
||||||
if(processed) continue;
|
if(processed) continue;
|
||||||
if(insert_mode){
|
if(insert_mode){
|
||||||
DBG("forward_to_readline(%d)", c);
|
DBG("forward_to_readline(%d)", c);
|
||||||
@ -396,7 +500,7 @@ void *cmdline(void* arg){
|
|||||||
while(*ptr) forward_to_readline(*ptr++);
|
while(*ptr) forward_to_readline(*ptr++);
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
switch(c){
|
switch(c){ // TODO: add home/end
|
||||||
case KEY_UP: // roll down for one item
|
case KEY_UP: // roll down for one item
|
||||||
rolldown();
|
rolldown();
|
||||||
break;
|
break;
|
||||||
|
|||||||
@ -22,6 +22,13 @@
|
|||||||
#include "dbg.h"
|
#include "dbg.h"
|
||||||
#include "ttysocket.h"
|
#include "ttysocket.h"
|
||||||
|
|
||||||
|
typedef enum{ // display/input data as
|
||||||
|
DISP_TEXT, // text (non-ASCII input and output as \xxx)
|
||||||
|
DISP_RAW, // hex output as xx xx xx, input in as numbers in bin (0bxx), oct(0xx), hex (0xxx||0Xxx) or dec and letters
|
||||||
|
DISP_HEX, // hexdump output, input in hex only (with or without spaces)
|
||||||
|
DISP_UNCHANGED // old
|
||||||
|
} disptype;
|
||||||
|
|
||||||
void init_readline();
|
void init_readline();
|
||||||
void deinit_readline();
|
void deinit_readline();
|
||||||
void init_ncurses();
|
void init_ncurses();
|
||||||
|
|||||||
187
popup_msg.c
Normal file
187
popup_msg.c
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the ttyterm project.
|
||||||
|
* Copyright 2023 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||||
|
*
|
||||||
|
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Copyright 2018-2020,2021 Thomas E. Dickey *
|
||||||
|
* Copyright 2017 Free Software Foundation, Inc. *
|
||||||
|
* *
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a *
|
||||||
|
* copy of this software and associated documentation files (the *
|
||||||
|
* "Software"), to deal in the Software without restriction, including *
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish, *
|
||||||
|
* distribute, distribute with modifications, sublicense, and/or sell *
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is *
|
||||||
|
* furnished to do so, subject to the following conditions: *
|
||||||
|
* *
|
||||||
|
* The above copyright notice and this permission notice shall be included *
|
||||||
|
* in all copies or substantial portions of the Software. *
|
||||||
|
* *
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
|
||||||
|
* IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
|
||||||
|
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
|
||||||
|
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
|
||||||
|
* THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||||
|
* *
|
||||||
|
* Except as contained in this notice, the name(s) of the above copyright *
|
||||||
|
* holders shall not be used in advertising or otherwise to promote the *
|
||||||
|
* sale, use or other dealings in this Software without prior written *
|
||||||
|
* authorization. *
|
||||||
|
****************************************************************************/
|
||||||
|
/*
|
||||||
|
* $Id: popup_msg.c,v 1.11 2021/12/18 21:19:19 tom Exp $
|
||||||
|
*
|
||||||
|
* Show a multi-line message in a window which may extend beyond the screen.
|
||||||
|
*
|
||||||
|
* Thomas Dickey - 2017/4/15.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "dbg.h"
|
||||||
|
#include "popup_msg.h"
|
||||||
|
|
||||||
|
static WINDOW *old_window;
|
||||||
|
|
||||||
|
static void begin_popup(void){
|
||||||
|
doupdate();
|
||||||
|
old_window = dupwin(curscr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void end_popup(void){
|
||||||
|
touchwin(old_window);
|
||||||
|
wnoutrefresh(old_window);
|
||||||
|
doupdate();
|
||||||
|
delwin(old_window);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Display a temporary window, e.g., to display a help-message.
|
||||||
|
*/
|
||||||
|
void popup_msg(WINDOW *parent, const char *const *msg){
|
||||||
|
int x0 = 4;
|
||||||
|
int y0 = 2;
|
||||||
|
int y1 = 0, x1 = 0;
|
||||||
|
int y2 = 0;
|
||||||
|
int wide = getmaxx(parent) - ((x0 + 1) * 2);
|
||||||
|
int high = getmaxy(parent) - ((y0 + 1) * 2);
|
||||||
|
WINDOW *help;
|
||||||
|
WINDOW *data;
|
||||||
|
int n;
|
||||||
|
int width = 0;
|
||||||
|
int length;
|
||||||
|
int last_y, last_x;
|
||||||
|
int ch = ERR;
|
||||||
|
|
||||||
|
for (n = 0; msg[n] != 0; ++n) {
|
||||||
|
int check = (int) strlen(msg[n]);
|
||||||
|
if (width < check) width = check;
|
||||||
|
}
|
||||||
|
length = n;
|
||||||
|
last_x = width - wide + 4;
|
||||||
|
|
||||||
|
if ((help = newwin(high, wide, y0, x0)) == 0)
|
||||||
|
return;
|
||||||
|
if ((data = newpad(length + 1, width + 1)) == 0) {
|
||||||
|
delwin(help);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
begin_popup();
|
||||||
|
|
||||||
|
keypad(data, TRUE);
|
||||||
|
|
||||||
|
for (n = 0; n < length; ++n){
|
||||||
|
waddstr(data, msg[n]);
|
||||||
|
if ((n + 1) < length) waddch(data, '\n');
|
||||||
|
}
|
||||||
|
y2 = getcury(data);
|
||||||
|
last_y = (y2 - (high - 3));
|
||||||
|
|
||||||
|
do{
|
||||||
|
switch (ch){
|
||||||
|
case KEY_HOME:
|
||||||
|
y1 = 0;
|
||||||
|
break;
|
||||||
|
case KEY_END:
|
||||||
|
y1 = last_y;
|
||||||
|
break;
|
||||||
|
case KEY_PREVIOUS:
|
||||||
|
case KEY_PPAGE:
|
||||||
|
if (y1 > 0) {
|
||||||
|
y1 -= high / 2;
|
||||||
|
if (y1 < 0)
|
||||||
|
y1 = 0;
|
||||||
|
} else {
|
||||||
|
beep();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case KEY_NEXT:
|
||||||
|
case KEY_NPAGE:
|
||||||
|
if (y1 < last_y) {
|
||||||
|
y1 += high / 2;
|
||||||
|
if (y1 > last_y)
|
||||||
|
y1 = last_y;
|
||||||
|
} else {
|
||||||
|
beep();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CTRL('P'):
|
||||||
|
case KEY_UP:
|
||||||
|
if (y1 > 0)
|
||||||
|
--y1;
|
||||||
|
else
|
||||||
|
beep();
|
||||||
|
break;
|
||||||
|
case CTRL('N'):
|
||||||
|
case KEY_DOWN:
|
||||||
|
if (y1 < last_y)
|
||||||
|
++y1;
|
||||||
|
else
|
||||||
|
beep();
|
||||||
|
break;
|
||||||
|
case CTRL('L'):
|
||||||
|
case KEY_LEFT:
|
||||||
|
if(x1 > 0) --x1;
|
||||||
|
else beep();
|
||||||
|
break;
|
||||||
|
case CTRL('R'):
|
||||||
|
case KEY_RIGHT:
|
||||||
|
if(x1 < last_x) ++x1;
|
||||||
|
else beep();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
beep();
|
||||||
|
break;
|
||||||
|
case ERR:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
werase(help);
|
||||||
|
box(help, 0, 0);
|
||||||
|
wnoutrefresh(help);
|
||||||
|
pnoutrefresh(data, y1, x1, y0 + 1, x0 + 1, high, wide);
|
||||||
|
doupdate();
|
||||||
|
} while ((ch = wgetch(data)) != ERR && ch != QUIT && ch != ESCAPE);
|
||||||
|
werase(help);
|
||||||
|
wrefresh(help);
|
||||||
|
delwin(help);
|
||||||
|
delwin(data);
|
||||||
|
|
||||||
|
end_popup();
|
||||||
|
}
|
||||||
25
popup_msg.h
Normal file
25
popup_msg.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the ttyterm project.
|
||||||
|
* Copyright 2023 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||||
|
*
|
||||||
|
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <curses.h>
|
||||||
|
|
||||||
|
#define QUIT CTRL('Q')
|
||||||
|
#define ESCAPE CTRL('[')
|
||||||
|
|
||||||
|
void popup_msg(WINDOW *parent, const char *const *msg);
|
||||||
220
string_functions.c
Normal file
220
string_functions.c
Normal file
@ -0,0 +1,220 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the ttyterm project.
|
||||||
|
* Copyright 2023 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||||
|
*
|
||||||
|
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "string_functions.h"
|
||||||
|
|
||||||
|
// read text string and throw out all < 31 and > 126
|
||||||
|
static inline const char *omit_nonletters(const char *line){
|
||||||
|
while(*line){
|
||||||
|
char c = *line;
|
||||||
|
if(c > 31 && c < 127) break;
|
||||||
|
++line;
|
||||||
|
}
|
||||||
|
return line;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return hex of given sybol (0..9, a..f or A..F) or -1
|
||||||
|
static inline int hex2i(char c){
|
||||||
|
if(c >= '0' && c <= '9') return c - '0';
|
||||||
|
else if(c >= 'A' && c <= 'F') return c - 'A' + 10;
|
||||||
|
else if(c >= 'a' && c <= 'f') return c - 'a' + 10;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline const char *getbin(const char *line, int *ch){
|
||||||
|
char c = *line;
|
||||||
|
if(c < '0' || c > '1'){
|
||||||
|
*ch = -1;
|
||||||
|
return line+1;
|
||||||
|
}
|
||||||
|
int num = 0, ctr = 8;
|
||||||
|
do{
|
||||||
|
if(--ctr < 0) break; // nineth symbol
|
||||||
|
if(c < '0' || c > '1'){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
num <<= 1;
|
||||||
|
if(c == '1') num |= 1;
|
||||||
|
++line;
|
||||||
|
}while((c = *line));
|
||||||
|
*ch = num < 256 ? num : -1;
|
||||||
|
return line;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief getoct read octal number without first '0' (up to three symbols)
|
||||||
|
* @param line - pointer to string
|
||||||
|
* @param ch - data read (or -1 if error)
|
||||||
|
* @return pointer to next symbol after this (or first incorrect symbol)
|
||||||
|
*/
|
||||||
|
static inline const char *getoct(const char *line, int *ch){
|
||||||
|
char c = *line;
|
||||||
|
if(c < '0' || c > '7'){
|
||||||
|
*ch = -1;
|
||||||
|
return line+1;
|
||||||
|
}
|
||||||
|
int num = 0, ctr = 3;
|
||||||
|
do{
|
||||||
|
if(--ctr < 0) break; // fourth symbol
|
||||||
|
if(c < '0' || c > '7'){ // other symbol
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
num <<= 3;
|
||||||
|
num += c - '0';
|
||||||
|
++line;
|
||||||
|
}while((c = *line));
|
||||||
|
*ch = num < 256 ? num : -1;
|
||||||
|
return line;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline const char *getdec(const char *line, int *ch){
|
||||||
|
char c = *line;
|
||||||
|
if(c < '0' || c > '9'){
|
||||||
|
*ch = -1;
|
||||||
|
return line+1;
|
||||||
|
}
|
||||||
|
int num = 0, ctr = 3;
|
||||||
|
do{
|
||||||
|
if(--ctr < 0) break; // fourth symbol
|
||||||
|
if(c < '0' || c > '9'){ // other symbol
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
num *= 10;
|
||||||
|
num += c - '0';
|
||||||
|
++line;
|
||||||
|
}while((c = *line));
|
||||||
|
*ch = num < 256 ? num : -1;
|
||||||
|
return line;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief gethex - read hex number without first '\x'
|
||||||
|
* @param line - pointer to string
|
||||||
|
* @param ch - data read (or -1 if error)
|
||||||
|
* @return pointer to next symbol after hex number (x or xx)
|
||||||
|
*/
|
||||||
|
static inline const char *gethex(const char *line, int *ch){
|
||||||
|
int i = hex2i(*line++);
|
||||||
|
if(i > -1){
|
||||||
|
int j = hex2i(*line);
|
||||||
|
if(j > -1){
|
||||||
|
i = (i<<4) | j;
|
||||||
|
++line;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*ch = i;
|
||||||
|
return line;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief getspec - get special symbol (after '\') (without unicode support!)
|
||||||
|
* @param line - pointer to string
|
||||||
|
* @param ch - data read (or -1 if error)
|
||||||
|
* @return pointer to next symbol after this
|
||||||
|
*/
|
||||||
|
static inline const char *getspec(const char *line, int *ch){
|
||||||
|
if(!*line){ *ch = -1; return line; }
|
||||||
|
int got = -1, s = *line++; // next symbol after '\'
|
||||||
|
if(s >= '0' && s <= '7'){ // octal symbol
|
||||||
|
line = getoct(line-1, &got);
|
||||||
|
}else switch(s){
|
||||||
|
case 'a': got = '\a'; break;
|
||||||
|
case 'b': got = '\b'; break;
|
||||||
|
case 'e': got = '\e'; break;
|
||||||
|
case 'f': got = '\f'; break;
|
||||||
|
case 'n': got = '\n'; break;
|
||||||
|
case 'r': got = '\r'; break;
|
||||||
|
case 't': got = '\t'; break;
|
||||||
|
case 'v': got = '\v'; break;
|
||||||
|
case 'x': line = gethex(line, &got); break; // hex symbol
|
||||||
|
default:// return "as is" all other printable symbols
|
||||||
|
if(s > 31 && s < 127) got = s;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*ch = got;
|
||||||
|
return line;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief convert_and_send - convert input line and send it (in text mode add `eol`)
|
||||||
|
* @param line - line with data
|
||||||
|
* @return amount of bytes sent, 0 if error or -1 if disconnect
|
||||||
|
*/
|
||||||
|
int convert_and_send(disptype input_type, const char *line){
|
||||||
|
static char *buf = NULL;
|
||||||
|
static size_t bufsiz = 0;
|
||||||
|
size_t curpos = 0; // position in `buf`
|
||||||
|
line = omit_nonletters(line);
|
||||||
|
while(*line){
|
||||||
|
if(curpos >= bufsiz){ // out ouptut buffer can't be larger than input
|
||||||
|
bufsiz += BUFSIZ;
|
||||||
|
buf = realloc(buf, bufsiz);
|
||||||
|
}
|
||||||
|
int ch = -1;
|
||||||
|
switch(input_type){
|
||||||
|
case DISP_TEXT: // only check for '\'
|
||||||
|
ch = *line++;
|
||||||
|
if(ch == '\\') line = getspec(line, &ch);
|
||||||
|
break;
|
||||||
|
case DISP_RAW: // read next uint8_t and put into buffer
|
||||||
|
ch = *line++;
|
||||||
|
if(ch == '0'){ // number: 0, 0xHH, 0OOO, 0bBBBBBBBB
|
||||||
|
ch = *line;
|
||||||
|
switch(ch){
|
||||||
|
case 'x': // hexadecimal
|
||||||
|
case 'X':
|
||||||
|
line = gethex(line + 1, &ch);
|
||||||
|
break;
|
||||||
|
case 'b':
|
||||||
|
case 'B':
|
||||||
|
line = getbin(line + 1, &ch);
|
||||||
|
break;
|
||||||
|
default: // zero or octal
|
||||||
|
if(ch >= '0' && ch <= '7') line = getoct(line, &ch);
|
||||||
|
else ch = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}else if(ch > '0' && ch <= '9'){ // decimal number
|
||||||
|
line = getdec(line-1, &ch);
|
||||||
|
} // else - letter (without escape-symbols!)
|
||||||
|
break;
|
||||||
|
case DISP_HEX: // read next 2 hex bytes and put into buffer
|
||||||
|
line = gethex(line, &ch);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return 0; // unknown display type
|
||||||
|
}
|
||||||
|
if(ch > -1) buf[curpos++] = ch;
|
||||||
|
line = omit_nonletters(line);
|
||||||
|
}
|
||||||
|
// now insert EOL in text mode
|
||||||
|
if(input_type == DISP_TEXT){
|
||||||
|
if(curpos+2 >= bufsiz){
|
||||||
|
bufsiz += BUFSIZ;
|
||||||
|
buf = realloc(buf, bufsiz);
|
||||||
|
}
|
||||||
|
int l; char *e = geteol(&l);
|
||||||
|
snprintf(buf+curpos, l, "%s", e);
|
||||||
|
curpos += l;
|
||||||
|
}
|
||||||
|
return SendData(buf, curpos);
|
||||||
|
}
|
||||||
23
string_functions.h
Normal file
23
string_functions.h
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the ttyterm project.
|
||||||
|
* Copyright 2023 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||||
|
*
|
||||||
|
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ncurses_and_readline.h"
|
||||||
|
|
||||||
|
int convert_and_send(disptype input_type, const char *line);
|
||||||
179
ttysocket.c
179
ttysocket.c
@ -33,6 +33,8 @@
|
|||||||
|
|
||||||
static int sec = 0, usec = 100; // timeout
|
static int sec = 0, usec = 100; // timeout
|
||||||
static FILE *dupfile = NULL; // file for output
|
static FILE *dupfile = NULL; // file for output
|
||||||
|
static chardevice *device = NULL; // current opened device
|
||||||
|
|
||||||
// TODO: if unix socket name starts with \0 translate it as \\0 to d->name!
|
// TODO: if unix socket name starts with \0 translate it as \\0 to d->name!
|
||||||
|
|
||||||
// set Read_tty timeout in milliseconds
|
// set Read_tty timeout in milliseconds
|
||||||
@ -76,31 +78,31 @@ static int waittoread(int fd){
|
|||||||
}
|
}
|
||||||
|
|
||||||
// substitute all EOL's by '\n'
|
// substitute all EOL's by '\n'
|
||||||
static size_t rmeols(chardevice *d){
|
static size_t rmeols(){
|
||||||
if(!d){
|
if(!device){
|
||||||
DBG("d is NULL");
|
DBG("d is NULL");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
TTY_descr2 *D = d->dev;
|
TTY_descr2 *D = device->dev;
|
||||||
if(!D || D->comfd < 0){
|
if(!D || D->comfd < 0){
|
||||||
DBG("D bad");
|
DBG("D bad");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if(0 == strcmp(d->eol, "\n")){
|
if(0 == strcmp(device->eol, "\n")){
|
||||||
DBG("No subs need");
|
DBG("No subs need");
|
||||||
return D->buflen; // don't need to do this
|
return D->buflen; // don't need to do this
|
||||||
}
|
}
|
||||||
int L = strlen(D->buf);
|
int L = strlen(D->buf);
|
||||||
char *newbuf = MALLOC(char, L), *ptr = D->buf, *eptr = D->buf + L;
|
char *newbuf = MALLOC(char, L), *ptr = D->buf, *eptr = D->buf + L;
|
||||||
while(ptr < eptr){
|
while(ptr < eptr){
|
||||||
char *eol = strstr(ptr, d->eol);
|
char *eol = strstr(ptr, device->eol);
|
||||||
if(eol){
|
if(eol){
|
||||||
eol[0] = '\n';
|
eol[0] = '\n';
|
||||||
eol[1] = 0;
|
eol[1] = 0;
|
||||||
}
|
}
|
||||||
strcat(newbuf, ptr);
|
strcat(newbuf, ptr);
|
||||||
if(!eol) break;
|
if(!eol) break;
|
||||||
ptr = eol + d->eollen;
|
ptr = eol + device->eollen;
|
||||||
}
|
}
|
||||||
strcpy(D->buf, newbuf);
|
strcpy(D->buf, newbuf);
|
||||||
FREE(newbuf);
|
FREE(newbuf);
|
||||||
@ -108,10 +110,16 @@ static size_t rmeols(chardevice *d){
|
|||||||
return D->buflen;
|
return D->buflen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *geteol(int *s){
|
||||||
|
if(!device) return NULL;
|
||||||
|
*s = device->eollen;
|
||||||
|
return device->eol;
|
||||||
|
}
|
||||||
|
|
||||||
// get data drom TTY
|
// get data drom TTY
|
||||||
static char *getttydata(chardevice *d, int *len){
|
static char *getttydata(int *len){
|
||||||
if(!d || !d->dev) return NULL;
|
if(!device || !device->dev) return NULL;
|
||||||
TTY_descr2 *D = d->dev;
|
TTY_descr2 *D = device->dev;
|
||||||
if(D->comfd < 0) return NULL;
|
if(D->comfd < 0) return NULL;
|
||||||
int L = 0;
|
int L = 0;
|
||||||
int length = D->bufsz;
|
int length = D->bufsz;
|
||||||
@ -130,7 +138,7 @@ static char *getttydata(chardevice *d, int *len){
|
|||||||
}
|
}
|
||||||
ptr += l; L += l;
|
ptr += l; L += l;
|
||||||
length -= l;
|
length -= l;
|
||||||
if(L >= d->eollen && 0 == strcmp(&ptr[-(d->eollen)], d->eol)){ // found end of line
|
if(L >= device->eollen && 0 == strcmp(&ptr[-(device->eollen)], device->eol)){ // found end of line
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}while(length);
|
}while(length);
|
||||||
@ -138,14 +146,14 @@ static char *getttydata(chardevice *d, int *len){
|
|||||||
D->buf[L] = 0;
|
D->buf[L] = 0;
|
||||||
if(len) *len = L;
|
if(len) *len = L;
|
||||||
if(!L) return NULL;
|
if(!L) return NULL;
|
||||||
rmeols(d);
|
rmeols(device);
|
||||||
DBG("buffer len: %zd, content: =%s=", D->buflen, D->buf);
|
DBG("buffer len: %zd, content: =%s=", D->buflen, D->buf);
|
||||||
return D->buf;
|
return D->buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *getsockdata(chardevice *d, int *len){
|
static char *getsockdata(int *len){
|
||||||
if(!d || !d->dev) return NULL;
|
if(!device || !device->dev) return NULL;
|
||||||
TTY_descr2 *D = d->dev;
|
TTY_descr2 *D = device->dev;
|
||||||
if(D->comfd < 0) return NULL;
|
if(D->comfd < 0) return NULL;
|
||||||
char *ptr = NULL;
|
char *ptr = NULL;
|
||||||
int n = waittoread(D->comfd);
|
int n = waittoread(D->comfd);
|
||||||
@ -155,7 +163,7 @@ static char *getsockdata(chardevice *d, int *len){
|
|||||||
ptr = D->buf;
|
ptr = D->buf;
|
||||||
ptr[n] = 0;
|
ptr[n] = 0;
|
||||||
D->buflen = n;
|
D->buflen = n;
|
||||||
n = rmeols(d);
|
n = rmeols(device);
|
||||||
DBG("got %d: ..%s..", n, ptr);
|
DBG("got %d: ..%s..", n, ptr);
|
||||||
}else{
|
}else{
|
||||||
DBG("Got nothing");
|
DBG("Got nothing");
|
||||||
@ -172,23 +180,24 @@ static char *getsockdata(chardevice *d, int *len){
|
|||||||
* @param len (o) - length of data read (-1 if device disconnected)
|
* @param len (o) - length of data read (-1 if device disconnected)
|
||||||
* @return NULL or string
|
* @return NULL or string
|
||||||
*/
|
*/
|
||||||
char *ReadData(chardevice *d, int *len){
|
char *ReadData(int *len){
|
||||||
if(!d || !d->dev) return NULL;
|
if(!device || !device->dev) return NULL;
|
||||||
if(len) *len = -1;
|
if(len) *len = -1;
|
||||||
char *r = NULL;
|
char *r = NULL;
|
||||||
switch(d->type){
|
switch(device->type){
|
||||||
case DEV_TTY:
|
case DEV_TTY:
|
||||||
r = getttydata(d, len);
|
r = getttydata(len);
|
||||||
break;
|
break;
|
||||||
case DEV_NETSOCKET:
|
case DEV_NETSOCKET:
|
||||||
case DEV_UNIXSOCKET:
|
case DEV_UNIXSOCKET:
|
||||||
r = getsockdata(d, len);
|
r = getsockdata(len);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(r && dupfile){
|
if(r && dupfile){
|
||||||
fprintf(dupfile, "< %s", r);
|
fwrite("< ", 1, 2, dupfile);
|
||||||
|
fwrite(r, 1, *len, dupfile);
|
||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
@ -196,40 +205,33 @@ char *ReadData(chardevice *d, int *len){
|
|||||||
/**
|
/**
|
||||||
* @brief SendData - send data to tty or socket
|
* @brief SendData - send data to tty or socket
|
||||||
* @param d - device
|
* @param d - device
|
||||||
* @param str - text string
|
* @param data - buffer with data
|
||||||
* @return 0 if error, -1 if disconnected
|
* @return 0 if error or empty string, -1 if disconnected
|
||||||
*/
|
*/
|
||||||
int SendData(chardevice *d, char *str){
|
int SendData(const char *data, size_t len){
|
||||||
char buf[BUFSIZ];
|
if(!device) return -1;
|
||||||
if(!d) return -1;
|
if(!data || len == 0) return 0;
|
||||||
DBG("send %s", str);
|
|
||||||
if(!str) return 0;
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
if(0 == pthread_mutex_lock(&d->mutex)){
|
if(0 == pthread_mutex_lock(&device->mutex)){
|
||||||
int l = strlen(str), lplus = l + d->eollen;
|
switch(device->type){
|
||||||
if(l < 1) return 0;
|
|
||||||
if(lplus > BUFSIZ-1) lplus = BUFSIZ-1;
|
|
||||||
snprintf(buf, lplus+1, "%s%s", str, d->eol);
|
|
||||||
DBG("SENDBUF (%d): _%s_", lplus, buf);
|
|
||||||
switch(d->type){
|
|
||||||
case DEV_TTY:
|
case DEV_TTY:
|
||||||
if(write_tty(d->dev->comfd, buf, lplus)) ret = 0;
|
if(write_tty(device->dev->comfd, data, len)) ret = 0;
|
||||||
else ret = l;
|
else ret = len;
|
||||||
break;
|
break;
|
||||||
case DEV_NETSOCKET:
|
case DEV_NETSOCKET:
|
||||||
case DEV_UNIXSOCKET:
|
case DEV_UNIXSOCKET:
|
||||||
if(lplus != send(d->dev->comfd, buf, lplus, MSG_NOSIGNAL)) ret = 0;
|
if(len != (size_t)send(device->dev->comfd, data, len, MSG_NOSIGNAL)) ret = 0;
|
||||||
else ret = l;
|
else ret = len;
|
||||||
pthread_mutex_unlock(&d->mutex);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
str = NULL;
|
data = NULL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(str && dupfile){
|
if(data && dupfile){
|
||||||
fprintf(dupfile, "> %s", buf);
|
fwrite("> ", 1, 2, dupfile);
|
||||||
|
fwrite(data, 1, len, dupfile);
|
||||||
}
|
}
|
||||||
pthread_mutex_unlock(&d->mutex);
|
pthread_mutex_unlock(&device->mutex);
|
||||||
}else ret = -1;
|
}else ret = -1;
|
||||||
DBG("ret=%d", ret);
|
DBG("ret=%d", ret);
|
||||||
return ret;
|
return ret;
|
||||||
@ -237,8 +239,8 @@ int SendData(chardevice *d, char *str){
|
|||||||
|
|
||||||
static const int socktypes[] = {SOCK_STREAM, SOCK_RAW, SOCK_RDM, SOCK_SEQPACKET, SOCK_DCCP, SOCK_PACKET, SOCK_DGRAM, 0};
|
static const int socktypes[] = {SOCK_STREAM, SOCK_RAW, SOCK_RDM, SOCK_SEQPACKET, SOCK_DCCP, SOCK_PACKET, SOCK_DGRAM, 0};
|
||||||
|
|
||||||
static TTY_descr2* opensocket(chardevice *d){
|
static TTY_descr2* opensocket(){
|
||||||
if(!d) return FALSE;
|
if(!device) return FALSE;
|
||||||
TTY_descr2 *descr = MALLOC(TTY_descr2, 1); // only for `buf` and bufsz/buflen
|
TTY_descr2 *descr = MALLOC(TTY_descr2, 1); // only for `buf` and bufsz/buflen
|
||||||
descr->buf = MALLOC(char, BUFSIZ);
|
descr->buf = MALLOC(char, BUFSIZ);
|
||||||
descr->bufsz = BUFSIZ;
|
descr->bufsz = BUFSIZ;
|
||||||
@ -250,11 +252,11 @@ static TTY_descr2* opensocket(chardevice *d){
|
|||||||
struct sockaddr *sa = NULL;
|
struct sockaddr *sa = NULL;
|
||||||
socklen_t addrlen = 0;
|
socklen_t addrlen = 0;
|
||||||
int domain = -1;
|
int domain = -1;
|
||||||
if(d->type == DEV_NETSOCKET){
|
if(device->type == DEV_NETSOCKET){
|
||||||
DBG("NETSOCK to %s", d->name);
|
DBG("NETSOCK to %s", device->name);
|
||||||
sa = (struct sockaddr*) &addr;
|
sa = (struct sockaddr*) &addr;
|
||||||
addrlen = sizeof(addr);
|
addrlen = sizeof(addr);
|
||||||
if((host = gethostbyname(d->name)) == NULL ){
|
if((host = gethostbyname(device->name)) == NULL ){
|
||||||
WARN("gethostbyname()");
|
WARN("gethostbyname()");
|
||||||
FREE(descr->buf);
|
FREE(descr->buf);
|
||||||
FREE(descr);
|
FREE(descr);
|
||||||
@ -263,7 +265,7 @@ static TTY_descr2* opensocket(chardevice *d){
|
|||||||
struct in_addr *ia = (struct in_addr*)host->h_addr_list[0];
|
struct in_addr *ia = (struct in_addr*)host->h_addr_list[0];
|
||||||
DBG("addr: %s", inet_ntoa(*ia));
|
DBG("addr: %s", inet_ntoa(*ia));
|
||||||
addr.sin_family = AF_INET;
|
addr.sin_family = AF_INET;
|
||||||
int p = atoi(d->port); DBG("PORT: %s - %d", d->port, p);
|
int p = atoi(device->port); DBG("PORT: %s - %d", device->port, p);
|
||||||
addr.sin_port = htons(p);
|
addr.sin_port = htons(p);
|
||||||
//addr.sin_addr.s_addr = *(long*)(host->h_addr);
|
//addr.sin_addr.s_addr = *(long*)(host->h_addr);
|
||||||
addr.sin_addr.s_addr = ia->s_addr;
|
addr.sin_addr.s_addr = ia->s_addr;
|
||||||
@ -273,16 +275,16 @@ static TTY_descr2* opensocket(chardevice *d){
|
|||||||
sa = (struct sockaddr*) &saddr;
|
sa = (struct sockaddr*) &saddr;
|
||||||
addrlen = sizeof(saddr);
|
addrlen = sizeof(saddr);
|
||||||
saddr.sun_family = AF_UNIX;
|
saddr.sun_family = AF_UNIX;
|
||||||
if(*(d->name) == 0){ // if sun_path[0] == 0 then don't create a file
|
if(*(device->name) == 0){ // if sun_path[0] == 0 then don't create a file
|
||||||
DBG("convert name");
|
DBG("convert name");
|
||||||
saddr.sun_path[0] = 0;
|
saddr.sun_path[0] = 0;
|
||||||
strncpy(saddr.sun_path+1, d->name+1, 105);
|
strncpy(saddr.sun_path+1, device->name+1, 105);
|
||||||
}
|
}
|
||||||
else if(strncmp("\\0", d->name, 2) == 0){
|
else if(strncmp("\\0", device->name, 2) == 0){
|
||||||
DBG("convert name");
|
DBG("convert name");
|
||||||
saddr.sun_path[0] = 0;
|
saddr.sun_path[0] = 0;
|
||||||
strncpy(saddr.sun_path+1, d->name+2, 105);
|
strncpy(saddr.sun_path+1, device->name+2, 105);
|
||||||
}else strncpy(saddr.sun_path, d->name, 106);
|
}else strncpy(saddr.sun_path, device->name, 106);
|
||||||
domain = AF_UNIX;
|
domain = AF_UNIX;
|
||||||
}
|
}
|
||||||
const int *type = socktypes;
|
const int *type = socktypes;
|
||||||
@ -363,17 +365,17 @@ someerr:
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static TTY_descr2* opentty(chardevice *d){
|
static TTY_descr2* opentty(){
|
||||||
if(!d->name){
|
if(!device->name){
|
||||||
/// ïÔÓÕÔÓÔ×ÕÅÔ ÉÍÑ ÐÏÒÔÁ
|
/// ïÔÓÕÔÓÔ×ÕÅÔ ÉÍÑ ÐÏÒÔÁ
|
||||||
WARNX(_("Port name is missing"));
|
WARNX(_("Port name is missing"));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
TTY_descr2 *descr = MALLOC(TTY_descr2, 1);
|
TTY_descr2 *descr = MALLOC(TTY_descr2, 1);
|
||||||
descr->portname = strdup(d->name);
|
descr->portname = strdup(device->name);
|
||||||
descr->speed = d->speed;
|
descr->speed = device->speed;
|
||||||
tcflag_t flags;
|
tcflag_t flags;
|
||||||
descr->format = parse_format(d->port, &flags);
|
descr->format = parse_format(device->port, &flags);
|
||||||
if(!descr->format) goto someerr;
|
if(!descr->format) goto someerr;
|
||||||
descr->buf = MALLOC(char, BUFSIZ);
|
descr->buf = MALLOC(char, BUFSIZ);
|
||||||
descr->bufsz = BUFSIZ-1;
|
descr->bufsz = BUFSIZ-1;
|
||||||
@ -389,14 +391,14 @@ static TTY_descr2* opentty(chardevice *d){
|
|||||||
descr->tty.c_lflag = 0; // ~(ICANON | ECHO | ECHOE | ISIG)
|
descr->tty.c_lflag = 0; // ~(ICANON | ECHO | ECHOE | ISIG)
|
||||||
descr->tty.c_iflag = 0;
|
descr->tty.c_iflag = 0;
|
||||||
descr->tty.c_cflag = BOTHER | flags |CREAD|CLOCAL;
|
descr->tty.c_cflag = BOTHER | flags |CREAD|CLOCAL;
|
||||||
descr->tty.c_ispeed = d->speed;
|
descr->tty.c_ispeed = device->speed;
|
||||||
descr->tty.c_ospeed = d->speed;
|
descr->tty.c_ospeed = device->speed;
|
||||||
if(ioctl(descr->comfd, TCSETS2, &descr->tty)){
|
if(ioctl(descr->comfd, TCSETS2, &descr->tty)){
|
||||||
WARN(_("Can't set new port config"));
|
WARN(_("Can't set new port config"));
|
||||||
goto someerr;
|
goto someerr;
|
||||||
}
|
}
|
||||||
ioctl(descr->comfd, TCGETS2, &descr->tty);
|
ioctl(descr->comfd, TCGETS2, &descr->tty);
|
||||||
d->speed = descr->tty.c_ispeed;
|
device->speed = descr->tty.c_ispeed;
|
||||||
#ifdef EBUG
|
#ifdef EBUG
|
||||||
printf("ispeed: %d, ospeed: %d, cflag=%d (BOTHER=%d)\n", descr->tty.c_ispeed, descr->tty.c_ospeed, descr->tty.c_cflag&CBAUD, BOTHER);
|
printf("ispeed: %d, ospeed: %d, cflag=%d (BOTHER=%d)\n", descr->tty.c_ispeed, descr->tty.c_ospeed, descr->tty.c_cflag&CBAUD, BOTHER);
|
||||||
if(system("stty -F /dev/ttyUSB0")) WARN("system()");
|
if(system("stty -F /dev/ttyUSB0")) WARN("system()");
|
||||||
@ -417,20 +419,24 @@ someerr:
|
|||||||
int opendev(chardevice *d, char *path){
|
int opendev(chardevice *d, char *path){
|
||||||
if(!d) return FALSE;
|
if(!d) return FALSE;
|
||||||
DBG("Try to open device");
|
DBG("Try to open device");
|
||||||
switch(d->type){
|
device = MALLOC(chardevice, 1);
|
||||||
|
memcpy(device, d, sizeof(chardevice));
|
||||||
|
device->name = strdup(d->name);
|
||||||
|
device->port = strdup(d->port);
|
||||||
|
switch(device->type){
|
||||||
case DEV_TTY:
|
case DEV_TTY:
|
||||||
DBG("Serial");
|
DBG("Serial");
|
||||||
d->dev = opentty(d);
|
device->dev = opentty();
|
||||||
if(!d->dev){
|
if(!device->dev){
|
||||||
WARN("Can't open device %s", d->name);
|
WARN("Can't open device %s", device->name);
|
||||||
DBG("CANT OPEN");
|
DBG("CANT OPEN");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DEV_NETSOCKET:
|
case DEV_NETSOCKET:
|
||||||
case DEV_UNIXSOCKET:
|
case DEV_UNIXSOCKET:
|
||||||
d->dev = opensocket(d);
|
device->dev = opensocket();
|
||||||
if(!d->dev){
|
if(!device->dev){
|
||||||
WARNX("Can't open socket");
|
WARNX("Can't open socket");
|
||||||
DBG("CANT OPEN");
|
DBG("CANT OPEN");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
@ -443,44 +449,45 @@ int opendev(chardevice *d, char *path){
|
|||||||
dupfile = fopen(path, "a");
|
dupfile = fopen(path, "a");
|
||||||
if(!dupfile){
|
if(!dupfile){
|
||||||
WARN("Can't open %s", path);
|
WARN("Can't open %s", path);
|
||||||
closedev(d);
|
closedev();
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void closedev(chardevice *d){
|
void closedev(){
|
||||||
if(!d) return;
|
if(!device) return;
|
||||||
pthread_mutex_unlock(&d->mutex);
|
pthread_mutex_unlock(&device->mutex);
|
||||||
pthread_mutex_trylock(&d->mutex);
|
pthread_mutex_trylock(&device->mutex);
|
||||||
if(dupfile){
|
if(dupfile){
|
||||||
fclose(dupfile);
|
fclose(dupfile);
|
||||||
dupfile = NULL;
|
dupfile = NULL;
|
||||||
}
|
}
|
||||||
switch(d->type){
|
switch(device->type){
|
||||||
case DEV_TTY:
|
case DEV_TTY:
|
||||||
if(d->dev){
|
if(device->dev){
|
||||||
TTY_descr2 *t = d->dev;
|
TTY_descr2 *t = device->dev;
|
||||||
ioctl(t->comfd, TCSETS2, &t->oldtty); // return TTY to previous state
|
ioctl(t->comfd, TCSETS2, &t->oldtty); // return TTY to previous state
|
||||||
close(t->comfd);
|
close(t->comfd);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DEV_NETSOCKET:
|
case DEV_NETSOCKET:
|
||||||
if(d->dev){
|
if(device->dev){
|
||||||
close(d->dev->comfd);
|
close(device->dev->comfd);
|
||||||
FREE(d->dev);
|
FREE(device->dev);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(d->dev){
|
if(device->dev){
|
||||||
FREE(d->dev->format);
|
FREE(device->dev->format);
|
||||||
FREE(d->dev->portname);
|
FREE(device->dev->portname);
|
||||||
FREE(d->dev->buf);
|
FREE(device->dev->buf);
|
||||||
FREE(d->dev);
|
FREE(device->dev);
|
||||||
}
|
}
|
||||||
FREE(d->name);
|
FREE(device->name);
|
||||||
|
FREE(device);
|
||||||
DBG("Device closed");
|
DBG("Device closed");
|
||||||
}
|
}
|
||||||
|
|||||||
10
ttysocket.h
10
ttysocket.h
@ -23,9 +23,10 @@
|
|||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <asm-generic/termbits.h>
|
#include <asm-generic/termbits.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
//#include "dbg.h"
|
//#include "dbg.h"
|
||||||
|
|
||||||
typedef enum{
|
typedef enum{ // device: tty terminal, network socket or UNIX socket
|
||||||
DEV_TTY,
|
DEV_TTY,
|
||||||
DEV_NETSOCKET,
|
DEV_NETSOCKET,
|
||||||
DEV_UNIXSOCKET,
|
DEV_UNIXSOCKET,
|
||||||
@ -55,10 +56,11 @@ typedef struct{
|
|||||||
int eollen; // length of `eol`
|
int eollen; // length of `eol`
|
||||||
} chardevice;
|
} chardevice;
|
||||||
|
|
||||||
char *ReadData(chardevice *d, int *l);
|
char *geteol(int *s);
|
||||||
int SendData(chardevice *d, char *str);
|
char *ReadData(int *l);
|
||||||
|
int SendData(const char *data, size_t len);
|
||||||
void settimeout(int tms);
|
void settimeout(int tms);
|
||||||
int opendev(chardevice *d, char *path);
|
int opendev(chardevice *d, char *path);
|
||||||
void closedev(chardevice *d);
|
void closedev();
|
||||||
|
|
||||||
#endif // TTY_H__
|
#endif // TTY_H__
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user