Initial import from FreeBSD RELENG_4:
[games.git] / lib / libedit / read.c
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  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *      This product includes software developed by the University of
19  *      California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36
37 #if !defined(lint) && !defined(SCCSID)
38 #if 0
39 static char sccsid[] = "@(#)read.c      8.1 (Berkeley) 6/4/93";
40 #endif
41 static const char rcsid[] =
42   "$FreeBSD: src/lib/libedit/read.c,v 1.4.6.3 2000/10/31 23:51:10 brian Exp $";
43 #endif /* not lint && not SCCSID */
44 /*
45  * read.c: Clean this junk up! This is horrible code.
46  *         Terminal read functions
47  */
48 #include "sys.h"
49 #include <errno.h>
50 #include <fcntl.h>
51 #include <unistd.h>
52 #include <stdlib.h>
53 #include "el.h"
54
55 #define OKCMD -1
56
57 private int read__fixio         __P((int, int));
58 private int read_preread        __P((EditLine *));
59 private int read_getcmd         __P((EditLine *, el_action_t *, char *));
60
61 #ifdef DEBUG_EDIT
62 private void
63 read_debug(el)
64     EditLine *el;
65 {
66
67     if (el->el_line.cursor > el->el_line.lastchar)
68         (void) fprintf(el->el_errfile, "cursor > lastchar\r\n");
69     if (el->el_line.cursor < el->el_line.buffer)
70         (void) fprintf(el->el_errfile, "cursor < buffer\r\n");
71     if (el->el_line.cursor > el->el_line.limit)
72         (void) fprintf(el->el_errfile, "cursor > limit\r\n");
73     if (el->el_line.lastchar > el->el_line.limit)
74         (void) fprintf(el->el_errfile, "lastchar > limit\r\n");
75     if (el->el_line.limit != &el->el_line.buffer[EL_BUFSIZ - 2])
76         (void) fprintf(el->el_errfile, "limit != &buffer[EL_BUFSIZ-2]\r\n");
77 }
78 #endif /* DEBUG_EDIT */
79
80 /* read__fixio():
81  *      Try to recover from a read error
82  */
83 private int
84 read__fixio(fd, e)
85     int fd, e;
86 {
87     switch (e) {
88     case -1:    /* Make sure that the code is reachable */
89
90 #ifdef EWOULDBLOCK
91     case EWOULDBLOCK:
92 # ifndef TRY_AGAIN
93 #  define TRY_AGAIN
94 # endif
95 #endif /* EWOULDBLOCK */
96
97 #if defined(POSIX) && defined(EAGAIN)
98 # if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
99     case EAGAIN:
100 #  ifndef TRY_AGAIN
101 #   define TRY_AGAIN
102 #  endif
103 # endif /* EWOULDBLOCK && EWOULDBLOCK != EAGAIN */
104 #endif /* POSIX && EAGAIN */
105
106         e = 0;
107 #ifdef TRY_AGAIN
108 # if defined(F_SETFL) && defined(O_NDELAY)
109         if ((e = fcntl(fd, F_GETFL, 0)) == -1)
110             return -1;
111
112         if (fcntl(fd, F_SETFL, e & ~O_NDELAY) == -1)
113             return -1;
114         else
115             e = 1;
116 # endif /* F_SETFL && O_NDELAY */
117
118 # ifdef FIONBIO
119         if (ioctl(fd, FIONBIO, (ioctl_t) &e) == -1)
120             return -1;
121         else
122             e = 1;
123 # endif /* FIONBIO */
124
125 #endif /* TRY_AGAIN */
126         return e ? 0 : -1;
127
128     case EINTR:
129         return 0;
130
131     default:
132         return -1;
133     }
134 }
135
136
137 /* read_preread():
138  *      Try to read the stuff in the input queue;
139  */
140 private int
141 read_preread(el)
142     EditLine *el;
143 {
144     int    chrs = 0;
145
146     if (el->el_chared.c_macro.nline) {
147         el_free((ptr_t) el->el_chared.c_macro.nline);
148         el->el_chared.c_macro.nline = NULL;
149     }
150
151     if (el->el_tty.t_mode == ED_IO)
152         return 0;
153
154 #ifdef FIONREAD
155     (void) ioctl(el->el_infd, FIONREAD, (ioctl_t) &chrs);
156     if (chrs > 0) {
157         char    buf[EL_BUFSIZ];
158
159         chrs = read(el->el_infd, buf, (size_t) MIN(chrs, EL_BUFSIZ - 1));
160         if (chrs > 0) {
161             buf[chrs] = '\0';
162             el->el_chared.c_macro.nline = strdup(buf);
163             el_push(el->el_chared.c_macro.nline);
164         }
165     }
166 #endif  /* FIONREAD */
167
168     return chrs > 0;
169 }
170
171
172 /* el_push():
173  *      Push a macro
174  */
175 public void
176 el_push(el, str)
177     EditLine *el;
178     const char   *str;
179 {
180     c_macro_t *ma = &el->el_chared.c_macro;
181
182     if (str != NULL && ma->level + 1 < EL_MAXMACRO) {
183         ma->level++;
184         ma->macro[ma->level] = (char *) str;
185     }
186     else {
187         term_beep(el);
188         term__flush();
189     }
190 }
191
192
193 /* read_getcmd():
194  *      Return next command from the input stream.
195  */
196 private int
197 read_getcmd(el, cmdnum, ch)
198     EditLine *el;
199     el_action_t *cmdnum;
200     char *ch;
201 {
202     el_action_t  cmd = ED_UNASSIGNED;
203     int     num;
204
205     while (cmd == ED_UNASSIGNED || cmd == ED_SEQUENCE_LEAD_IN) {
206         if ((num = el_getc(el, ch)) != 1)       /* if EOF or error */
207             return num;
208
209 #ifdef  KANJI
210         if ((*ch & 0200)) {
211             el->el_state.metanext = 0;
212             cmd = CcViMap[' '];
213             break;
214         }
215         else
216 #endif /* KANJI */
217
218         if (el->el_state.metanext) {
219             el->el_state.metanext = 0;
220             *ch |= 0200;
221         }
222         cmd = el->el_map.current[(unsigned char) *ch];
223         if (cmd == ED_SEQUENCE_LEAD_IN) {
224             key_value_t val;
225             switch (key_get(el, ch, &val)) {
226             case XK_CMD:
227                 cmd = val.cmd;
228                 break;
229             case XK_STR:
230                 el_push(el, val.str);
231                 break;
232 #ifdef notyet
233             case XK_EXE:
234                 /* XXX: In the future to run a user function */
235                 RunCommand(val.str);
236                 break;
237 #endif
238             default:
239                 abort();
240                 break;
241             }
242         }
243         if (el->el_map.alt == NULL)
244             el->el_map.current = el->el_map.key;
245     }
246     *cmdnum = cmd;
247     return OKCMD;
248 }
249
250
251 /* el_getc():
252  *      Read a character
253  */
254 public int
255 el_getc(el, cp)
256     EditLine *el;
257     char *cp;
258 {
259     int num_read;
260     unsigned char tcp;
261     int tried = 0;
262
263     c_macro_t *ma = &el->el_chared.c_macro;
264
265     term__flush();
266     for (;;) {
267         if (ma->level < 0) {
268             if (!read_preread(el))
269                 break;
270         }
271         if (ma->level < 0)
272             break;
273
274         if (*ma->macro[ma->level] == 0) {
275             ma->level--;
276             continue;
277         }
278         *cp = *ma->macro[ma->level]++ & 0377;
279         if (*ma->macro[ma->level] == 0) {       /* Needed for QuoteMode On */
280             ma->level--;
281         }
282         return 1;
283     }
284
285 #ifdef DEBUG_READ
286     (void) fprintf(el->el_errfile, "Turning raw mode on\n");
287 #endif /* DEBUG_READ */
288     if (tty_rawmode(el) < 0)    /* make sure the tty is set up correctly */
289         return 0;
290
291 #ifdef DEBUG_READ
292     (void) fprintf(el->el_errfile, "Reading a character\n");
293 #endif /* DEBUG_READ */
294     while ((num_read = read(el->el_infd, (char *) &tcp, 1)) == -1)
295         if (!tried && read__fixio(el->el_infd, errno) == 0)
296             tried = 1;
297         else {
298             *cp = '\0';
299             return -1;
300         }
301 #ifdef DEBUG_READ
302     (void) fprintf(el->el_errfile, "Got it %c\n", tcp);
303 #endif /* DEBUG_READ */
304     *cp = tcp;
305     return num_read;
306 }
307
308
309
310 public const char *
311 el_gets(el, nread)
312     EditLine *el;
313     int *nread;
314 {
315     int retval;
316     el_action_t  cmdnum = 0;
317     int     num;                /* how many chars we have read at NL */
318     char    ch;
319
320     if (el->el_flags & HANDLE_SIGNALS)
321         sig_set(el);
322
323     re_clear_display(el);               /* reset the display stuff */
324     ch_reset(el);
325
326 #ifdef FIONREAD
327     if (el->el_tty.t_mode == EX_IO && ma->level < 0) {
328         long    chrs = 0;
329
330         (void) ioctl(el->el_infd, FIONREAD, (ioctl_t) &chrs);
331         if (chrs == 0) {
332             if (tty_rawmode(el) < 0) {
333                 if (nread)
334                         *nread = 0;
335                 return NULL;
336             }
337         }
338     }
339 #endif /* FIONREAD */
340
341     re_refresh(el);                     /* print the prompt */
342
343     for (num = OKCMD; num == OKCMD;) {  /* while still editing this line */
344 #ifdef DEBUG_EDIT
345         read_debug(el);
346 #endif /* DEBUG_EDIT */
347         /* if EOF or error */
348         if ((num = read_getcmd(el, &cmdnum, &ch)) != OKCMD) {
349 #ifdef DEBUG_READ
350             (void) fprintf(el->el_errfile, "Returning from el_gets %d\n", num);
351 #endif /* DEBUG_READ */
352             break;
353         }
354
355         if (cmdnum >= el->el_map.nfunc) {       /* BUG CHECK command */
356 #ifdef DEBUG_EDIT
357             (void) fprintf(el->el_errfile,
358                            "ERROR: illegal command from key 0%o\r\n", ch);
359 #endif /* DEBUG_EDIT */
360             continue;           /* try again */
361         }
362
363         /* now do the real command */
364 #ifdef DEBUG_READ
365         {
366             el_bindings_t *b;
367             for (b = el->el_map.help; b->name; b++)
368                 if (b->func == cmdnum)
369                     break;
370             if (b->name)
371                 (void) fprintf(el->el_errfile, "Executing %s\n", b->name);
372             else
373                 (void) fprintf(el->el_errfile, "Error command = %d\n", cmdnum);
374         }
375 #endif /* DEBUG_READ */
376         retval = (*el->el_map.func[cmdnum])(el, ch);
377
378         /* save the last command here */
379         el->el_state.lastcmd = cmdnum;
380
381         /* use any return value */
382         switch (retval) {
383         case CC_CURSOR:
384             el->el_state.argument = 1;
385             el->el_state.doingarg = 0;
386             re_refresh_cursor(el);
387             break;
388
389         case CC_REDISPLAY:
390             re_clear_lines(el);
391             re_clear_display(el);
392             /* FALLTHROUGH */
393
394         case CC_REFRESH:
395             el->el_state.argument = 1;
396             el->el_state.doingarg = 0;
397             re_refresh(el);
398             break;
399
400         case CC_NORM:           /* normal char */
401             el->el_state.argument = 1;
402             el->el_state.doingarg = 0;
403             break;
404
405         case CC_ARGHACK:        /* Suggested by Rich Salz */
406             /* <rsalz@pineapple.bbn.com> */
407             break;              /* keep going... */
408
409         case CC_EOF:            /* end of file typed */
410             num = 0;
411             break;
412
413         case CC_NEWLINE:        /* normal end of line */
414             num = el->el_line.lastchar - el->el_line.buffer;
415             break;
416
417         case CC_FATAL:          /* fatal error, reset to known state */
418 #ifdef DEBUG_READ
419             (void) fprintf(el->el_errfile, "*** editor fatal ERROR ***\r\n\n");
420 #endif /* DEBUG_READ */
421             /* put (real) cursor in a known place */
422             re_clear_display(el);       /* reset the display stuff */
423             ch_reset(el);               /* reset the input pointers */
424             re_refresh(el);             /* print the prompt again */
425             el->el_state.argument = 1;
426             el->el_state.doingarg = 0;
427             break;
428
429         case CC_ERROR:
430         default:                /* functions we don't know about */
431 #ifdef DEBUG_READ
432             (void) fprintf(el->el_errfile, "*** editor ERROR ***\r\n\n");
433 #endif /* DEBUG_READ */
434             el->el_state.argument = 1;
435             el->el_state.doingarg = 0;
436             term_beep(el);
437             term__flush();
438             break;
439         }
440     }
441
442     term__flush();              /* flush any buffered output */
443     (void) tty_cookedmode(el);  /* make sure the tty is set up correctly */
444     if (el->el_flags & HANDLE_SIGNALS)
445         sig_clr(el);
446     if (nread)
447             *nread = num;
448     return num ? el->el_line.buffer : NULL;
449 }