root/src/noitedit/read.c

Revision 83ae07dae4f92f9cea49d1ab26f4e6a92fbe8db9, 13.9 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 10 years ago)

more hacks... works for me now, refs #105

  • Property mode set to 100644
Line 
1 /*      $NetBSD: read.c,v 1.19 2001/01/10 07:45:41 jdolecek Exp $       */
2
3 /*-
4  * Copyright (c) 1992, 1993
5  *      The Regents of the University of California.  All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Christos Zoulas of Cornell University.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *      This product includes software developed by the University of
21  *      California, Berkeley and its contributors.
22  * 4. Neither the name of the University nor the names of its contributors
23  *    may be used to endorse or promote products derived from this software
24  *    without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  */
38
39 #include "noitedit/compat.h"
40 #if !defined(lint) && !defined(SCCSID)
41 #if 0
42 static char sccsid[] = "@(#)read.c      8.1 (Berkeley) 6/4/93";
43 #else
44 __RCSID("$NetBSD: read.c,v 1.19 2001/01/10 07:45:41 jdolecek Exp $");
45 #endif
46 #endif /* not lint && not SCCSID */
47
48 /*
49  * read.c: Clean this junk up! This is horrible code.
50  *         Terminal read functions
51  */
52 #include "noitedit/sys.h"
53 #include <errno.h>
54 #include <sys/ioctl.h>
55 #if HAVE_UNISTD_H
56 #include <unistd.h>
57 #endif
58 #include <stdlib.h>
59 #include "noitedit/el.h"
60
61 #define OKCMD     -1
62 #define EAGAINCMD -2
63
64 #define ISEAGAIN(el) ((el)->el_nb_state == EAGAINCMD)
65
66 private int     read__fixio(int, int);
67 private int     read_preread(EditLine *);
68 private int     read_getcmd(EditLine *, el_action_t *, char *);
69 private int     read_char(EditLine *, char *);
70
71 #ifdef DEBUG_EDIT
72 private void
73 read_debug(EditLine *el)
74 {
75
76         if (el->el_line.cursor > el->el_line.lastchar)
77                 (void) el->el_err_printf(el, "cursor > lastchar\r\n");
78         if (el->el_line.cursor < el->el_line.buffer)
79                 (void) el->el_err_printf(el, "cursor < buffer\r\n");
80         if (el->el_line.cursor > el->el_line.limit)
81                 (void) el->el_err_printf(el, "cursor > limit\r\n");
82         if (el->el_line.lastchar > el->el_line.limit)
83                 (void) el->el_err_printf(el, "lastchar > limit\r\n");
84         if (el->el_line.limit != &el->el_line.buffer[EL_BUFSIZ - 2])
85                 (void) el->el_err_printf(el, "limit != &buffer[EL_BUFSIZ-2]\r\n");
86 }
87 #endif /* DEBUG_EDIT */
88
89
90 /* read__fixio():
91  *      Try to recover from a read error
92  */
93 /* ARGSUSED */
94 private int
95 read__fixio(int fd, int e)
96 {
97
98         switch (e) {
99         case -1:                /* Make sure that the code is reachable */
100
101 #ifdef EWOULDBLOCK
102         case EWOULDBLOCK:
103 #ifndef TRY_AGAIN
104 #define TRY_AGAIN
105 #endif
106 #endif /* EWOULDBLOCK */
107
108 #if defined(POSIX) && defined(EAGAIN)
109 #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
110         case EAGAIN:
111 #ifndef TRY_AGAIN
112 #define TRY_AGAIN
113 #endif
114 #endif /* EWOULDBLOCK && EWOULDBLOCK != EAGAIN */
115 #endif /* POSIX && EAGAIN */
116
117                 e = 0;
118 #ifdef TRY_AGAIN
119 #if defined(F_SETFL) && defined(O_NDELAY)
120 /*
121                 if ((e = fcntl(fd, F_GETFL, 0)) == -1)
122                         return (-1);
123
124                 if (fcntl(fd, F_SETFL, e & ~O_NDELAY) == -1)
125                         return (-1);
126                 else
127                         e = 1;
128 */
129 #endif /* F_SETFL && O_NDELAY */
130
131 #ifdef FIONBIO
132 /*
133                 {
134                         int zero = 0;
135
136                         if (ioctl(fd, FIONBIO, (ioctl_t) & zero) == -1)
137                                 return (-1);
138                         else
139                                 e = 1;
140                 }
141 */
142 #endif /* FIONBIO */
143
144 #endif /* TRY_AGAIN */
145                 return (e ? 0 : -1);
146
147         case EINTR:
148                 return (0);
149
150         default:
151                 return (-1);
152         }
153 }
154
155
156 /* read_preread():
157  *      Try to read the stuff in the input queue;
158  */
159 private int
160 read_preread(EditLine *el)
161 {
162         int chrs = 0;
163
164         if (el->el_chared.c_macro.nline) {
165                 el_free((ptr_t) el->el_chared.c_macro.nline);
166                 el->el_chared.c_macro.nline = NULL;
167         }
168         if (el->el_tty.t_mode == ED_IO)
169                 return (0);
170
171 #ifdef FIONREAD
172         (void) ioctl(el->el_infd, FIONREAD, (ioctl_t) & chrs);
173         if (chrs > 0) {
174                 char buf[EL_BUFSIZ];
175                 int mask;
176
177                 if(el->el_in_e)
178                         chrs = el->
179                                 el_in_e->
180                                 opset->
181                                 read(el->el_in_e->fd, buf,
182                                     (size_t) MIN(chrs, EL_BUFSIZ - 1),
183                                     &mask, el->el_in_e);
184                 else
185                         chrs = read(el->el_infd, buf,
186                             (size_t) MIN(chrs, EL_BUFSIZ - 1));
187                 if (chrs > 0) {
188                         buf[chrs] = '\0';
189                         el->el_chared.c_macro.nline = strdup(buf);
190                         el_push(el, el->el_chared.c_macro.nline);
191                 }
192         }
193 #endif /* FIONREAD */
194
195         return (chrs > 0);
196 }
197
198
199 /* el_push():
200  *      Push a macro
201  */
202 public void
203 el_push(EditLine *el, const char *str)
204 {
205         c_macro_t *ma = &el->el_chared.c_macro;
206
207         if (str != NULL && ma->level + 1 < EL_MAXMACRO) {
208                 ma->level++;
209                 /* LINTED const cast */
210                 ma->macro[ma->level] = (char *) str;
211         } else {
212                 term_beep(el);
213                 term__flush();
214         }
215 }
216
217
218 public int
219 el_internal_read_getcmd(EditLine *el, el_action_t *cmdnum, char *ch, int nonblock)
220 {
221         el_action_t cmd = ED_UNASSIGNED;
222         int num;
223
224         while (cmd == ED_UNASSIGNED || cmd == ED_SEQUENCE_LEAD_IN) {
225                 if ((num = el_getc(el, ch)) != 1) {     /* if EOF or error */
226                         /* So solaris doesn't read -> -1 with EAGAIN when
227                          * no data is ready on the terminal.. it returns 0.
228                          * I'm likely not understanding something, but that
229                          * seems deeply flawed.  Regardless, I cannot think
230                          * of a case where we'd want to return something other
231                          * than EAGAINCMD... this seems "more correct" than
232                          * only returning it whe errno == EAGAIN
233
234                                 if(errno == EAGAIN) return EAGAINCMD;
235                                 return (num);
236
237                          */
238                         return EAGAINCMD;
239                 }
240                
241 #ifdef  KANJI
242                 if ((*ch & 0200)) {
243                         el->el_state.metanext = 0;
244                         cmd = CcViMap[' '];
245                         break;
246                 } else
247 #endif /* KANJI */
248
249                 if (el->el_state.metanext) {
250                         el->el_state.metanext = 0;
251                         *ch |= 0200;
252                 }
253                 cmd = el->el_map.current[(unsigned char) *ch];
254                 if (cmd == ED_SEQUENCE_LEAD_IN || el->el_keystate) {
255                         key_value_t val;
256                         switch (key_get(el, ch, &val)) {
257                         case XK_CMD:
258                                 cmd = val.cmd;
259                                 break;
260                         case XK_STR:
261                                 el_push(el, val.str);
262                                 break;
263 #ifdef notyet
264                         case XK_EXE:
265                                 /* XXX: In the future to run a user function */
266                                 RunCommand(val.str);
267                                 break;
268 #endif
269                         default:
270                                 EL_ABORT((el->el_errfile, "Bad XK_ type \n"));
271                                 break;
272                         }
273                 }
274                 if (el->el_map.alt == NULL)
275                         el->el_map.current = el->el_map.key;
276
277                 if (cmd == ED_UNASSIGNED && nonblock)
278                         break;
279         }
280         *cmdnum = cmd;
281         return (OKCMD);
282 }
283
284 /* read_getcmd():
285  *      Return next command from the input stream.
286  */
287 private int
288 read_getcmd(EditLine *el, el_action_t *cmdnum, char *ch)
289 {
290         return el_internal_read_getcmd(el, cmdnum, ch, 0);
291 }
292
293
294 /* read_char():
295  *      Read a character from the tty.
296  */
297 private int
298 read_char(EditLine *el, char *cp)
299 {
300         int num_read;
301         int tried = 0;
302
303         do {
304                 int mask;
305                 if(el->el_in_e)
306                         num_read = el->
307                                 el_in_e->
308                                 opset->
309                                 read(el->el_in_e->fd, cp, 1,
310                                     &mask, el->el_in_e);
311                 else
312                         num_read = read(el->el_infd, cp, 1);
313
314                 if (num_read)
315                         break;
316                 if (num_read == -1) {
317                         if (errno == EAGAIN) return 0;
318                         if (!tried && read__fixio(el->el_infd, errno) == 0) {
319                                 tried = 1;
320                         } else {
321                                 *cp = '\0';
322                                 return -1;
323                         }
324                 }
325         } while (num_read == -1);
326
327         return (num_read);
328 }
329
330 public int el_internal_read_char(EditLine *el, char *cp)
331 {
332         return read_char(el, cp);
333 }
334
335 /* el_getc():
336  *      Read a character
337  */
338 public int
339 el_getc(EditLine *el, char *cp)
340 {
341         int num_read;
342         c_macro_t *ma = &el->el_chared.c_macro;
343
344         term__flush();
345         for (;;) {
346                 if (ma->level < 0) {
347                         if (!read_preread(el))
348                                 break;
349                 }
350                 if (ma->level < 0)
351                         break;
352
353                 if (*ma->macro[ma->level] == 0) {
354                         ma->level--;
355                         continue;
356                 }
357                 *cp = *ma->macro[ma->level]++ & 0377;
358                 if (*ma->macro[ma->level] == 0) {       /* Needed for QuoteMode
359                                                          * On */
360                         ma->level--;
361                 }
362                 return (1);
363         }
364
365 #ifdef DEBUG_READ
366         (void) el->el_err_printf(el, "Turning raw mode on\r\n");
367 #endif /* DEBUG_READ */
368         if (tty_rawmode(el) < 0)/* make sure the tty is set up correctly */
369                 return (0);
370
371 #ifdef DEBUG_READ
372         (void) el->el_err_printf(el, "Reading a character\r\n");
373 #endif /* DEBUG_READ */
374         num_read = read_char(el, cp);
375 #ifdef DEBUG_READ
376         (void) el->el_err_printf(el, "Got it(%d) [%02x]\r\n",
377                                  (int)num_read, (unsigned char)*cp);
378 #endif /* DEBUG_READ */
379         return (num_read);
380 }
381
382 public int el_gets_dispatch(EditLine *el, el_action_t cmdnum, char ch, int *num)
383 {
384         int retval;
385
386         if ((int) cmdnum >= el->el_map.nfunc) { /* BUG CHECK command */
387 #ifdef DEBUG_EDIT
388                 (void) el->el_err_printf(el,
389                                            "ERROR: illegal command from key 0%o\r\n", ch);
390 #endif /* DEBUG_EDIT */
391                 return 0;       /* try again */
392         }
393         /* now do the real command */
394 #ifdef DEBUG_READ
395         {
396                 el_bindings_t *b;
397                 for (b = el->el_map.help; b->name; b++)
398                         if (b->func == cmdnum)
399                                 break;
400                 if (b->name)
401                         (void) el->el_err_printf(el,
402                                                    "Executing %s\r\n", b->name);
403                 else
404                         (void) el->el_err_printf(el,
405                                                    "Error command = %d\r\n", cmdnum);
406         }
407 #endif /* DEBUG_READ */
408         retval = (*el->el_map.func[cmdnum]) (el, ch);
409
410         /* save the last command here */
411         el->el_state.lastcmd = cmdnum;
412
413         /* use any return value */
414         switch (retval) {
415                 case CC_CURSOR:
416                         el->el_state.argument = 1;
417                         el->el_state.doingarg = 0;
418                         re_refresh_cursor(el);
419                         break;
420
421                 case CC_REDISPLAY:
422                         re_clear_lines(el);
423                         re_clear_display(el);
424                         /* FALLTHROUGH */
425
426                 case CC_REFRESH:
427                         el->el_state.argument = 1;
428                         el->el_state.doingarg = 0;
429                         re_refresh(el);
430                         break;
431
432                 case CC_REFRESH_BEEP:
433                         el->el_state.argument = 1;
434                         el->el_state.doingarg = 0;
435                         re_refresh(el);
436                         term_beep(el);
437                         break;
438
439                 case CC_NORM:   /* normal char */
440                         el->el_state.argument = 1;
441                         el->el_state.doingarg = 0;
442                         break;
443
444                 case CC_ARGHACK:        /* Suggested by Rich Salz */
445                         /* <rsalz@pineapple.bbn.com> */
446                         break;  /* keep going... */
447
448                 case CC_EOF:    /* end of file typed */
449                         *num = 0;
450                         break;
451
452                 case CC_NEWLINE:        /* normal end of line */
453                         *num = el->el_line.lastchar - el->el_line.buffer;
454                         break;
455
456                 case CC_FATAL:  /* fatal error, reset to known state */
457 #ifdef DEBUG_READ
458                         (void) el->el_err_printf(el,
459                                                    "*** editor fatal ERROR ***\r\n\r\n");
460 #endif /* DEBUG_READ */
461                         /* put (real) cursor in a known place */
462                         re_clear_display(el);   /* reset the display stuff */
463                         ch_reset(el);   /* reset the input pointers */
464                         re_refresh(el); /* print the prompt again */
465                         el->el_state.argument = 1;
466                         el->el_state.doingarg = 0;
467                         break;
468
469                 case CC_ERROR:
470                 default:        /* functions we don't know about */
471 #ifdef DEBUG_READ
472                         (void) el->el_err_printf(el,
473                                                    "*** editor ERROR ***\r\n\r\n");
474 #endif /* DEBUG_READ */
475                         el->el_state.argument = 1;
476                         el->el_state.doingarg = 0;
477                         term_beep(el);
478                         term__flush();
479                         break;
480         }
481         return 1;
482 }
483
484 public int
485 el_eagain(EditLine *el)
486 {
487         return ISEAGAIN(el);
488 }
489
490 public const char *
491 el_gets(EditLine *el, int *nread)
492 {
493         el_action_t cmdnum = 0;
494         int num;                /* how many chars we have read at NL */
495         char ch;
496 #ifdef FIONREAD
497         c_macro_t *ma = &el->el_chared.c_macro;
498 #endif /* FIONREAD */
499
500         if (nread)
501                 *nread = 0;
502
503         if(el_eagain(el)) {
504                 el->el_nb_state = 0;
505                 goto eagain_resume;
506         }
507
508         if (el->el_flags & HANDLE_SIGNALS)
509                 sig_set(el);
510
511         if (el->el_flags & NO_TTY) {
512                 char *cp = el->el_line.buffer;
513                 size_t idx;
514
515 #if _WIN32
516                 printf("%s", el->el_prompt.p_func(el));
517 #endif
518
519                 while (read_char(el, cp) == 1) {
520                         /* make sure there is space for next character */
521                         if (cp + 1 >= el->el_line.limit) {
522                                 idx = (cp - el->el_line.buffer);
523                                 if (!ch_enlargebufs(el, 2))
524                                         break;
525                                 cp = &el->el_line.buffer[idx];
526                         }
527                         cp++;
528                         if (cp[-1] == '\r' || cp[-1] == '\n')
529                                 break;
530                 }
531
532                 el->el_line.cursor = el->el_line.lastchar = cp;
533                 *cp = '\0';
534                 if (nread)
535                         *nread = el->el_line.cursor - el->el_line.buffer;
536                 return (el->el_line.buffer);
537         }
538         re_clear_display(el);   /* reset the display stuff */
539         ch_reset(el);
540
541 #ifdef FIONREAD
542         if (el->el_tty.t_mode == EX_IO && ma->level < 0) {
543                 long chrs = 0;
544
545                 (void) ioctl(el->el_infd, FIONREAD, (ioctl_t) & chrs);
546                 if (chrs == 0) {
547                         if (tty_rawmode(el) < 0) {
548                                 if (nread)
549                                         *nread = 0;
550                                 return (NULL);
551                         }
552                 }
553         }
554 #endif /* FIONREAD */
555
556         re_refresh(el);         /* print the prompt */
557
558         if (el->el_flags & EDIT_DISABLED) {
559                 char *cp = el->el_line.buffer;
560                 size_t idx;
561
562                 term__flush();
563
564                 while (read_char(el, cp) == 1) {
565                         /* make sure there is space next character */
566                         if (cp + 1 >= el->el_line.limit) {
567                                 idx = (cp - el->el_line.buffer);
568                                 if (!ch_enlargebufs(el, 2))
569                                         break;
570                                 cp = &el->el_line.buffer[idx];
571                         }
572                         cp++;
573                         if (cp[-1] == '\r' || cp[-1] == '\n')
574                                 break;
575                 }
576
577                 el->el_line.cursor = el->el_line.lastchar = cp;
578                 *cp = '\0';
579                 if (nread)
580                         *nread = el->el_line.cursor - el->el_line.buffer;
581                 return (el->el_line.buffer);
582         }
583  eagain_resume:
584         for (num = OKCMD; num == OKCMD;) {      /* while still editing this
585                                                  * line */
586 #ifdef DEBUG_EDIT
587                 read_debug(el);
588 #endif /* DEBUG_EDIT */
589                 /* if EOF or error */
590                 if ((num = read_getcmd(el, &cmdnum, &ch)) != OKCMD) {
591 #ifdef DEBUG_READ
592                         (void) el->el_err_printf(el,
593                             "Returning from el_gets %d\r\n", num);
594 #endif /* DEBUG_READ */
595                         if(num == EAGAINCMD) {
596                                 el->el_nb_state = EAGAINCMD;
597                                 return NULL;
598                         }
599                         break;
600                 }
601                 el_gets_dispatch(el, cmdnum, ch, &num);
602         }
603         el->el_nb_state = 0;
604
605                                 /* make sure the tty is set up correctly */
606         (void) tty_cookedmode(el);
607         term__flush();          /* flush any buffered output */
608         if (el->el_flags & HANDLE_SIGNALS)
609                 sig_clr(el);
610         if (nread)
611                 *nread = num;
612         return (num ? el->el_line.buffer : NULL);
613 }
Note: See TracBrowser for help on using the browser.