xref: /original-bsd/lib/libedit/read.c (revision c3e32dec)
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
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
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
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
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
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
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 *
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