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