nexmon – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /* source: xio-readline.c */
2 /* Copyright Gerhard Rieger */
3 /* Published under the GNU General Public License V.2, see file COPYING */
4  
5 /* this file contains the source for opening the readline address */
6  
7 #include "xiosysincludes.h"
8 #include "xioopen.h"
9  
10 #include "xio-termios.h"
11 #include "xio-readline.h"
12  
13  
14 #if WITH_READLINE
15  
16 /*
17 options: history file
18 prompt
19 mode=vi?
20 inputrc=?
21  
22 uses stdin!!
23 */
24  
25 /* length of buffer for dynamic prompt */
26 #define READLINE_MAXPROMPT 512
27  
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);
31  
32  
33 static const struct xioaddr_endpoint_desc xioendpoint_readline0 = {
34 XIOADDR_SYS, "readline", 0, XIOBIT_RDONLY|XIOBIT_RDWR, GROUP_FD|GROUP_TERMIOS|GROUP_READLINE, XIOSHUT_CLOSE, XIOCLOSE_NONE, xioopen_readline, 0, 0, 0 HELP(NULL) };
35  
36 const union xioaddr_desc *xioaddrs_readline[] = {
37 (union xioaddr_desc *)&xioendpoint_readline0,
38 NULL
39 };
40  
41 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) };
42 const struct optdesc opt_prompt = { "prompt", NULL, OPT_PROMPT, GROUP_READLINE, PH_LATE, TYPE_STRING, OFUNC_OFFSET, XIO_OFFSETOF(para.readline.prompt) };
43 const struct optdesc opt_noprompt = { "noprompt", NULL, OPT_NOPROMPT, GROUP_READLINE, PH_LATE, TYPE_BOOL, OFUNC_SPEC, 0 };
44 const struct optdesc opt_noecho = { "noecho", NULL, OPT_NOECHO, GROUP_READLINE, PH_LATE, TYPE_STRING, OFUNC_SPEC, 0 };
45  
46 static int xioopen_readline(int argc, const char *argv[], struct opt *opts,
47 int xioflags, xiofile_t *xfd, unsigned groups,
48 int dummy1, int dummy2, int dummy3) {
49 int rw = (xioflags & XIO_ACCMODE);
50 char msgbuf[256], *cp = msgbuf;
51 bool noprompt = false;
52 char *noecho = NULL;
53  
54 if (argc != 1) {
55 Error1("%s: 0 parameters required", argv[0]);
56 return STAT_NORETRY;
57 }
58  
59 if (!(xioflags & XIO_MAYCONVERT)) {
60 Error("address with data processing not allowed here");
61 return STAT_NORETRY;
62 }
63 xfd->common.flags |= XIO_DOESCONVERT;
64  
65 strcpy(cp, "using "); cp = strchr(cp, '\0');
66 if (XIOWITHRD(rw)) {
67 strcpy(cp, "readline on stdin for reading"); cp = strchr(cp, '\0');
68  
69 if (XIOWITHWR(rw))
70 strcpy(cp, " and "); cp = strchr(cp, '\0');
71 }
72 if (XIOWITHWR(rw)) {
73 strcpy(cp, "stdio for writing"); cp = strchr(cp, '\0');
74 }
75 Notice(msgbuf);
76  
77 xfd->stream.rfd = 0; /* stdin */
78 if (XIOWITHWR(rw)) {
79 xfd->stream.wfd = 1; /* stdout */
80 }
81 xfd->stream.howtoclose = XIOCLOSE_READLINE;
82 xfd->stream.dtype = XIODATA_READLINE;
83  
84 #if WITH_TERMIOS
85 if (Isatty(xfd->stream.rfd)) {
86 if (Tcgetattr(xfd->stream.rfd, &xfd->stream.savetty) < 0) {
87 Warn2("cannot query current terminal settings on fd %d. %s",
88 xfd->stream.rfd, strerror(errno));
89 } else {
90 xfd->stream.ttyvalid = true;
91 }
92 }
93 #endif /* WITH_TERMIOS */
94  
95 if (applyopts_single(&xfd->stream, opts, PH_INIT) < 0) return -1;
96 applyopts(-1, opts, PH_INIT);
97  
98 applyopts2(xfd->stream.rfd, opts, PH_INIT, PH_FD);
99  
100 Using_history();
101 applyopts_offset(&xfd->stream, opts);
102 retropt_bool(opts, OPT_NOPROMPT, &noprompt);
103 if (!noprompt && !xfd->stream.para.readline.prompt) {
104 xfd->stream.para.readline.dynbytes = READLINE_MAXPROMPT;
105 xfd->stream.para.readline.dynprompt =
106 Malloc(xfd->stream.para.readline.dynbytes+1);
107 xfd->stream.para.readline.dynend =
108 xfd->stream.para.readline.dynprompt;
109 }
110  
111 #if HAVE_REGEX_H
112 retropt_string(opts, OPT_NOECHO, &noecho);
113 if (noecho) {
114 int errcode;
115 char errbuf[128];
116 if ((errcode = regcomp(&xfd->stream.para.readline.noecho, noecho,
117 REG_EXTENDED|REG_NOSUB))
118 != 0) {
119 regerror(errcode, &xfd->stream.para.readline.noecho,
120 errbuf, sizeof(errbuf));
121 Error3("regcomp(%p, \"%s\", REG_EXTENDED|REG_NOSUB): %s",
122 &xfd->stream.para.readline.noecho, noecho, errbuf);
123 return -1;
124 }
125 xfd->stream.para.readline.hasnoecho = true;
126 }
127 #endif /* HAVE_REGEX_H */
128 if (xfd->stream.para.readline.history_file) {
129 Read_history(xfd->stream.para.readline.history_file);
130 }
131 #if _WITH_TERMIOS
132 xiotermios_clrflag(xfd->stream.rfd, 3, ICANON);
133 xiotermios_clrflag(xfd->stream.rfd, 3, ECHO);
134 #endif /* _WITH_TERMIOS */
135 return _xio_openlate(&xfd->stream, opts);
136 }
137  
138  
139 ssize_t xioread_readline(struct single *pipe, void *buff, size_t bufsiz) {
140 /*! indent */
141 ssize_t bytes;
142 char *line;
143 int _errno;
144  
145 #if HAVE_REGEX_H
146 if (pipe->para.readline.dynprompt &&
147 pipe->para.readline.hasnoecho &&
148 !regexec(&pipe->para.readline.noecho,
149 pipe->para.readline.dynprompt, 0, NULL, 0)) {
150 #if _WITH_TERMIOS
151 /* under these conditions, we do not echo input, thus we circumvent
152 readline */
153 struct termios saveterm, setterm;
154 *pipe->para.readline.dynend = '\0';
155 Tcgetattr(pipe->rfd, &saveterm); /*! error */
156 setterm = saveterm;
157 setterm.c_lflag |= ICANON;
158 Tcsetattr(pipe->rfd, TCSANOW, &setterm); /*!*/
159 #endif /* _WITH_TERMIOS */
160 do {
161 bytes = Read(pipe->rfd, buff, bufsiz);
162 } while (bytes < 0 && errno == EINTR);
163 if (bytes < 0) {
164 _errno = errno;
165 Error4("read(%d, %p, "F_Zu"): %s",
166 pipe->rfd, buff, bufsiz, strerror(_errno));
167 errno = _errno;
168 return -1;
169 }
170 #if _WITH_TERMIOS
171 setterm.c_lflag &= ~ICANON;
172 Tcgetattr(pipe->rfd, &setterm); /*! error */
173 Tcsetattr(pipe->rfd, TCSANOW, &saveterm); /*!*/
174 #endif /* _WITH_TERMIOS */
175 pipe->para.readline.dynend = pipe->para.readline.dynprompt;
176 /*Write(pipe->rfd, "\n", 1);*/ /*!*/
177 return bytes;
178 }
179 #endif /* HAVE_REGEX_H */
180  
181 #if _WITH_TERMIOS
182 xiotermios_setflag(pipe->rfd, 3, ECHO);
183 #endif /* _WITH_TERMIOS */
184 if (pipe->para.readline.prompt || pipe->para.readline.dynprompt) {
185 /* we must carriage return, because readline will first print the
186 prompt */
187 ssize_t writt;
188 writt = writefull(pipe->rfd, "\r", 1);
189 if (writt < 0) {
190 Warn2("write(%d, \"\\r\", 1): %s",
191 pipe->rfd, strerror(errno));
192 } else if (writt < 1) {
193 Warn1("write() only wrote "F_Zu" of 1 byte", writt);
194 }
195 }
196  
197 if (pipe->para.readline.dynprompt) {
198 *pipe->para.readline.dynend = '\0';
199 line = Readline(pipe->para.readline.dynprompt);
200 pipe->para.readline.dynend = pipe->para.readline.dynprompt;
201 } else {
202 line = Readline(pipe->para.readline.prompt);
203 }
204 /* GNU readline defines no error return */
205 if (line == NULL) {
206 return 0; /* EOF */
207 }
208 #if _WITH_TERMIOS
209 xiotermios_clrflag(pipe->rfd, 3, ECHO);
210 #endif /* _WITH_TERMIOS */
211 Add_history(line);
212 bytes = strlen(line);
213 ((char *)buff)[0] = '\0'; strncat(buff, line, bufsiz-1);
214 free(line);
215 if ((size_t)bytes < bufsiz) {
216 strcat(buff, "\n"); ++bytes;
217 }
218 return bytes;
219 }
220  
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;
225 const void *pcr;
226 const void *plf;
227 size_t len;
228  
229 if (bytes > pipe->para.readline.dynbytes) {
230 ptr = (const char *)buff + bytes - pipe->para.readline.dynbytes;
231 len = pipe->para.readline.dynbytes;
232 } else {
233 len = bytes;
234 }
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;
244 }
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;
253 }
254 memcpy(pipe->para.readline.dynend, ptr, len);
255 pipe->para.readline.dynend = pipe->para.readline.dynend + len;
256 }
257 return;
258 }
259  
260 #endif /* WITH_READLINE */