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"
10 #include "xio-termios.h"
11 #include "xio-readline.h"
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;
50 Error1("%s: 0 parameters required", argv
[0]);
54 if (!(xioflags
& XIO_MAYCONVERT
)) {
55 Error("address with data processing not allowed here");
58 xfd
->common
.flags
|= XIO_DOESCONVERT
;
60 strcpy(cp
, "using "); cp
= strchr(cp
, '\0');
62 strcpy(cp
, "readline on stdin for reading"); cp
= strchr(cp
, '\0');
66 cp
= strchr(cp
, '\0');
70 strcpy(cp
, "stdio for writing"); cp
= strchr(cp
, '\0');
74 xfd
->stream
.fd
= 0; /* stdin */
75 xfd
->stream
.howtoend
= END_NONE
;
76 xfd
->stream
.dtype
= XIODATA_READLINE
;
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
));
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
);
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
;
106 retropt_string(opts
, OPT_NOECHO
, &noecho
);
110 if ((errcode
= regcomp(&xfd
->stream
.para
.readline
.noecho
, noecho
,
111 REG_EXTENDED
|REG_NOSUB
))
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
);
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
);
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
) {
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)) {
145 /* under these conditions, we do not echo input, thus we circumvent
147 struct termios saveterm
, setterm
;
148 *pipe
->para
.readline
.dynend
= '\0';
149 Tcgetattr(pipe
->fd
, &saveterm
); /*! error */
151 setterm
.c_lflag
|= ICANON
;
152 Tcsetattr(pipe
->fd
, TCSANOW
, &setterm
); /*!*/
153 #endif /* _WITH_TERMIOS */
155 bytes
= Read(pipe
->fd
, buff
, bufsiz
);
156 } while (bytes
< 0 && errno
== EINTR
);
159 Error4("read(%d, %p, "F_Zu
"): %s",
160 pipe
->fd
, buff
, bufsiz
, strerror(_errno
));
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);*/ /*!*/
173 #endif /* HAVE_REGEX_H */
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
183 writt
= writefull(pipe
->fd
, "\r", 1);
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
;
197 line
= Readline(pipe
->para
.readline
.prompt
);
199 /* GNU readline defines no error return */
204 xiotermios_clrflag(pipe
->fd
, 3, ECHO
);
205 xiotermios_flush(pipe
->fd
);
206 #endif /* _WITH_TERMIOS */
208 bytes
= strlen(line
);
209 ((char *)buff
)[0] = '\0'; strncat(buff
, line
, bufsiz
-1);
211 if ((size_t)bytes
< bufsiz
) {
212 strcat(buff
, "\n"); ++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
;
225 if (bytes
> pipe
->para
.readline
.dynbytes
) {
226 ptr
= (const char *)buff
+ bytes
- pipe
->para
.readline
.dynbytes
;
227 len
= pipe
->para
.readline
.dynbytes
;
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
;
256 #endif /* WITH_READLINE */