1 /* source: xio-readline.c */
2 /* Copyright Gerhard Rieger 2002-2008 */
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
, (int)&((xiofile_t
*)0)->stream
.para
.readline
.history_file
};
37 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
};
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
181 writt
= Write(pipe
->fd
, "\r", 1);
182 } while (writt
< 0 && errno
== EINTR
);
184 Warn2("write(%d, \"\\r\", 1): %s",
185 pipe
->fd
, strerror(errno
));
186 } else if (writt
< 1) {
187 Warn1("write() only wrote "F_Zu
" of 1 byte", writt
);
191 if (pipe
->para
.readline
.dynprompt
) {
192 *pipe
->para
.readline
.dynend
= '\0';
193 line
= Readline(pipe
->para
.readline
.dynprompt
);
194 pipe
->para
.readline
.dynend
= pipe
->para
.readline
.dynprompt
;
196 line
= Readline(pipe
->para
.readline
.prompt
);
198 /* GNU readline defines no error return */
203 xiotermios_clrflag(pipe
->fd
, 3, ECHO
);
204 #endif /* _WITH_TERMIOS */
206 bytes
= strlen(line
);
207 strncpy(buff
, line
, bufsiz
);
209 if ((size_t)bytes
< bufsiz
) {
210 strcat(buff
, "\n"); ++bytes
;
215 void xioscan_readline(struct single
*pipe
, const void *buff
, size_t bytes
) {
216 if (pipe
->dtype
== XIODATA_READLINE
&& pipe
->para
.readline
.dynprompt
) {
217 /* we save the last part of the output as possible prompt */
218 const void *ptr
= buff
;
219 const void *pcr
= memrchr(buff
, '\r', bytes
);
220 const void *plf
= memrchr(buff
, '\n', bytes
);
222 if (bytes
> pipe
->para
.readline
.dynbytes
) {
223 ptr
= (const char *)buff
+ bytes
- pipe
->para
.readline
.dynbytes
;
226 /* forget old prompt */
227 pipe
->para
.readline
.dynend
= pipe
->para
.readline
.dynprompt
;
228 /* new prompt starts here */
229 ptr
= (const char *)pcr
+1;
231 if (plf
&& plf
>= ptr
) {
232 /* forget old prompt */
233 pipe
->para
.readline
.dynend
= pipe
->para
.readline
.dynprompt
;
234 /* new prompt starts here */
235 ptr
= (const char *)plf
+1;
237 len
= (const char *)buff
-(const char *)ptr
+bytes
;
238 if (pipe
->para
.readline
.dynend
- pipe
->para
.readline
.dynprompt
+ len
>
239 pipe
->para
.readline
.dynbytes
) {
240 memmove(pipe
->para
.readline
.dynprompt
,
241 pipe
->para
.readline
.dynend
-
242 (pipe
->para
.readline
.dynbytes
- len
),
243 pipe
->para
.readline
.dynbytes
- len
);
244 pipe
->para
.readline
.dynend
=
245 pipe
->para
.readline
.dynprompt
+ pipe
->para
.readline
.dynbytes
- len
;
247 memcpy(pipe
->para
.readline
.dynend
, ptr
, len
);
248 /*pipe->para.readline.dynend = pipe->para.readline.dynprompt + len;*/
249 pipe
->para
.readline
.dynend
= pipe
->para
.readline
.dynend
+ len
;
254 #endif /* WITH_READLINE */