nexmon – Blame information for rev 1
?pathlinks?
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 */ |