mirror of
https://github.com/tio/tio.git
synced 2026-05-01 23:07:58 +02:00
Line editing.
The program can be started in line editing mode. In this mode, the
current line can be edited by inserting/deleting characters. Escape
values can be used for bytes.
Controls:
printable - adds character to the position of the cursor
RIGHT, LEFT - moves cursor in the line
UP, DOWN - gets prevoiusly sent lines from the history
BACKSPACE - deletes character before the cursor
ENTER - sends line
Commands:
:? - list available commands
:q - quit
:v - show version
:: - send ':'
Escapes:
\dNNN - decimal NNN (e.g: \d045 = 45)
\xNN - hexadecimal NN (e.g: \xff = 255)
\bNNNNNNNN - binary NNNNNNNN (e.g: \b00000001 = 1)
Added option --line-edit, to start the program in line editing mode.
Added option --no-newline-in-line-edit to prevent sending newline
characters.
This commit is contained in:
parent
7fc8e278ed
commit
aa9f6435db
10 changed files with 730 additions and 195 deletions
68
man/tio.1
68
man/tio.1
|
|
@ -99,7 +99,17 @@ Start in hexadecimal mode.
|
|||
.TP
|
||||
.BR \-\-newline-in-hex
|
||||
|
||||
Interpret new line characters ('\\r', '\\n') in hexadecimal mode.
|
||||
Interpret new line characters ('\er', '\en') in hexadecimal mode.
|
||||
|
||||
.TP
|
||||
.BR \-\-line-edit
|
||||
|
||||
Start in line editing mode.
|
||||
|
||||
.TP
|
||||
.BR \-\-no-newline-in-line-edit
|
||||
|
||||
Does not append "\er\en" after a line in line editing mode.
|
||||
|
||||
.TP
|
||||
.BR \-v ", " \-\-version
|
||||
|
|
@ -150,6 +160,62 @@ By default there is \fBno new line\fR in this mode, but it can be turned on usin
|
|||
.TP
|
||||
Bytes can be sent in this mode by typing the \fBtwo-character hexadecimal\fR representation of the value, e.g.: to send \fI0xA\fR you must type \fI0a\fR or \fI0A\fR.
|
||||
|
||||
.SH "LINE EDIT"
|
||||
The program can be started in line editing mode using the \fB--line-edot\fR option. In this mode, the current line can be edited by inserting/deleting characters. Escape values can be used for bytes.
|
||||
.PP
|
||||
.TP 16n
|
||||
The following keys can be used:
|
||||
|
||||
.IP "\fB<ASCII>"
|
||||
Add character to the position of the cursor.
|
||||
|
||||
.IP "\fBRIGHT\fR, \fBLEFT\fR"
|
||||
Move cursor in the line.
|
||||
|
||||
.IP "\fBUP\fR, \fBDOWN\fR"
|
||||
Get prevoiusly sent lines from the history.
|
||||
|
||||
.IP "\fBBACKSPACE\fR"
|
||||
Delete character before the cursor.
|
||||
|
||||
.IP "\fBENTER\fR"
|
||||
Send line.
|
||||
|
||||
.PP
|
||||
.TP 16n
|
||||
The following commands can be used:
|
||||
|
||||
.IP "\fB:?\fR"
|
||||
List available commands.
|
||||
|
||||
.IP "\fB:q\fR"
|
||||
Quit.
|
||||
|
||||
.IP "\fB:v\fR"
|
||||
Show version.
|
||||
|
||||
.IP "\fB::\fR"
|
||||
Send ':'.
|
||||
|
||||
.PP
|
||||
.TP 16n
|
||||
Escape bytes:
|
||||
|
||||
.IP \fB\edNNN\fR
|
||||
Send NNN as a decimal value. NNN must be 3 characters and less than or equal to 255. For example: \ed023 = 23.
|
||||
|
||||
.IP \fB\exNN\fR
|
||||
Send NN as a hexadecimal value. NN must be 2 characters. For example: \exff = 255.
|
||||
|
||||
.IP \fB\ebNNNNNNNN\fR
|
||||
Send NNNNNNNN as a binary value. NNNNNNNN must be 8 characters. For example: \eb0000001 = 1.
|
||||
|
||||
.TP 7n
|
||||
The following line sends the ASCII string \fI"Hello"\fR:
|
||||
|
||||
H\ed101\ex6c\eb01101100o
|
||||
|
||||
|
||||
.SH "EXAMPLES"
|
||||
.TP
|
||||
Typical use is without options. For example:
|
||||
|
|
|
|||
|
|
@ -12,7 +12,9 @@ tio_SOURCES = tty.c \
|
|||
include/tio/time.h \
|
||||
include/tio/print.h \
|
||||
include/tio/log.h \
|
||||
include/tio/error.h
|
||||
include/tio/error.h \
|
||||
lineedit.c \
|
||||
include/tio/lineedit.h
|
||||
|
||||
if ADD_SETSPEED2
|
||||
tio_SOURCES += setspeed2.c
|
||||
|
|
|
|||
|
|
@ -17,8 +17,14 @@ _tio()
|
|||
-p --parity \
|
||||
-o --output-delay \
|
||||
-n --no-autoconnect \
|
||||
-e --local-echo \
|
||||
-t --timestamp \
|
||||
-l --log \
|
||||
-m --map \
|
||||
-x --hex \
|
||||
--newline-in-hex \
|
||||
--line-edit \
|
||||
--no-newline-in-line-edit \
|
||||
-v --version \
|
||||
-t --timestamp \
|
||||
-h --help"
|
||||
|
|
@ -70,6 +76,22 @@ _tio()
|
|||
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
|
||||
return 0
|
||||
;;
|
||||
-x | --hex)
|
||||
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
|
||||
return 0
|
||||
;;
|
||||
--newline-in-hex)
|
||||
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
|
||||
return 0
|
||||
;;
|
||||
--line-edit)
|
||||
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
|
||||
return 0
|
||||
;;
|
||||
--no-newline-in-line-edit)
|
||||
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
|
||||
return 0
|
||||
;;
|
||||
-v | --version)
|
||||
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
|
||||
return 0
|
||||
|
|
|
|||
40
src/include/tio/lineedit.h
Normal file
40
src/include/tio/lineedit.h
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
#ifndef LINEEDIT_H
|
||||
#define LINEEDIT_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <termios.h>
|
||||
#include <stdbool.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#define LINE_SIZE 81 /* 80 chars + terminating */
|
||||
|
||||
#define GOTOXY(x,y) fprintf(stdout, "\033[%d;%dH", (y), (x))
|
||||
|
||||
#define ACTION_PREFIX_1 0x1b
|
||||
#define ACTION_PREFIX_2 0x5b
|
||||
#define ARROW_LEFT 0x44
|
||||
#define ARROW_RIGHT 0x43
|
||||
#define ARROW_UP 0x41
|
||||
#define ARROW_DOWN 0x42
|
||||
|
||||
#define BACKSPACE 0x7f
|
||||
|
||||
void lineedit_configure(const char * prefix, size_t max_len);
|
||||
void add_to_history(const char * line);
|
||||
char * get_line(char c);
|
||||
void free_line(char * line);
|
||||
|
||||
#endif
|
||||
|
|
@ -28,6 +28,8 @@
|
|||
#include <sys/param.h>
|
||||
|
||||
#define OPT_NEWLINE_IN_HEX 1000 // "short" option for --newline-in-hex
|
||||
#define OPT_LINE_EDIT 1001 // "short" option for --line-edit
|
||||
#define OPT_NO_NEWLINE_LINE_EDIT 1002 // "short" option for --no-newline-in-line-edit
|
||||
|
||||
/* Options */
|
||||
struct option_t
|
||||
|
|
@ -45,6 +47,8 @@ struct option_t
|
|||
bool timestamp;
|
||||
bool hex_mode;
|
||||
bool newline_in_hex;
|
||||
bool line_edit;
|
||||
bool no_newline_in_line_edit;
|
||||
const char *log_filename;
|
||||
const char *map;
|
||||
};
|
||||
|
|
|
|||
192
src/lineedit.c
Normal file
192
src/lineedit.c
Normal file
|
|
@ -0,0 +1,192 @@
|
|||
#include "tio/lineedit.h"
|
||||
#include "tio/options.h"
|
||||
#include "tio/print.h"
|
||||
|
||||
static struct winsize winsize;
|
||||
|
||||
static char edited_line[LINE_SIZE];
|
||||
static unsigned char edited_line_ctr = 0;
|
||||
static int edited_line_cursor_pos = 0;
|
||||
static const char * line_edit_prefix;
|
||||
static int line_edit_prefix_length;
|
||||
static char prev_char = 0, prevprev_char = 0;
|
||||
|
||||
static char ** history = NULL;
|
||||
static unsigned int history_max_len;
|
||||
static unsigned int history_len = 0;
|
||||
static unsigned int history_pointer = 0;
|
||||
|
||||
static void free_history(void){
|
||||
for(unsigned int i = 0; i < history_len; i++){
|
||||
if(history[i]){
|
||||
free(history[i]);
|
||||
}
|
||||
}
|
||||
|
||||
free(history);
|
||||
}
|
||||
|
||||
static char * get_from_history(int dir){
|
||||
char * ret = NULL;
|
||||
|
||||
if(dir == 1){
|
||||
ret = history[history_pointer];
|
||||
|
||||
if(history_pointer + 1 < history_len){
|
||||
history_pointer++;
|
||||
}
|
||||
} else if(dir == -1){
|
||||
if(history_pointer > 0){
|
||||
history_pointer--;
|
||||
}
|
||||
|
||||
ret = history[history_pointer];
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void lineedit_configure(const char * prefix, size_t max_len){
|
||||
if(ioctl(0, TIOCGWINSZ, &winsize) < 0){
|
||||
warning_printf("Could not get the dimensions of the terminal");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
history_max_len = max_len;
|
||||
history = (char **) calloc(history_max_len, sizeof(char *));
|
||||
if(history == NULL){
|
||||
warning_printf("Could not allocate the history");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
atexit(free_history);
|
||||
|
||||
line_edit_prefix = prefix;
|
||||
line_edit_prefix_length = strlen(prefix);
|
||||
}
|
||||
|
||||
char * get_line(char c){
|
||||
char * finished_line = NULL;
|
||||
char * history_line = NULL;
|
||||
|
||||
if(prev_char == ACTION_PREFIX_1 && c == ACTION_PREFIX_2){
|
||||
/* do nothing */
|
||||
} else if(prevprev_char == ACTION_PREFIX_1 && prev_char == ACTION_PREFIX_2){
|
||||
switch(c){
|
||||
case ARROW_LEFT:
|
||||
if(edited_line_cursor_pos > 0){
|
||||
edited_line_cursor_pos--;
|
||||
}
|
||||
break;
|
||||
|
||||
case ARROW_RIGHT:
|
||||
if(edited_line_cursor_pos < edited_line_ctr){
|
||||
edited_line_cursor_pos++;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case ARROW_UP:
|
||||
if((history_line = get_from_history(1)) != NULL){
|
||||
strcpy(edited_line, history_line);
|
||||
edited_line_ctr = strlen(history_line);
|
||||
edited_line_cursor_pos = edited_line_ctr;
|
||||
}
|
||||
break;
|
||||
|
||||
case ARROW_DOWN:
|
||||
if((history_line = get_from_history(-1)) != NULL){
|
||||
strcpy(edited_line, history_line);
|
||||
edited_line_ctr = strlen(history_line);
|
||||
edited_line_cursor_pos = edited_line_ctr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if(c == '\r' || c == '\n'){
|
||||
edited_line[edited_line_ctr] = '\0';
|
||||
finished_line = strdup(edited_line);
|
||||
} else {
|
||||
if(isprint(c)){
|
||||
if(edited_line_ctr < LINE_SIZE - 1){
|
||||
memmove(&edited_line[edited_line_cursor_pos + 1],
|
||||
&edited_line[edited_line_cursor_pos],
|
||||
edited_line_ctr - edited_line_cursor_pos);
|
||||
|
||||
edited_line[edited_line_cursor_pos] = c;
|
||||
|
||||
edited_line_ctr++;
|
||||
edited_line_cursor_pos++;
|
||||
}
|
||||
} else if(c == BACKSPACE){
|
||||
char * rest = &edited_line[edited_line_cursor_pos];
|
||||
memcpy(&edited_line[edited_line_cursor_pos - 1], rest, edited_line_ctr - edited_line_cursor_pos);
|
||||
|
||||
if(edited_line_ctr > 0){
|
||||
edited_line_ctr--;
|
||||
}
|
||||
|
||||
if(edited_line_cursor_pos > 0){
|
||||
edited_line_cursor_pos--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* clear line with spaces */
|
||||
fprintf(stdout, "\r%*c", winsize.ws_col, ' ');
|
||||
/* output the contents of the buffer */
|
||||
fprintf(stdout, "\r%s%.*s", line_edit_prefix, edited_line_ctr, edited_line);
|
||||
|
||||
/* set the position of the cursor */
|
||||
GOTOXY(edited_line_cursor_pos + line_edit_prefix_length + 1, winsize.ws_row);
|
||||
|
||||
fflush(stdout);
|
||||
|
||||
/* clear buffer */
|
||||
if(finished_line != NULL){
|
||||
memset(edited_line, 0, LINE_SIZE);
|
||||
edited_line_ctr = 0;
|
||||
edited_line_cursor_pos = 0;
|
||||
}
|
||||
|
||||
prevprev_char = prev_char;
|
||||
prev_char = c;
|
||||
|
||||
return finished_line;
|
||||
}
|
||||
|
||||
void free_line(char * line){
|
||||
free(line);
|
||||
fprintf(stdout, "\r%s", line_edit_prefix);
|
||||
}
|
||||
|
||||
void add_to_history(const char * line){
|
||||
/* dont add duplicate duplicate */
|
||||
if(history_len > 0 && strcmp(line, history[0]) == 0){
|
||||
return;
|
||||
}
|
||||
|
||||
/* history is full, make room */
|
||||
if(history_len == history_max_len){
|
||||
free(history[history_len - 1]);
|
||||
}
|
||||
|
||||
/* shift history to the right by 1 */
|
||||
size_t count = history_len == history_max_len ? history_len - 1 : history_len;
|
||||
memmove(&history[1], &history[0], count * sizeof(char *));
|
||||
|
||||
/* add to history */
|
||||
history[0] = strdup(line);
|
||||
if(history[0] == NULL){
|
||||
return;
|
||||
}
|
||||
|
||||
if(history_len < history_max_len){
|
||||
history_len++;
|
||||
}
|
||||
|
||||
history_pointer = 0;
|
||||
}
|
||||
|
||||
|
||||
1
src/linenoise
Submodule
1
src/linenoise
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 97d2850af13c339369093b78abe5265845d78220
|
||||
|
|
@ -28,6 +28,7 @@
|
|||
#include "tio/log.h"
|
||||
#include "tio/error.h"
|
||||
#include "tio/print.h"
|
||||
#include "tio/lineedit.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
|
|
@ -51,6 +52,9 @@ int main(int argc, char *argv[])
|
|||
/* Install log exit handler */
|
||||
atexit(&log_exit);
|
||||
|
||||
if(option.line_edit)
|
||||
lineedit_configure(">", 100);
|
||||
|
||||
/* Create log file */
|
||||
if (option.log)
|
||||
log_open(option.log_filename);
|
||||
|
|
|
|||
|
|
@ -49,6 +49,8 @@ struct option_t option =
|
|||
false, // No timestamp
|
||||
false, // Not starting in hex mode
|
||||
false, // No newlines in hex mode
|
||||
false, // Not starting in line edit mode
|
||||
false, // Send new line in line edit mode
|
||||
"", // Log filename
|
||||
"" // Map string
|
||||
};
|
||||
|
|
@ -71,12 +73,15 @@ void print_help(char *argv[])
|
|||
printf(" -m, --map <flags> Map special characters\n");
|
||||
printf(" -x, --hex Start in hexadecimal mode\n");
|
||||
printf(" --newline-in-hex Interpret new line characters in hex mode\n");
|
||||
printf(" --line-edit Start in line edit mode\n");
|
||||
printf(" --no-newline-in-line-edit Don't send newline after a line in line edit mode\n");
|
||||
printf(" -v, --version Display version\n");
|
||||
printf(" -h, --help Display help\n");
|
||||
printf("\n");
|
||||
printf("See the man page for list of supported mapping flags.\n");
|
||||
printf("\n");
|
||||
printf("In session, press ctrl-t q to quit.\n");
|
||||
printf("In line edit mode, type :q to quit.\n");
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
|
@ -123,11 +128,15 @@ void parse_options(int argc, char *argv[])
|
|||
{"map", required_argument, 0, 'm'},
|
||||
{"hex", no_argument, 0, 'x'},
|
||||
{"newline-in-hex", no_argument, 0, OPT_NEWLINE_IN_HEX },
|
||||
{"line-edit", no_argument, 0, OPT_LINE_EDIT },
|
||||
{"no-newline-in-line-edit", no_argument, 0, OPT_NO_NEWLINE_LINE_EDIT },
|
||||
{"version", no_argument, 0, 'v'},
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
#define OPT_NO_NEWLINE_LINE_EDIT 1002 // "short" option for --no-newline-in-line-edit
|
||||
|
||||
/* getopt_long stores the option index here */
|
||||
int option_index = 0;
|
||||
|
||||
|
|
@ -203,6 +212,14 @@ void parse_options(int argc, char *argv[])
|
|||
option.newline_in_hex = true;
|
||||
break;
|
||||
|
||||
case OPT_LINE_EDIT:
|
||||
option.line_edit = true;
|
||||
break;
|
||||
|
||||
case OPT_NO_NEWLINE_LINE_EDIT:
|
||||
option.no_newline_in_line_edit = true;
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
printf("tio v%s\n", VERSION);
|
||||
printf("Copyright (c) 2014-2018 Martin Lund\n");
|
||||
|
|
|
|||
213
src/tty.c
213
src/tty.c
|
|
@ -43,11 +43,14 @@
|
|||
#include "tio/time.h"
|
||||
#include "tio/log.h"
|
||||
#include "tio/error.h"
|
||||
#include "tio/lineedit.h"
|
||||
|
||||
#ifdef HAVE_TERMIOS2
|
||||
extern int setspeed2(int fd, int baudrate);
|
||||
#endif
|
||||
|
||||
#define ESCAPED_BUFFER_SIZE 9 // max 8 binary digit + terminating 0
|
||||
|
||||
static struct termios tio, tio_old, stdout_new, stdout_old, stdin_new, stdin_old;
|
||||
static unsigned long rx_total = 0, tx_total = 0;
|
||||
static bool connected = false;
|
||||
|
|
@ -60,9 +63,14 @@ static bool map_i_nl_crnl = false;
|
|||
static bool map_o_cr_nl = false;
|
||||
static bool map_o_nl_crnl = false;
|
||||
static bool map_o_del_bs = false;
|
||||
static char hex_chars[2];
|
||||
static char hex_chars[3] = { 0 };
|
||||
static unsigned char hex_char_index = 0;
|
||||
|
||||
static char parsed_line[LINE_SIZE];
|
||||
static unsigned int parsed_line_ctr;
|
||||
|
||||
void handle_command_sequence(char input_char, char previous_char, char *output_char, bool *forward);
|
||||
|
||||
#define tio_printf(format, args...) \
|
||||
{ \
|
||||
if (tainted) putchar('\n'); \
|
||||
|
|
@ -80,22 +88,20 @@ static void optional_local_echo(char c)
|
|||
log_write(c);
|
||||
}
|
||||
|
||||
|
||||
inline static bool is_valid_bin(char c)
|
||||
{
|
||||
return (c >= '0' && c <= '1');
|
||||
}
|
||||
|
||||
inline static bool is_valid_hex(char c)
|
||||
{
|
||||
return ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'));
|
||||
}
|
||||
|
||||
inline static unsigned char char_to_nibble(char c)
|
||||
inline static bool is_valid_dec(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;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
return (c >= '0' && c <= '9');
|
||||
}
|
||||
|
||||
static void output_hex(char c)
|
||||
|
|
@ -103,7 +109,7 @@ static void output_hex(char c)
|
|||
hex_chars[hex_char_index++] = c;
|
||||
|
||||
if(hex_char_index == 2){
|
||||
unsigned char hex_value = char_to_nibble(hex_chars[0]) << 4 | (char_to_nibble(hex_chars[1]) & 0x0F);
|
||||
unsigned char hex_value = (unsigned char)strtol(hex_chars, NULL, 16);
|
||||
hex_char_index = 0;
|
||||
|
||||
optional_local_echo(hex_value);
|
||||
|
|
@ -135,6 +141,162 @@ static void print_normal(char c)
|
|||
fflush(stdout);
|
||||
}
|
||||
|
||||
static void send_line(const char * line)
|
||||
{
|
||||
int len = strlen(line);
|
||||
|
||||
if(option.local_echo){
|
||||
fprintf(stdout, "\r\n");
|
||||
for(int i = 0; i < len; i++){
|
||||
optional_local_echo(line[i]);
|
||||
}
|
||||
|
||||
if(option.no_newline_in_line_edit){
|
||||
fprintf(stdout, "\r\n");
|
||||
}
|
||||
} else {
|
||||
get_line(0);
|
||||
}
|
||||
|
||||
ssize_t status = write(fd, line, len);
|
||||
if (status < 0){
|
||||
warning_printf("Could not write to tty device");
|
||||
} else {
|
||||
tx_total += len;
|
||||
}
|
||||
}
|
||||
|
||||
static void parse_line(const char * line)
|
||||
{
|
||||
int len = strlen(line);
|
||||
|
||||
if(len == 0){
|
||||
return;
|
||||
}
|
||||
|
||||
/* escaped characters will collapse */
|
||||
if(len > LINE_SIZE - 3){
|
||||
warning_printf("Line is too long (%d): %s", len, line);
|
||||
return;
|
||||
}
|
||||
|
||||
parsed_line_ctr = 0;
|
||||
memset(parsed_line, 0, LINE_SIZE);
|
||||
|
||||
/* handle commands */
|
||||
if(len == 2 && line[0] == ':'){
|
||||
switch(line[1]){
|
||||
case '?':
|
||||
tio_printf("Commands:");
|
||||
tio_printf(":? List available commands");
|
||||
tio_printf(":q Quit");
|
||||
tio_printf(":v Show version");
|
||||
tio_printf(":: Send ':'");
|
||||
break;
|
||||
|
||||
case 'q':
|
||||
handle_command_sequence(KEY_Q, KEY_CTRL_T, NULL, NULL);
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
handle_command_sequence(KEY_V, KEY_CTRL_T, NULL, NULL);
|
||||
break;
|
||||
|
||||
case ':':
|
||||
parsed_line[parsed_line_ctr++] = ':';
|
||||
break;
|
||||
|
||||
default:
|
||||
warning_printf("Unknown command: %c", line[1]);
|
||||
return;
|
||||
|
||||
}
|
||||
/* interpret line */
|
||||
} else {
|
||||
int characters_to_read = 0;
|
||||
char buffer[ESCAPED_BUFFER_SIZE];
|
||||
unsigned int buffer_ctr = 0;
|
||||
int base = 10;
|
||||
memset(buffer, 0, ESCAPED_BUFFER_SIZE);
|
||||
|
||||
unsigned long value;
|
||||
|
||||
/* handle escape characters */
|
||||
for(unsigned int i = 0; i < len; i++){
|
||||
if(characters_to_read > 0){
|
||||
if(base == 16 && !is_valid_hex(line[i])){
|
||||
warning_printf("Invalid hexadecimal character: %c", line[i]);
|
||||
return;
|
||||
} else if(base == 10 && !is_valid_dec(line[i])){
|
||||
warning_printf("Invalid decimal character: %c", line[i]);
|
||||
return;
|
||||
} else if(base == 2 && !is_valid_bin(line[i])){
|
||||
warning_printf("Invalid binary character: %c", line[i]);
|
||||
return;
|
||||
} else {
|
||||
buffer[buffer_ctr++] = line[i];
|
||||
|
||||
if(buffer_ctr == characters_to_read){
|
||||
value = (unsigned long)strtol(buffer, NULL, base);
|
||||
|
||||
if(value > 255){
|
||||
warning_printf("Value is too large for a byte: %lu", value);
|
||||
return;
|
||||
}
|
||||
|
||||
parsed_line[parsed_line_ctr++] = (unsigned char)value;
|
||||
|
||||
memset(buffer, 0, ESCAPED_BUFFER_SIZE);
|
||||
buffer_ctr = 0;
|
||||
characters_to_read = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(line[i] == '\\'){
|
||||
if(i + 1 < len && line[i+1] == '\\'){
|
||||
parsed_line[parsed_line_ctr++] = '\\';
|
||||
i++;
|
||||
} else if(i + 1 < len && line[i+1] == 'x'){
|
||||
base = 16;
|
||||
characters_to_read = 2;
|
||||
i++;
|
||||
} else if(i + 1 < len && line[i+1] == 'd'){
|
||||
base = 10;
|
||||
characters_to_read = 3;
|
||||
i++;
|
||||
} else if(i + 1 < len && line[i+1] == 'b'){
|
||||
base = 2;
|
||||
characters_to_read = 8;
|
||||
i++;
|
||||
} else if(i + 1 < len){
|
||||
warning_printf("Unknown base: %c", line[i+1]);
|
||||
return;
|
||||
} else {
|
||||
warning_printf("Invalid escape: %s", line);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
parsed_line[parsed_line_ctr++] = line[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(characters_to_read != 0){
|
||||
warning_printf("Unescaped line: %s", line);
|
||||
return;
|
||||
}
|
||||
|
||||
if(option.no_newline_in_line_edit == false){
|
||||
parsed_line[parsed_line_ctr++] = '\r';
|
||||
parsed_line[parsed_line_ctr++] = '\n';
|
||||
}
|
||||
|
||||
parsed_line[parsed_line_ctr++] = '\0';
|
||||
}
|
||||
|
||||
send_line(parsed_line);
|
||||
}
|
||||
|
||||
static void toggle_line(const char *line_name, int mask)
|
||||
{
|
||||
int state;
|
||||
|
|
@ -375,7 +537,12 @@ void stdout_configure(void)
|
|||
|
||||
/* Print launch hints */
|
||||
tio_printf("tio v%s", VERSION);
|
||||
tio_printf("Press ctrl-t q to quit");
|
||||
if(option.line_edit)
|
||||
{
|
||||
tio_printf("Type :q to quit, :? for help.");
|
||||
} else {
|
||||
tio_printf("Press ctrl-t q to quit, ctrl-t ? for help.");
|
||||
}
|
||||
|
||||
/* At start use normal print function */
|
||||
print = print_normal;
|
||||
|
|
@ -661,6 +828,7 @@ int tty_connect(void)
|
|||
int status;
|
||||
time_t next_timestamp = 0;
|
||||
char* now = NULL;
|
||||
char* raw_line = NULL;
|
||||
|
||||
/* Open tty device */
|
||||
#ifdef __APPLE__
|
||||
|
|
@ -745,6 +913,12 @@ int tty_connect(void)
|
|||
|
||||
maxfd = MAX(fd, STDIN_FILENO) + 1; /* Maximum bit entry (fd) to test */
|
||||
|
||||
/* display initial prompt */
|
||||
if(option.line_edit)
|
||||
{
|
||||
get_line(0);
|
||||
}
|
||||
|
||||
/* Input loop */
|
||||
while (true)
|
||||
{
|
||||
|
|
@ -783,6 +957,7 @@ int tty_connect(void)
|
|||
next_timestamp = 0;
|
||||
}
|
||||
|
||||
// FIXME: make it better in line edit mode
|
||||
/* Map input character */
|
||||
if ((input_char == '\n') && (map_i_nl_crnl))
|
||||
{
|
||||
|
|
@ -825,6 +1000,15 @@ int tty_connect(void)
|
|||
goto error_read;
|
||||
}
|
||||
|
||||
if(option.line_edit){
|
||||
if((raw_line = get_line(input_char)) != NULL){
|
||||
add_to_history(raw_line);
|
||||
|
||||
parse_line(raw_line);
|
||||
|
||||
free_line(raw_line);
|
||||
}
|
||||
} else {
|
||||
/* Forward input to output except ctrl-t key */
|
||||
output_char = input_char;
|
||||
if (input_char == KEY_CTRL_T)
|
||||
|
|
@ -838,6 +1022,7 @@ int tty_connect(void)
|
|||
if(print_mode == HEX){
|
||||
if(!is_valid_hex(input_char)){
|
||||
warning_printf("Invalid hex character: '%c' (0x%02x)", input_char, input_char);
|
||||
hex_char_index = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
|
@ -861,6 +1046,7 @@ int tty_connect(void)
|
|||
delay(option.output_delay);
|
||||
}
|
||||
|
||||
|
||||
if(print_mode == HEX){
|
||||
output_hex(output_char);
|
||||
} else {
|
||||
|
|
@ -884,6 +1070,7 @@ int tty_connect(void)
|
|||
previous_char = input_char;
|
||||
|
||||
}
|
||||
}
|
||||
} else if (status == -1)
|
||||
{
|
||||
error_printf("Error: select() failed (%s)", strerror(errno));
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue