mirror of
https://repo.or.cz/socat.git
synced 2025-07-12 22:53:24 +00:00
socat V1.6.0.0 (initial GIT commit)
This commit is contained in:
commit
b819572f5e
170 changed files with 59193 additions and 0 deletions
244
xio-readline.c
Normal file
244
xio-readline.c
Normal file
|
@ -0,0 +1,244 @@
|
|||
/* $Id: xio-readline.c,v 1.17 2007/01/25 21:36:11 gerhard Exp $ */
|
||||
/* Copyright Gerhard Rieger 2002-2007 */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
/* this file contains the source for opening the readline address */
|
||||
|
||||
#include "xiosysincludes.h"
|
||||
#include "xioopen.h"
|
||||
|
||||
#include "xio-termios.h"
|
||||
#include "xio-readline.h"
|
||||
|
||||
|
||||
#if WITH_READLINE
|
||||
|
||||
/*
|
||||
options: history file
|
||||
prompt
|
||||
mode=vi?
|
||||
inputrc=?
|
||||
|
||||
uses stdin!!
|
||||
*/
|
||||
|
||||
/* length of buffer for dynamic prompt */
|
||||
#define READLINE_MAXPROMPT 512
|
||||
|
||||
static int xioopen_readline(int argc, const char *argv[], struct opt *opts,
|
||||
int rw, xiofile_t *xfd, unsigned groups,
|
||||
int dummy1, int dummy2, int dummy3);
|
||||
|
||||
|
||||
const struct addrdesc addr_readline = {
|
||||
"readline", 3, xioopen_readline, GROUP_FD|GROUP_TERMIOS|GROUP_READLINE, 0, 0, 0 HELP(NULL) };
|
||||
|
||||
const struct optdesc opt_history_file = { "history-file", "history", OPT_HISTORY_FILE, GROUP_READLINE, PH_LATE, TYPE_STRING, OFUNC_OFFSET, (int)&((xiofile_t *)0)->stream.para.readline.history_file };
|
||||
const struct optdesc opt_prompt = { "prompt", NULL, OPT_PROMPT, GROUP_READLINE, PH_LATE, TYPE_STRING, OFUNC_OFFSET, (int)&((xiofile_t *)0)->stream.para.readline.prompt };
|
||||
const struct optdesc opt_noprompt = { "noprompt", NULL, OPT_NOPROMPT, GROUP_READLINE, PH_LATE, TYPE_BOOL, OFUNC_SPEC, 0 };
|
||||
const struct optdesc opt_noecho = { "noecho", NULL, OPT_NOECHO, GROUP_READLINE, PH_LATE, TYPE_STRING, OFUNC_SPEC, 0 };
|
||||
|
||||
static int xioopen_readline(int argc, const char *argv[], struct opt *opts,
|
||||
int xioflags, xiofile_t *xfd, unsigned groups,
|
||||
int dummy1, int dummy2, int dummy3) {
|
||||
int rw = (xioflags & XIO_ACCMODE);
|
||||
char msgbuf[256], *cp = msgbuf;
|
||||
bool noprompt = false;
|
||||
char *noecho = NULL;
|
||||
|
||||
if (argc != 1) {
|
||||
Error1("%s: 0 parameters required", argv[0]);
|
||||
return STAT_NORETRY;
|
||||
}
|
||||
|
||||
if (!(xioflags & XIO_MAYCONVERT)) {
|
||||
Error("address with data processing not allowed here");
|
||||
return STAT_NORETRY;
|
||||
}
|
||||
xfd->common.flags |= XIO_DOESCONVERT;
|
||||
|
||||
strcpy(cp, "using "); cp = strchr(cp, '\0');
|
||||
if ((rw+1)&1) {
|
||||
strcpy(cp, "readline on stdin for reading"); cp = strchr(cp, '\0');
|
||||
|
||||
if ((rw+1)&2)
|
||||
strcpy(cp, " and "); cp = strchr(cp, '\0');
|
||||
}
|
||||
if ((rw+1)&2) {
|
||||
strcpy(cp, "stdio for writing"); cp = strchr(cp, '\0');
|
||||
}
|
||||
Notice(msgbuf);
|
||||
|
||||
xfd->stream.fd = 0; /* stdin */
|
||||
xfd->stream.howtoend = END_NONE;
|
||||
xfd->stream.dtype = XIODATA_READLINE;
|
||||
|
||||
#if WITH_TERMIOS
|
||||
if (Isatty(xfd->stream.fd)) {
|
||||
if (Tcgetattr(xfd->stream.fd, &xfd->stream.savetty) < 0) {
|
||||
Warn2("cannot query current terminal settings on fd %d. %s",
|
||||
xfd->stream.fd, strerror(errno));
|
||||
} else {
|
||||
xfd->stream.ttyvalid = true;
|
||||
}
|
||||
}
|
||||
#endif /* WITH_TERMIOS */
|
||||
|
||||
if (applyopts_single(&xfd->stream, opts, PH_INIT) < 0) return -1;
|
||||
applyopts(-1, opts, PH_INIT);
|
||||
|
||||
applyopts2(xfd->stream.fd, opts, PH_INIT, PH_FD);
|
||||
|
||||
Using_history();
|
||||
applyopts_offset(&xfd->stream, opts);
|
||||
retropt_bool(opts, OPT_NOPROMPT, &noprompt);
|
||||
if (!noprompt && !xfd->stream.para.readline.prompt) {
|
||||
xfd->stream.para.readline.dynbytes = READLINE_MAXPROMPT;
|
||||
xfd->stream.para.readline.dynprompt =
|
||||
Malloc(xfd->stream.para.readline.dynbytes+1);
|
||||
xfd->stream.para.readline.dynend =
|
||||
xfd->stream.para.readline.dynprompt;
|
||||
}
|
||||
|
||||
#if HAVE_REGEX_H
|
||||
retropt_string(opts, OPT_NOECHO, &noecho);
|
||||
if (noecho) {
|
||||
int errcode;
|
||||
char errbuf[128];
|
||||
if ((errcode = regcomp(&xfd->stream.para.readline.noecho, noecho,
|
||||
REG_EXTENDED|REG_NOSUB))
|
||||
!= 0) {
|
||||
regerror(errcode, &xfd->stream.para.readline.noecho,
|
||||
errbuf, sizeof(errbuf));
|
||||
Error3("regcomp(%p, \"%s\", REG_EXTENDED|REG_NOSUB): %s",
|
||||
&xfd->stream.para.readline.noecho, noecho, errbuf);
|
||||
return -1;
|
||||
}
|
||||
xfd->stream.para.readline.hasnoecho = true;
|
||||
}
|
||||
#endif /* HAVE_REGEX_H */
|
||||
if (xfd->stream.para.readline.history_file) {
|
||||
Read_history(xfd->stream.para.readline.history_file);
|
||||
}
|
||||
xiotermios_clrflag(xfd->stream.fd, 3, ICANON);
|
||||
xiotermios_clrflag(xfd->stream.fd, 3, ECHO);
|
||||
return _xio_openlate(&xfd->stream, opts);
|
||||
}
|
||||
|
||||
|
||||
ssize_t xioread_readline(struct single *pipe, void *buff, size_t bufsiz) {
|
||||
/*! indent */
|
||||
ssize_t bytes;
|
||||
char *line;
|
||||
int _errno;
|
||||
|
||||
#if HAVE_REGEX_H
|
||||
if (pipe->para.readline.dynprompt &&
|
||||
pipe->para.readline.hasnoecho &&
|
||||
!regexec(&pipe->para.readline.noecho,
|
||||
pipe->para.readline.dynprompt, 0, NULL, 0)) {
|
||||
/* under these conditions, we do not echo input, thus we circumvent
|
||||
readline */
|
||||
struct termios saveterm, setterm;
|
||||
*pipe->para.readline.dynend = '\0';
|
||||
Tcgetattr(pipe->fd, &saveterm); /*! error */
|
||||
setterm = saveterm;
|
||||
setterm.c_lflag |= ICANON;
|
||||
Tcsetattr(pipe->fd, TCSANOW, &setterm); /*!*/
|
||||
do {
|
||||
bytes = Read(pipe->fd, buff, bufsiz);
|
||||
} while (bytes < 0 && errno == EINTR);
|
||||
if (bytes < 0) {
|
||||
_errno = errno;
|
||||
Error4("read(%d, %p, "F_Zu"): %s",
|
||||
pipe->fd, buff, bufsiz, strerror(_errno));
|
||||
errno = _errno;
|
||||
return -1;
|
||||
}
|
||||
setterm.c_lflag &= ~ICANON;
|
||||
Tcgetattr(pipe->fd, &setterm); /*! error */
|
||||
Tcsetattr(pipe->fd, TCSANOW, &saveterm); /*!*/
|
||||
pipe->para.readline.dynend = pipe->para.readline.dynprompt;
|
||||
/*Write(pipe->fd, "\n", 1);*/ /*!*/
|
||||
return bytes;
|
||||
}
|
||||
#endif /* HAVE_REGEX_H */
|
||||
|
||||
xiotermios_setflag(pipe->fd, 3, ECHO);
|
||||
if (pipe->para.readline.prompt || pipe->para.readline.dynprompt) {
|
||||
/* we must carriage return, because readline will first print the
|
||||
prompt */
|
||||
ssize_t writt;
|
||||
do {
|
||||
writt = Write(pipe->fd, "\r", 1);
|
||||
} while (writt < 0 && errno == EINTR);
|
||||
if (writt < 0) {
|
||||
Warn2("write(%d, \"\\r\", 1): %s",
|
||||
pipe->fd, strerror(errno));
|
||||
} else if (writt < 1) {
|
||||
Warn1("write() only wrote "F_Zu" of 1 byte", writt);
|
||||
}
|
||||
}
|
||||
|
||||
if (pipe->para.readline.dynprompt) {
|
||||
*pipe->para.readline.dynend = '\0';
|
||||
line = Readline(pipe->para.readline.dynprompt);
|
||||
pipe->para.readline.dynend = pipe->para.readline.dynprompt;
|
||||
} else {
|
||||
line = Readline(pipe->para.readline.prompt);
|
||||
}
|
||||
/* GNU readline defines no error return */
|
||||
if (line == NULL) {
|
||||
return 0; /* EOF */
|
||||
}
|
||||
xiotermios_clrflag(pipe->fd, 3, ECHO);
|
||||
Add_history(line);
|
||||
bytes = strlen(line);
|
||||
strncpy(buff, line, bufsiz);
|
||||
free(line);
|
||||
if ((size_t)bytes < bufsiz) {
|
||||
strcat(buff, "\n"); ++bytes;
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
void xioscan_readline(struct single *pipe, const void *buff, size_t bytes) {
|
||||
if (pipe->dtype == XIODATA_READLINE && pipe->para.readline.dynprompt) {
|
||||
/* we save the last part of the output as possible prompt */
|
||||
const void *ptr = buff;
|
||||
const void *pcr = memrchr(buff, '\r', bytes);
|
||||
const void *plf = memrchr(buff, '\n', bytes);
|
||||
size_t len;
|
||||
if (bytes > pipe->para.readline.dynbytes) {
|
||||
ptr = (const char *)buff + bytes - pipe->para.readline.dynbytes;
|
||||
}
|
||||
if (pcr) {
|
||||
/* forget old prompt */
|
||||
pipe->para.readline.dynend = pipe->para.readline.dynprompt;
|
||||
/* new prompt starts here */
|
||||
ptr = (const char *)pcr+1;
|
||||
}
|
||||
if (plf && plf >= ptr) {
|
||||
/* forget old prompt */
|
||||
pipe->para.readline.dynend = pipe->para.readline.dynprompt;
|
||||
/* new prompt starts here */
|
||||
ptr = (const char *)plf+1;
|
||||
}
|
||||
len = (const char *)buff-(const char *)ptr+bytes;
|
||||
if (pipe->para.readline.dynend - pipe->para.readline.dynprompt + len >
|
||||
pipe->para.readline.dynbytes) {
|
||||
memmove(pipe->para.readline.dynprompt,
|
||||
pipe->para.readline.dynend -
|
||||
(pipe->para.readline.dynbytes - len),
|
||||
pipe->para.readline.dynbytes - len);
|
||||
pipe->para.readline.dynend =
|
||||
pipe->para.readline.dynprompt + pipe->para.readline.dynbytes - len;
|
||||
}
|
||||
memcpy(pipe->para.readline.dynend, ptr, len);
|
||||
/*pipe->para.readline.dynend = pipe->para.readline.dynprompt + len;*/
|
||||
pipe->para.readline.dynend = pipe->para.readline.dynend + len;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#endif /* WITH_READLINE */
|
Loading…
Add table
Add a link
Reference in a new issue