1 /*-
2 * Copyright (c) 1992, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Christos Zoulas of Cornell University.
7 *
8 * %sccs.include.redist.c%
9 */
10
11 #if !defined(lint) && !defined(SCCSID)
12 static char sccsid[] = "@(#)read.c 8.1 (Berkeley) 06/04/93";
13
14 #endif /* not lint && not SCCSID */
15 /*
16 * read.c: Clean this junk up! This is horrible code.
17 * Terminal read functions
18 */
19 #include "sys.h"
20 #include <sys/errno.h>
21 #include <unistd.h>
22 #include <stdlib.h>
23 extern int errno;
24 #include "el.h"
25
26 #define OKCMD -1
27
28 private int read__fixio __P((int, int));
29 private int read_preread __P((EditLine *));
30 private int read_getcmd __P((EditLine *, el_action_t *, char *));
31
32 #ifdef DEBUG_EDIT
33 private void
read_debug(el)34 read_debug(el)
35 EditLine *el;
36 {
37
38 if (el->el_line.cursor > el->el_line.lastchar)
39 (void) fprintf(el->el_errfile, "cursor > lastchar\r\n");
40 if (el->el_line.cursor < el->el_line.buffer)
41 (void) fprintf(el->el_errfile, "cursor < buffer\r\n");
42 if (el->el_line.cursor > el->el_line.limit)
43 (void) fprintf(el->el_errfile, "cursor > limit\r\n");
44 if (el->el_line.lastchar > el->el_line.limit)
45 (void) fprintf(el->el_errfile, "lastchar > limit\r\n");
46 if (el->el_line.limit != &el->el_line.buffer[EL_BUFSIZ - 2])
47 (void) fprintf(el->el_errfile, "limit != &buffer[EL_BUFSIZ-2]\r\n");
48 }
49 #endif /* DEBUG_EDIT */
50
51 /* read__fixio():
52 * Try to recover from a read error
53 */
54 private int
read__fixio(fd,e)55 read__fixio(fd, e)
56 int fd, e;
57 {
58 switch (e) {
59 case -1: /* Make sure that the code is reachable */
60
61 #ifdef EWOULDBLOCK
62 case EWOULDBLOCK:
63 # define TRY_AGAIN
64 #endif /* EWOULDBLOCK */
65
66 #if defined(POSIX) && defined(EAGAIN)
67 # if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
68 case EAGAIN:
69 # define TRY_AGAIN
70 # endif /* EWOULDBLOCK && EWOULDBLOCK != EAGAIN */
71 #endif /* POSIX && EAGAIN */
72
73 e = 0;
74 #ifdef TRY_AGAIN
75 # if defined(F_SETFL) && defined(O_NDELAY)
76 if ((e = fcntl(fd, F_GETFL, 0)) == -1)
77 return -1;
78
79 if (fcntl(fd, F_SETFL, e & ~O_NDELAY) == -1)
80 return -1;
81 else
82 e = 1;
83 # endif /* F_SETFL && O_NDELAY */
84
85 # ifdef FIONBIO
86 if (ioctl(fd, FIONBIO, (ioctl_t) &e) == -1)
87 return -1;
88 else
89 e = 1;
90 # endif /* FIONBIO */
91
92 #endif /* TRY_AGAIN */
93 return e ? 0 : -1;
94
95 case EINTR:
96 return 0;
97
98 default:
99 return -1;
100 }
101 }
102
103
104 /* read_preread():
105 * Try to read the stuff in the input queue;
106 */
107 private int
read_preread(el)108 read_preread(el)
109 EditLine *el;
110 {
111 int chrs = 0;
112
113 if (el->el_chared.c_macro.nline) {
114 el_free((ptr_t) el->el_chared.c_macro.nline);
115 el->el_chared.c_macro.nline = NULL;
116 }
117
118 if (el->el_tty.t_mode == ED_IO)
119 return 0;
120
121 #ifdef FIONREAD
122 (void) ioctl(el->el_infd, FIONREAD, (ioctl_t) &chrs);
123 if (chrs > 0) {
124 char buf[EL_BUFSIZ];
125
126 chrs = read(el->el_infd, buf, (size_t) MIN(chrs, EL_BUFSIZ - 1));
127 if (chrs > 0) {
128 buf[chrs] = '\0';
129 el->el_chared.c_macro.nline = strdup(buf);
130 el_push(el->el_chared.c_macro.nline);
131 }
132 }
133 #endif /* FIONREAD */
134
135 return chrs > 0;
136 }
137
138
139 /* el_push():
140 * Push a macro
141 */
142 public void
el_push(el,str)143 el_push(el, str)
144 EditLine *el;
145 const char *str;
146 {
147 c_macro_t *ma = &el->el_chared.c_macro;
148
149 if (str != NULL && ma->level + 1 < EL_MAXMACRO) {
150 ma->level++;
151 ma->macro[ma->level] = (char *) str;
152 }
153 else {
154 term_beep(el);
155 term__flush();
156 }
157 }
158
159
160 /* read_getcmd():
161 * Return next command from the input stream.
162 */
163 private int
read_getcmd(el,cmdnum,ch)164 read_getcmd(el, cmdnum, ch)
165 EditLine *el;
166 el_action_t *cmdnum;
167 char *ch;
168 {
169 el_action_t cmd = 0;
170 int num;
171
172 while (cmd == 0 || cmd == ED_SEQUENCE_LEAD_IN) {
173 if ((num = el_getc(el, ch)) != 1) /* if EOF or error */
174 return num;
175
176 #ifdef KANJI
177 if ((*ch & 0200)) {
178 el->el_state.metanext = 0;
179 cmd = CcViMap[' '];
180 break;
181 }
182 else
183 #endif /* KANJI */
184
185 if (el->el_state.metanext) {
186 el->el_state.metanext = 0;
187 *ch |= 0200;
188 }
189 cmd = el->el_map.current[(unsigned char) *ch];
190 if (cmd == ED_SEQUENCE_LEAD_IN) {
191 key_value_t val;
192 switch (key_get(el, ch, &val)) {
193 case XK_CMD:
194 cmd = val.cmd;
195 break;
196 case XK_STR:
197 el_push(el, val.str);
198 break;
199 #ifdef notyet
200 case XK_EXE:
201 /* XXX: In the future to run a user function */
202 RunCommand(val.str);
203 break;
204 #endif
205 default:
206 abort();
207 break;
208 }
209 }
210 if (el->el_map.alt == NULL)
211 el->el_map.current = el->el_map.key;
212 }
213 *cmdnum = cmd;
214 return OKCMD;
215 }
216
217
218 /* el_getc():
219 * Read a character
220 */
221 public int
el_getc(el,cp)222 el_getc(el, cp)
223 EditLine *el;
224 char *cp;
225 {
226 int num_read;
227 unsigned char tcp;
228 int tried = 0;
229
230 c_macro_t *ma = &el->el_chared.c_macro;
231
232 term__flush();
233 for (;;) {
234 if (ma->level < 0) {
235 if (!read_preread(el))
236 break;
237 }
238 if (ma->level < 0)
239 break;
240
241 if (*ma->macro[ma->level] == 0) {
242 ma->level--;
243 continue;
244 }
245 *cp = *ma->macro[ma->level]++ & 0377;
246 if (*ma->macro[ma->level] == 0) { /* Needed for QuoteMode On */
247 ma->level--;
248 }
249 return 1;
250 }
251
252 #ifdef DEBUG_READ
253 (void) fprintf(el->el_errfile, "Turning raw mode on\n");
254 #endif /* DEBUG_READ */
255 if (tty_rawmode(el) < 0) /* make sure the tty is set up correctly */
256 return 0;
257
258 #ifdef DEBUG_READ
259 (void) fprintf(el->el_errfile, "Reading a character\n");
260 #endif /* DEBUG_READ */
261 while ((num_read = read(el->el_infd, (char *) &tcp, 1)) == -1)
262 if (!tried && read__fixio(el->el_infd, errno) == 0)
263 tried = 1;
264 else {
265 *cp = '\0';
266 return -1;
267 }
268 #ifdef DEBUG_READ
269 (void) fprintf(el->el_errfile, "Got it %c\n", tcp);
270 #endif /* DEBUG_READ */
271 *cp = tcp;
272 return num_read;
273 }
274
275
276
277 public const char *
el_gets(el,nread)278 el_gets(el, nread)
279 EditLine *el;
280 int *nread;
281 {
282 int retval;
283 el_action_t cmdnum = 0;
284 int num; /* how many chars we have read at NL */
285 char ch;
286
287 if (el->el_flags & HANDLE_SIGNALS)
288 sig_set(el);
289
290 re_clear_display(el); /* reset the display stuff */
291 ch_reset(el);
292
293 #ifdef FIONREAD
294 if (el->el_tty.t_mode == EX_IO && ma->level < 0) {
295 long chrs = 0;
296
297 (void) ioctl(el->el_infd, FIONREAD, (ioctl_t) &chrs);
298 if (chrs == 0) {
299 if (tty_rawmode(el) < 0) {
300 if (nread)
301 *nread = 0;
302 return NULL;
303 }
304 }
305 }
306 #endif /* FIONREAD */
307
308 re_refresh(el); /* print the prompt */
309
310 for (num = OKCMD; num == OKCMD;) { /* while still editing this line */
311 #ifdef DEBUG_EDIT
312 read_debug(el);
313 #endif /* DEBUG_EDIT */
314 /* if EOF or error */
315 if ((num = read_getcmd(el, &cmdnum, &ch)) != OKCMD) {
316 #ifdef DEBUG_READ
317 (void) fprintf(el->el_errfile, "Returning from el_gets %d\n", num);
318 #endif /* DEBUG_READ */
319 break;
320 }
321
322 if (cmdnum >= el->el_map.nfunc) { /* BUG CHECK command */
323 #ifdef DEBUG_EDIT
324 (void) fprintf(el->el_errfile,
325 "ERROR: illegal command from key 0%o\r\n", ch);
326 #endif /* DEBUG_EDIT */
327 continue; /* try again */
328 }
329
330 /* now do the real command */
331 #ifdef DEBUG_READ
332 {
333 el_bindings_t *b;
334 for (b = el->el_map.help; b->name; b++)
335 if (b->func == cmdnum)
336 break;
337 if (b->name)
338 (void) fprintf(el->el_errfile, "Executing %s\n", b->name);
339 else
340 (void) fprintf(el->el_errfile, "Error command = %d\n", cmdnum);
341 }
342 #endif /* DEBUG_READ */
343 retval = (*el->el_map.func[cmdnum])(el, ch);
344
345 /* save the last command here */
346 el->el_state.lastcmd = cmdnum;
347
348 /* use any return value */
349 switch (retval) {
350 case CC_CURSOR:
351 el->el_state.argument = 1;
352 el->el_state.doingarg = 0;
353 re_refresh_cursor(el);
354 break;
355
356 case CC_REFRESH:
357 el->el_state.argument = 1;
358 el->el_state.doingarg = 0;
359 re_refresh(el);
360 break;
361
362 case CC_NORM: /* normal char */
363 el->el_state.argument = 1;
364 el->el_state.doingarg = 0;
365 break;
366
367 case CC_ARGHACK: /* Suggested by Rich Salz */
368 /* <rsalz@pineapple.bbn.com> */
369 break; /* keep going... */
370
371 case CC_EOF: /* end of file typed */
372 num = 0;
373 break;
374
375 case CC_NEWLINE: /* normal end of line */
376 num = el->el_line.lastchar - el->el_line.buffer;
377 break;
378
379 case CC_FATAL: /* fatal error, reset to known state */
380 #ifdef DEBUG_READ
381 (void) fprintf(el->el_errfile, "*** editor fatal ERROR ***\r\n\n");
382 #endif /* DEBUG_READ */
383 /* put (real) cursor in a known place */
384 re_clear_display(el); /* reset the display stuff */
385 ch_reset(el); /* reset the input pointers */
386 re_refresh(el); /* print the prompt again */
387 el->el_state.argument = 1;
388 el->el_state.doingarg = 0;
389 break;
390
391 case CC_ERROR:
392 default: /* functions we don't know about */
393 #ifdef DEBUG_READ
394 (void) fprintf(el->el_errfile, "*** editor ERROR ***\r\n\n");
395 #endif /* DEBUG_READ */
396 el->el_state.argument = 1;
397 el->el_state.doingarg = 0;
398 term_beep(el);
399 term__flush();
400 break;
401 }
402 }
403
404 (void) tty_cookedmode(el); /* make sure the tty is set up correctly */
405 term__flush(); /* flush any buffered output */
406 if (el->el_flags & HANDLE_SIGNALS)
407 sig_clr(el);
408 if (nread)
409 *nread = num;
410 return num ? el->el_line.buffer : NULL;
411 }
412