More corrections to test.sh: language; netstat; reuseaddr; usleep; force IPv4; timeout
[socat.git] / xio-readline.c
blob0fbbb8886306e0044d11af005f051a0e615c2ab6
1 /* source: xio-readline.c */
2 /* Copyright Gerhard Rieger and contributors (see file CHANGES) */
3 /* Published under the GNU General Public License V.2, see file COPYING */
5 /* this file contains the source for opening the readline address */
7 #include "xiosysincludes.h"
8 #include "xioopen.h"
10 #include "xio-termios.h"
11 #include "xio-readline.h"
14 #if WITH_READLINE
17 options: history file
18 prompt
19 mode=vi?
20 inputrc=?
22 uses stdin!!
25 /* length of buffer for dynamic prompt */
26 #define READLINE_MAXPROMPT 512
28 static int xioopen_readline(int argc, const char *argv[], struct opt *opts,
29 int rw, xiofile_t *xfd, unsigned groups,
30 int dummy1, int dummy2, int dummy3);
33 const struct addrdesc addr_readline = {
34 "readline", 3, xioopen_readline, GROUP_FD|GROUP_TERMIOS|GROUP_READLINE, 0, 0, 0 HELP(NULL) };
36 const struct optdesc opt_history_file = { "history-file", "history", OPT_HISTORY_FILE, GROUP_READLINE, PH_LATE, TYPE_STRING, OFUNC_OFFSET, XIO_OFFSETOF(para.readline.history_file) };
37 const struct optdesc opt_prompt = { "prompt", NULL, OPT_PROMPT, GROUP_READLINE, PH_LATE, TYPE_STRING, OFUNC_OFFSET, XIO_OFFSETOF(para.readline.prompt) };
38 const struct optdesc opt_noprompt = { "noprompt", NULL, OPT_NOPROMPT, GROUP_READLINE, PH_LATE, TYPE_BOOL, OFUNC_SPEC, 0 };
39 const struct optdesc opt_noecho = { "noecho", NULL, OPT_NOECHO, GROUP_READLINE, PH_LATE, TYPE_STRING, OFUNC_SPEC, 0 };
41 static int xioopen_readline(int argc, const char *argv[], struct opt *opts,
42 int xioflags, xiofile_t *xfd, unsigned groups,
43 int dummy1, int dummy2, int dummy3) {
44 int rw = (xioflags & XIO_ACCMODE);
45 char msgbuf[256], *cp = msgbuf;
46 bool noprompt = false;
47 char *noecho = NULL;
49 if (argc != 1) {
50 Error1("%s: 0 parameters required", argv[0]);
51 return STAT_NORETRY;
54 if (!(xioflags & XIO_MAYCONVERT)) {
55 Error("address with data processing not allowed here");
56 return STAT_NORETRY;
58 xfd->common.flags |= XIO_DOESCONVERT;
60 strcpy(cp, "using "); cp = strchr(cp, '\0');
61 if ((rw+1)&1) {
62 strcpy(cp, "readline on stdin for reading"); cp = strchr(cp, '\0');
64 if ((rw+1)&2) {
65 strcpy(cp, " and ");
66 cp = strchr(cp, '\0');
69 if ((rw+1)&2) {
70 strcpy(cp, "stdio for writing"); cp = strchr(cp, '\0');
72 Notice(msgbuf);
74 xfd->stream.fd = 0; /* stdin */
75 xfd->stream.howtoend = END_NONE;
76 xfd->stream.dtype = XIODATA_READLINE;
78 #if WITH_TERMIOS
79 if (Isatty(xfd->stream.fd)) {
80 if (Tcgetattr(xfd->stream.fd, &xfd->stream.savetty) < 0) {
81 Warn2("cannot query current terminal settings on fd %d. %s",
82 xfd->stream.fd, strerror(errno));
83 } else {
84 xfd->stream.ttyvalid = true;
87 #endif /* WITH_TERMIOS */
89 if (applyopts_single(&xfd->stream, opts, PH_INIT) < 0) return -1;
90 applyopts(-1, opts, PH_INIT);
92 applyopts2(xfd->stream.fd, opts, PH_INIT, PH_FD);
94 Using_history();
95 applyopts_offset(&xfd->stream, opts);
96 retropt_bool(opts, OPT_NOPROMPT, &noprompt);
97 if (!noprompt && !xfd->stream.para.readline.prompt) {
98 xfd->stream.para.readline.dynbytes = READLINE_MAXPROMPT;
99 xfd->stream.para.readline.dynprompt =
100 Malloc(xfd->stream.para.readline.dynbytes+1);
101 xfd->stream.para.readline.dynend =
102 xfd->stream.para.readline.dynprompt;
105 #if HAVE_REGEX_H
106 retropt_string(opts, OPT_NOECHO, &noecho);
107 if (noecho) {
108 int errcode;
109 char errbuf[128];
110 if ((errcode = regcomp(&xfd->stream.para.readline.noecho, noecho,
111 REG_EXTENDED|REG_NOSUB))
112 != 0) {
113 regerror(errcode, &xfd->stream.para.readline.noecho,
114 errbuf, sizeof(errbuf));
115 Error3("regcomp(%p, \"%s\", REG_EXTENDED|REG_NOSUB): %s",
116 &xfd->stream.para.readline.noecho, noecho, errbuf);
117 return -1;
119 xfd->stream.para.readline.hasnoecho = true;
121 #endif /* HAVE_REGEX_H */
122 if (xfd->stream.para.readline.history_file) {
123 Read_history(xfd->stream.para.readline.history_file);
125 #if _WITH_TERMIOS
126 xiotermios_clrflag(xfd->stream.fd, 3, ICANON|ECHO);
127 xiotermios_flush(xfd->stream.fd);
128 #endif /* _WITH_TERMIOS */
129 return _xio_openlate(&xfd->stream, opts);
133 ssize_t xioread_readline(struct single *pipe, void *buff, size_t bufsiz) {
134 /*! indent */
135 ssize_t bytes;
136 char *line;
137 int _errno;
139 #if HAVE_REGEX_H
140 if (pipe->para.readline.dynprompt &&
141 pipe->para.readline.hasnoecho &&
142 !regexec(&pipe->para.readline.noecho,
143 pipe->para.readline.dynprompt, 0, NULL, 0)) {
144 #if _WITH_TERMIOS
145 /* under these conditions, we do not echo input, thus we circumvent
146 readline */
147 struct termios saveterm, setterm;
148 *pipe->para.readline.dynend = '\0';
149 Tcgetattr(pipe->fd, &saveterm); /*! error */
150 setterm = saveterm;
151 setterm.c_lflag |= ICANON;
152 Tcsetattr(pipe->fd, TCSANOW, &setterm); /*!*/
153 #endif /* _WITH_TERMIOS */
154 do {
155 bytes = Read(pipe->fd, buff, bufsiz);
156 } while (bytes < 0 && errno == EINTR);
157 if (bytes < 0) {
158 _errno = errno;
159 Error4("read(%d, %p, "F_Zu"): %s",
160 pipe->fd, buff, bufsiz, strerror(_errno));
161 errno = _errno;
162 return -1;
164 #if _WITH_TERMIOS
165 setterm.c_lflag &= ~ICANON;
166 Tcgetattr(pipe->fd, &setterm); /*! error */
167 Tcsetattr(pipe->fd, TCSANOW, &saveterm); /*!*/
168 #endif /* _WITH_TERMIOS */
169 pipe->para.readline.dynend = pipe->para.readline.dynprompt;
170 /*Write(pipe->fd, "\n", 1);*/ /*!*/
171 return bytes;
173 #endif /* HAVE_REGEX_H */
175 #if _WITH_TERMIOS
176 xiotermios_setflag(pipe->fd, 3, ECHO);
177 xiotermios_flush(pipe->fd);
178 #endif /* _WITH_TERMIOS */
179 if (pipe->para.readline.prompt || pipe->para.readline.dynprompt) {
180 /* we must carriage return, because readline will first print the
181 prompt */
182 ssize_t writt;
183 writt = writefull(pipe->fd, "\r", 1);
184 if (writt < 0) {
185 Warn2("write(%d, \"\\r\", 1): %s",
186 pipe->fd, strerror(errno));
187 } else if (writt < 1) {
188 Warn1("write() only wrote "F_Zu" of 1 byte", writt);
192 if (pipe->para.readline.dynprompt) {
193 *pipe->para.readline.dynend = '\0';
194 line = Readline(pipe->para.readline.dynprompt);
195 pipe->para.readline.dynend = pipe->para.readline.dynprompt;
196 } else {
197 line = Readline(pipe->para.readline.prompt);
199 /* GNU readline defines no error return */
200 if (line == NULL) {
201 return 0; /* EOF */
203 #if _WITH_TERMIOS
204 xiotermios_clrflag(pipe->fd, 3, ECHO);
205 xiotermios_flush(pipe->fd);
206 #endif /* _WITH_TERMIOS */
207 Add_history(line);
208 bytes = strlen(line);
209 ((char *)buff)[0] = '\0'; strncat(buff, line, bufsiz-1);
210 free(line);
211 if ((size_t)bytes < bufsiz) {
212 strcat(buff, "\n"); ++bytes;
214 return bytes;
217 void xioscan_readline(struct single *pipe, const void *buff, size_t bytes) {
218 if (pipe->dtype == XIODATA_READLINE && pipe->para.readline.dynprompt) {
219 /* we save the last part of the output as possible prompt */
220 const void *ptr = buff;
221 const void *pcr;
222 const void *plf;
223 size_t len;
225 if (bytes > pipe->para.readline.dynbytes) {
226 ptr = (const char *)buff + bytes - pipe->para.readline.dynbytes;
227 len = pipe->para.readline.dynbytes;
228 } else {
229 len = bytes;
231 pcr = memrchr(ptr, '\r', len);
232 plf = memrchr(ptr, '\n', len);
233 if (pcr != NULL || plf != NULL) {
234 const void *peol = Max(pcr, plf);
235 /* forget old prompt */
236 pipe->para.readline.dynend = pipe->para.readline.dynprompt;
237 len -= (peol+1 - ptr);
238 /* new prompt starts here */
239 ptr = (const char *)peol+1;
241 if (pipe->para.readline.dynend - pipe->para.readline.dynprompt + len >
242 pipe->para.readline.dynbytes) {
243 memmove(pipe->para.readline.dynprompt,
244 pipe->para.readline.dynend -
245 (pipe->para.readline.dynbytes - len),
246 pipe->para.readline.dynbytes - len);
247 pipe->para.readline.dynend =
248 pipe->para.readline.dynprompt + pipe->para.readline.dynbytes - len;
250 memcpy(pipe->para.readline.dynend, ptr, len);
251 pipe->para.readline.dynend = pipe->para.readline.dynend + len;
253 return;
256 #endif /* WITH_READLINE */