1 /* source: xio-readline.c */
2 /* Copyright Gerhard Rieger */
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');
65 strcpy(cp
, " and "); cp
= strchr(cp
, '\0');
68 strcpy(cp
, "stdio for writing"); cp
= strchr(cp
, '\0');
72 xfd
->stream
.fd
= 0; /* stdin */
73 xfd
->stream
.howtoend
= END_NONE
;
74 xfd
->stream
.dtype
= XIODATA_READLINE
;
77 if (Isatty(xfd
->stream
.fd
)) {
78 if (Tcgetattr(xfd
->stream
.fd
, &xfd
->stream
.savetty
) < 0) {
79 Warn2("cannot query current terminal settings on fd %d. %s",
80 xfd
->stream
.fd
, strerror(errno
));
82 xfd
->stream
.ttyvalid
= true;
85 #endif /* WITH_TERMIOS */
87 if (applyopts_single(&xfd
->stream
, opts
, PH_INIT
) < 0) return -1;
88 applyopts(-1, opts
, PH_INIT
);
90 applyopts2(xfd
->stream
.fd
, opts
, PH_INIT
, PH_FD
);
93 applyopts_offset(&xfd
->stream
, opts
);
94 retropt_bool(opts
, OPT_NOPROMPT
, &noprompt
);
95 if (!noprompt
&& !xfd
->stream
.para
.readline
.prompt
) {
96 xfd
->stream
.para
.readline
.dynbytes
= READLINE_MAXPROMPT
;
97 xfd
->stream
.para
.readline
.dynprompt
=
98 Malloc(xfd
->stream
.para
.readline
.dynbytes
+1);
99 xfd
->stream
.para
.readline
.dynend
=
100 xfd
->stream
.para
.readline
.dynprompt
;
104 retropt_string(opts
, OPT_NOECHO
, &noecho
);
108 if ((errcode
= regcomp(&xfd
->stream
.para
.readline
.noecho
, noecho
,
109 REG_EXTENDED
|REG_NOSUB
))
111 regerror(errcode
, &xfd
->stream
.para
.readline
.noecho
,
112 errbuf
, sizeof(errbuf
));
113 Error3("regcomp(%p, \"%s\", REG_EXTENDED|REG_NOSUB): %s",
114 &xfd
->stream
.para
.readline
.noecho
, noecho
, errbuf
);
117 xfd
->stream
.para
.readline
.hasnoecho
= true;
119 #endif /* HAVE_REGEX_H */
120 if (xfd
->stream
.para
.readline
.history_file
) {
121 Read_history(xfd
->stream
.para
.readline
.history_file
);
124 xiotermios_clrflag(xfd
->stream
.fd
, 3, ICANON
);
125 xiotermios_clrflag(xfd
->stream
.fd
, 3, ECHO
);
126 #endif /* _WITH_TERMIOS */
127 return _xio_openlate(&xfd
->stream
, opts
);
131 ssize_t
xioread_readline(struct single
*pipe
, void *buff
, size_t bufsiz
) {
138 if (pipe
->para
.readline
.dynprompt
&&
139 pipe
->para
.readline
.hasnoecho
&&
140 !regexec(&pipe
->para
.readline
.noecho
,
141 pipe
->para
.readline
.dynprompt
, 0, NULL
, 0)) {
143 /* under these conditions, we do not echo input, thus we circumvent
145 struct termios saveterm
, setterm
;
146 *pipe
->para
.readline
.dynend
= '\0';
147 Tcgetattr(pipe
->fd
, &saveterm
); /*! error */
149 setterm
.c_lflag
|= ICANON
;
150 Tcsetattr(pipe
->fd
, TCSANOW
, &setterm
); /*!*/
151 #endif /* _WITH_TERMIOS */
153 bytes
= Read(pipe
->fd
, buff
, bufsiz
);
154 } while (bytes
< 0 && errno
== EINTR
);
157 Error4("read(%d, %p, "F_Zu
"): %s",
158 pipe
->fd
, buff
, bufsiz
, strerror(_errno
));
163 setterm
.c_lflag
&= ~ICANON
;
164 Tcgetattr(pipe
->fd
, &setterm
); /*! error */
165 Tcsetattr(pipe
->fd
, TCSANOW
, &saveterm
); /*!*/
166 #endif /* _WITH_TERMIOS */
167 pipe
->para
.readline
.dynend
= pipe
->para
.readline
.dynprompt
;
168 /*Write(pipe->fd, "\n", 1);*/ /*!*/
171 #endif /* HAVE_REGEX_H */
174 xiotermios_setflag(pipe
->fd
, 3, ECHO
);
175 #endif /* _WITH_TERMIOS */
176 if (pipe
->para
.readline
.prompt
|| pipe
->para
.readline
.dynprompt
) {
177 /* we must carriage return, because readline will first print the
180 writt
= writefull(pipe
->fd
, "\r", 1);
182 Warn2("write(%d, \"\\r\", 1): %s",
183 pipe
->fd
, strerror(errno
));
184 } else if (writt
< 1) {
185 Warn1("write() only wrote "F_Zu
" of 1 byte", writt
);
189 if (pipe
->para
.readline
.dynprompt
) {
190 *pipe
->para
.readline
.dynend
= '\0';
191 line
= Readline(pipe
->para
.readline
.dynprompt
);
192 pipe
->para
.readline
.dynend
= pipe
->para
.readline
.dynprompt
;
194 line
= Readline(pipe
->para
.readline
.prompt
);
196 /* GNU readline defines no error return */
201 xiotermios_clrflag(pipe
->fd
, 3, ECHO
);
202 #endif /* _WITH_TERMIOS */
204 bytes
= strlen(line
);
205 ((char *)buff
)[0] = '\0'; strncat(buff
, line
, bufsiz
-1);
207 if ((size_t)bytes
< bufsiz
) {
208 strcat(buff
, "\n"); ++bytes
;
213 void xioscan_readline(struct single
*pipe
, const void *buff
, size_t bytes
) {
214 if (pipe
->dtype
== XIODATA_READLINE
&& pipe
->para
.readline
.dynprompt
) {
215 /* we save the last part of the output as possible prompt */
216 const void *ptr
= buff
;
221 if (bytes
> pipe
->para
.readline
.dynbytes
) {
222 ptr
= (const char *)buff
+ bytes
- pipe
->para
.readline
.dynbytes
;
223 len
= pipe
->para
.readline
.dynbytes
;
227 pcr
= memrchr(ptr
, '\r', len
);
228 plf
= memrchr(ptr
, '\n', len
);
229 if (pcr
!= NULL
|| plf
!= NULL
) {
230 const void *peol
= Max(pcr
, plf
);
231 /* forget old prompt */
232 pipe
->para
.readline
.dynend
= pipe
->para
.readline
.dynprompt
;
233 len
-= (peol
+1 - ptr
);
234 /* new prompt starts here */
235 ptr
= (const char *)peol
+1;
237 if (pipe
->para
.readline
.dynend
- pipe
->para
.readline
.dynprompt
+ len
>
238 pipe
->para
.readline
.dynbytes
) {
239 memmove(pipe
->para
.readline
.dynprompt
,
240 pipe
->para
.readline
.dynend
-
241 (pipe
->para
.readline
.dynbytes
- len
),
242 pipe
->para
.readline
.dynbytes
- len
);
243 pipe
->para
.readline
.dynend
=
244 pipe
->para
.readline
.dynprompt
+ pipe
->para
.readline
.dynbytes
- len
;
246 memcpy(pipe
->para
.readline
.dynend
, ptr
, len
);
247 pipe
->para
.readline
.dynend
= pipe
->para
.readline
.dynend
+ len
;
252 #endif /* WITH_READLINE */