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
, int rw
, xiofile_t
*xfd
, const struct addrdesc
*addrdesc
);
31 const struct addrdesc xioaddr_readline
= { "READLINE", 3, xioopen_readline
, GROUP_FD
|GROUP_TERMIOS
|GROUP_READLINE
, 0, 0, 0 HELP(NULL
) };
33 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
) };
34 const struct optdesc opt_prompt
= { "prompt", NULL
, OPT_PROMPT
, GROUP_READLINE
, PH_LATE
, TYPE_STRING
, OFUNC_OFFSET
, XIO_OFFSETOF(para
.readline
.prompt
) };
35 const struct optdesc opt_noprompt
= { "noprompt", NULL
, OPT_NOPROMPT
, GROUP_READLINE
, PH_LATE
, TYPE_BOOL
, OFUNC_SPEC
, 0 };
36 const struct optdesc opt_noecho
= { "noecho", NULL
, OPT_NOECHO
, GROUP_READLINE
, PH_LATE
, TYPE_STRING
, OFUNC_SPEC
, 0 };
38 static int xioopen_readline(
44 const struct addrdesc
*addrdesc
)
46 struct single
*sfd
= &xfd
->stream
;
47 int rw
= (xioflags
& XIO_ACCMODE
);
48 char msgbuf
[256], *cp
= msgbuf
;
49 bool noprompt
= false;
53 xio_syntax(argv
[0], 0, argc
-1, addrdesc
->syntax
);
57 if (!(xioflags
& XIO_MAYCONVERT
)) {
58 Error("address with data processing not allowed here");
61 xfd
->common
.flags
|= XIO_DOESCONVERT
;
63 strcpy(cp
, "using "); cp
= strchr(cp
, '\0');
65 strcpy(cp
, "readline on stdin for reading"); cp
= strchr(cp
, '\0');
69 cp
= strchr(cp
, '\0');
73 strcpy(cp
, "stdio for writing"); cp
= strchr(cp
, '\0');
77 xfd
->stream
.fd
= 0; /* stdin */
78 if (sfd
->howtoend
== END_UNSPEC
)
79 xfd
->stream
.howtoend
= END_NONE
;
80 xfd
->stream
.dtype
= XIODATA_READLINE
;
83 if (Isatty(xfd
->stream
.fd
)) {
84 if (Tcgetattr(xfd
->stream
.fd
, &xfd
->stream
.savetty
) < 0) {
85 Warn2("cannot query current terminal settings on fd %d. %s",
86 xfd
->stream
.fd
, strerror(errno
));
88 xfd
->stream
.ttyvalid
= true;
91 #endif /* WITH_TERMIOS */
93 if (applyopts_single(sfd
, opts
, PH_INIT
) < 0) return -1;
94 applyopts(sfd
, -1, opts
, PH_INIT
);
96 applyopts2(sfd
, -1, opts
, PH_INIT
, PH_FD
);
99 applyopts_offset(&xfd
->stream
, opts
);
100 retropt_bool(opts
, OPT_NOPROMPT
, &noprompt
);
101 if (!noprompt
&& !xfd
->stream
.para
.readline
.prompt
) {
102 xfd
->stream
.para
.readline
.dynbytes
= READLINE_MAXPROMPT
;
103 xfd
->stream
.para
.readline
.dynprompt
=
104 Malloc(xfd
->stream
.para
.readline
.dynbytes
+1);
105 xfd
->stream
.para
.readline
.dynend
=
106 xfd
->stream
.para
.readline
.dynprompt
;
110 retropt_string(opts
, OPT_NOECHO
, &noecho
);
114 if ((errcode
= regcomp(&xfd
->stream
.para
.readline
.noecho
, noecho
,
115 REG_EXTENDED
|REG_NOSUB
))
117 regerror(errcode
, &xfd
->stream
.para
.readline
.noecho
,
118 errbuf
, sizeof(errbuf
));
119 Error3("regcomp(%p, \"%s\", REG_EXTENDED|REG_NOSUB): %s",
120 &xfd
->stream
.para
.readline
.noecho
, noecho
, errbuf
);
123 xfd
->stream
.para
.readline
.hasnoecho
= true;
125 #endif /* HAVE_REGEX_H */
126 if (xfd
->stream
.para
.readline
.history_file
) {
127 Read_history(xfd
->stream
.para
.readline
.history_file
);
130 xiotermios_clrflag(xfd
->stream
.fd
, 3, ICANON
|ECHO
);
131 xiotermios_flush(xfd
->stream
.fd
);
132 #endif /* _WITH_TERMIOS */
133 return _xio_openlate(&xfd
->stream
, opts
);
137 ssize_t
xioread_readline(struct single
*pipe
, void *buff
, size_t bufsiz
) {
144 if (pipe
->para
.readline
.dynprompt
&&
145 pipe
->para
.readline
.hasnoecho
&&
146 !regexec(&pipe
->para
.readline
.noecho
,
147 pipe
->para
.readline
.dynprompt
, 0, NULL
, 0)) {
149 /* under these conditions, we do not echo input, thus we circumvent
151 struct termios saveterm
, setterm
;
152 *pipe
->para
.readline
.dynend
= '\0';
153 Tcgetattr(pipe
->fd
, &saveterm
); /*! error */
155 setterm
.c_lflag
|= ICANON
;
156 Tcsetattr(pipe
->fd
, TCSANOW
, &setterm
); /*!*/
157 #endif /* _WITH_TERMIOS */
159 bytes
= Read(pipe
->fd
, buff
, bufsiz
);
160 } while (bytes
< 0 && errno
== EINTR
);
163 Error4("read(%d, %p, "F_Zu
"): %s",
164 pipe
->fd
, buff
, bufsiz
, strerror(_errno
));
169 setterm
.c_lflag
&= ~ICANON
;
170 Tcgetattr(pipe
->fd
, &setterm
); /*! error */
171 Tcsetattr(pipe
->fd
, TCSANOW
, &saveterm
); /*!*/
172 #endif /* _WITH_TERMIOS */
173 pipe
->para
.readline
.dynend
= pipe
->para
.readline
.dynprompt
;
174 /*Write(pipe->fd, "\n", 1);*/ /*!*/
177 #endif /* HAVE_REGEX_H */
180 xiotermios_setflag(pipe
->fd
, 3, ECHO
);
181 xiotermios_flush(pipe
->fd
);
182 #endif /* _WITH_TERMIOS */
183 if (pipe
->para
.readline
.prompt
|| pipe
->para
.readline
.dynprompt
) {
184 /* we must carriage return, because readline will first print the
187 writt
= writefull(pipe
->fd
, "\r", 1);
189 Warn2("write(%d, \"\\r\", 1): %s",
190 pipe
->fd
, strerror(errno
));
191 } else if (writt
< 1) {
192 Warn1("write() only wrote "F_Zu
" of 1 byte", writt
);
196 if (pipe
->para
.readline
.dynprompt
) {
197 *pipe
->para
.readline
.dynend
= '\0';
198 line
= Readline(pipe
->para
.readline
.dynprompt
);
199 pipe
->para
.readline
.dynend
= pipe
->para
.readline
.dynprompt
;
201 line
= Readline(pipe
->para
.readline
.prompt
);
203 /* GNU readline defines no error return */
208 xiotermios_clrflag(pipe
->fd
, 3, ECHO
);
209 xiotermios_flush(pipe
->fd
);
210 #endif /* _WITH_TERMIOS */
212 bytes
= strlen(line
);
213 ((char *)buff
)[0] = '\0'; strncat(buff
, line
, bufsiz
-1);
215 if ((size_t)bytes
< bufsiz
) {
216 strcat(buff
, "\n"); ++bytes
;
221 void xioscan_readline(struct single
*pipe
, const void *buff
, size_t bytes
) {
222 if (pipe
->dtype
== XIODATA_READLINE
&& pipe
->para
.readline
.dynprompt
) {
223 /* we save the last part of the output as possible prompt */
224 const void *ptr
= buff
;
229 if (bytes
> pipe
->para
.readline
.dynbytes
) {
230 ptr
= (const char *)buff
+ bytes
- pipe
->para
.readline
.dynbytes
;
231 len
= pipe
->para
.readline
.dynbytes
;
235 pcr
= memrchr(ptr
, '\r', len
);
236 plf
= memrchr(ptr
, '\n', len
);
237 if (pcr
!= NULL
|| plf
!= NULL
) {
238 const void *peol
= Max(pcr
, plf
);
239 /* forget old prompt */
240 pipe
->para
.readline
.dynend
= pipe
->para
.readline
.dynprompt
;
241 len
-= (peol
+1 - ptr
);
242 /* new prompt starts here */
243 ptr
= (const char *)peol
+1;
245 if (pipe
->para
.readline
.dynend
- pipe
->para
.readline
.dynprompt
+ len
>
246 pipe
->para
.readline
.dynbytes
) {
247 memmove(pipe
->para
.readline
.dynprompt
,
248 pipe
->para
.readline
.dynend
-
249 (pipe
->para
.readline
.dynbytes
- len
),
250 pipe
->para
.readline
.dynbytes
- len
);
251 pipe
->para
.readline
.dynend
=
252 pipe
->para
.readline
.dynprompt
+ pipe
->para
.readline
.dynbytes
- len
;
254 memcpy(pipe
->para
.readline
.dynend
, ptr
, len
);
255 pipe
->para
.readline
.dynend
= pipe
->para
.readline
.dynend
+ len
;
260 #endif /* WITH_READLINE */