allow machine-specific libkern sources
[unix-history] / usr / src / lib / libedit / read.c
CommitLineData
188802ca
KB
1/*-
2 * Copyright (c) 1992 The Regents of the University of California.
3 * 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
b6dd18ed
CZ
11#if !defined(lint) && !defined(SCCSID)
12static char sccsid[] = "@(#)read.c 5.2 (Berkeley) %G%";
188802ca 13
b6dd18ed 14#endif /* not lint && not SCCSID */
188802ca 15/*
b6dd18ed
CZ
16 * read.c: Clean this junk up! This is horrible code.
17 * Terminal read functions
188802ca
KB
18 */
19#include "sys.h"
20#include <sys/errno.h>
21#include <unistd.h>
22#include <stdlib.h>
23extern int errno;
24#include "el.h"
25
26#define OKCMD -1
27
b6dd18ed
CZ
28private int read__fixio __P((int, int));
29private int read_preread __P((EditLine *));
30private int read_getcmd __P((EditLine *, el_action_t *, char *));
31
188802ca
KB
32#ifdef DEBUG_EDIT
33private void
34read_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");
188802ca 48}
b6dd18ed 49#endif /* DEBUG_EDIT */
188802ca 50
b6dd18ed
CZ
51/* read__fixio():
52 * Try to recover from a read error
53 */
54private int
55read__fixio(fd, e)
56 int fd, e;
188802ca 57{
b6dd18ed
CZ
58 switch (e) {
59 case -1: /* Make sure that the code is reachable */
188802ca 60
b6dd18ed
CZ
61#ifdef EWOULDBLOCK
62 case EWOULDBLOCK:
63# define TRY_AGAIN
64#endif /* EWOULDBLOCK */
188802ca 65
b6dd18ed
CZ
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 */
107private int
108read_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)
188802ca
KB
119 return 0;
120
121#ifdef FIONREAD
b6dd18ed 122 (void) ioctl(el->el_infd, FIONREAD, (ioctl_t) &chrs);
188802ca 123 if (chrs > 0) {
b6dd18ed 124 char buf[EL_BUFSIZ];
188802ca 125
b6dd18ed 126 chrs = read(el->el_infd, buf, (size_t) MIN(chrs, EL_BUFSIZ - 1));
188802ca
KB
127 if (chrs > 0) {
128 buf[chrs] = '\0';
b6dd18ed
CZ
129 el->el_chared.c_macro.nline = strdup(buf);
130 el_push(el->el_chared.c_macro.nline);
188802ca
KB
131 }
132 }
133#endif /* FIONREAD */
b6dd18ed 134
188802ca
KB
135 return chrs > 0;
136}
188802ca
KB
137
138
139/* el_push():
140 * Push a macro
141 */
142public void
143el_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
b6dd18ed
CZ
159
160/* read_getcmd():
161 * Return next command from the input stream.
162 */
188802ca 163private int
b6dd18ed 164read_getcmd(el, cmdnum, ch)
188802ca
KB
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 */
221public int
222el_getc(el, cp)
223 EditLine *el;
224 char *cp;
225{
226 int num_read;
188802ca 227 unsigned char tcp;
b6dd18ed 228 int tried = 0;
188802ca
KB
229
230 c_macro_t *ma = &el->el_chared.c_macro;
231
232 term__flush();
233 for (;;) {
188802ca 234 if (ma->level < 0) {
b6dd18ed 235 if (!read_preread(el))
188802ca
KB
236 break;
237 }
188802ca
KB
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");
b6dd18ed 254#endif /* DEBUG_READ */
188802ca 255 if (tty_rawmode(el) < 0) /* make sure the tty is set up correctly */
b6dd18ed 256 return 0;
188802ca
KB
257
258#ifdef DEBUG_READ
259 (void) fprintf(el->el_errfile, "Reading a character\n");
b6dd18ed 260#endif /* DEBUG_READ */
188802ca 261 while ((num_read = read(el->el_infd, (char *) &tcp, 1)) == -1)
b6dd18ed
CZ
262 if (!tried && read__fixio(el->el_infd, errno) == 0)
263 tried = 1;
264 else {
265 *cp = '\0';
266 return -1;
188802ca
KB
267 }
268#ifdef DEBUG_READ
269 (void) fprintf(el->el_errfile, "Got it %c\n", tcp);
b6dd18ed 270#endif /* DEBUG_READ */
188802ca
KB
271 *cp = tcp;
272 return num_read;
273}
274
275
276
277public const char *
278el_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
188802ca 293#ifdef FIONREAD
b6dd18ed 294 if (el->el_tty.t_mode == EX_IO && ma->level < 0) {
188802ca
KB
295 long chrs = 0;
296
b6dd18ed 297 (void) ioctl(el->el_infd, FIONREAD, (ioctl_t) &chrs);
188802ca
KB
298 if (chrs == 0) {
299 if (tty_rawmode(el) < 0) {
300 if (nread)
301 *nread = 0;
302 return NULL;
303 }
304 }
305 }
b6dd18ed 306#endif /* FIONREAD */
188802ca
KB
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);
b6dd18ed 313#endif /* DEBUG_EDIT */
188802ca 314 /* if EOF or error */
b6dd18ed 315 if ((num = read_getcmd(el, &cmdnum, &ch)) != OKCMD) {
188802ca
KB
316#ifdef DEBUG_READ
317 (void) fprintf(el->el_errfile, "Returning from el_gets %d\n", num);
b6dd18ed 318#endif /* DEBUG_READ */
188802ca
KB
319 break;
320 }
321
322 if (cmdnum >= el->el_map.nfunc) { /* BUG CHECK command */
323#ifdef DEBUG_EDIT
b6dd18ed
CZ
324 (void) fprintf(el->el_errfile,
325 "ERROR: illegal command from key 0%o\r\n", ch);
326#endif /* DEBUG_EDIT */
188802ca
KB
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 }
b6dd18ed 342#endif /* DEBUG_READ */
188802ca
KB
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;
188802ca
KB
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");
b6dd18ed 395#endif /* DEBUG_READ */
188802ca
KB
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}