root/src/noitedit/read.c

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

dead assignments, refs #283

  • 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
223         while (cmd == ED_UNASSIGNED || cmd == ED_SEQUENCE_LEAD_IN) {
224                 if (el_getc(el, ch) != 1) {     /* if EOF or error */
225                         /* So solaris doesn't read -> -1 with EAGAIN when
226                          * no data is ready on the terminal.. it returns 0.
227                          * I'm likely not understanding something, but that
228                          * seems deeply flawed.  Regardless, I cannot think
229                          * of a case where we'd want to return something other
230                          * than EAGAINCMD... this seems "more correct" than
231                          * only returning it whe errno == EAGAIN
232
233                                 if(errno == EAGAIN) return EAGAINCMD;
234                                 return (num);
235
236                          */
237                         return EAGAINCMD;
238                 }
239                
240 #ifdef  KANJI
241                 if ((*ch & 0200)) {
242                         el->el_state.metanext = 0;
243                         cmd = CcViMap[' '];
244                         break;
245                 } else
246 #endif /* KANJI */
247
248                 if (el->el_state.metanext) {
249                         el->el_state.metanext = 0;
250                         *ch |= 0200;
251                 }
252                 cmd = el->el_map.current[(unsigned char) *ch];
253                 if (cmd == ED_SEQUENCE_LEAD_IN || el->el_keystate) {
254                         key_value_t val;
255                         switch (key_get(el, ch, &val)) {
256                         case XK_CMD:
257                                 cmd = val.cmd;
258                                 break;
259                         case XK_STR:
260                                 el_push(el, val.str);
261                                 break;
262 #ifdef notyet
263                         case XK_EXE:
264                                 /* XXX: In the future to run a user function */
265                                 RunCommand(val.str);
266                                 break;
267 #endif
268                         default:
269                                 EL_ABORT((el->el_errfile, "Bad XK_ type \n"));
270                                 break;
271                         }
272                 }
273                 if (el->el_map.alt == NULL)
274                         el->el_map.current = el->el_map.key;
275
276                 if (cmd == ED_UNASSIGNED && nonblock)
277                         break;
278         }
279         *cmdnum = cmd;
280         return (OKCMD);
281 }
282
283 /* read_getcmd():
284  *      Return next command from the input stream.
285  */
286 private int
287 read_getcmd(EditLine *el, el_action_t *cmdnum, char *ch)
288 {
289         return el_internal_read_getcmd(el, cmdnum, ch, 0);
290 }
291
292
293 /* read_char():
294  *      Read a character from the tty.
295  */
296 private int
297 read_char(EditLine *el, char *cp)
298 {
299         int num_read;
300         int tried = 0;
301
302         do {
303                 int mask;
304                 if(el->el_in_e)
305                         num_read = el->
306                                 el_in_e->
307                                 opset->
308                                 read(el->el_in_e->fd, cp, 1,
309                                     &mask, el->el_in_e);
310                 else
311                         num_read = read(el->el_infd, cp, 1);
312
313                 if (num_read)
314                         break;
315                 if (num_read == -1) {
316                         if (errno == EAGAIN) return 0;
317                         if (!tried && read__fixio(el->el_infd, errno) == 0) {
318                                 tried = 1;
319                         } else {
320                                 *cp = '\0';
321                                 return -1;
322                         }
323                 }
324         } while (num_read == -1);
325
326         return (num_read);
327 }
328
329 public int el_internal_read_char(EditLine *el, char *cp)
330 {
331         return read_char(el, cp);
332 }
333
334 /* el_getc():
335  *      Read a character
336  */
337 public int
338 el_getc(EditLine *el, char *cp)
339 {
340         int num_read;
341         c_macro_t *ma = &el->el_chared.c_macro;
342
343         term__flush();
344         for (;;) {
345                 if (ma->level < 0) {
346                         if (!read_preread(el))
347                                 break;
348                 }
349                 if (ma->level < 0)
350                         break;
351
352                 if (*ma->macro[ma->level] == 0) {
353                         ma->level--;
354                         continue;
355                 }
356                 *cp = *ma->macro[ma->level]++ & 0377;
357                 if (*ma->macro[ma->level] == 0) {       /* Needed for QuoteMode
358                                                          * On */
359                         ma->level--;
360                 }
361                 return (1);
362         }
363
364 #ifdef DEBUG_READ
365         (void) el->el_err_printf(el, "Turning raw mode on\r\n");
366 #endif /* DEBUG_READ */
367         if (tty_rawmode(el) < 0)/* make sure the tty is set up correctly */
368                 return (0);
369
370 #ifdef DEBUG_READ
371         (void) el->el_err_printf(el, "Reading a character\r\n");
372 #endif /* DEBUG_READ */
373         num_read = read_char(el, cp);
374 #ifdef DEBUG_READ
375         (void) el->el_err_printf(el, "Got it(%d) [%02x]\r\n",
376                                  (int)num_read, (unsigned char)*cp);
377 #endif /* DEBUG_READ */
378         return (num_read);
379 }
380
381 public int el_gets_dispatch(EditLine *el, el_action_t cmdnum, char ch, int *num)
382 {
383         int retval;
384
385         if ((int) cmdnum >= el->el_map.nfunc) { /* BUG CHECK command */
386 #ifdef DEBUG_EDIT
387                 (void) el->el_err_printf(el,
388                                            "ERROR: illegal command from key 0%o\r\n", ch);
389 #endif /* DEBUG_EDIT */
390                 return 0;       /* try again */
391         }
392         /* now do the real command */
393 #ifdef DEBUG_READ
394         {
395                 el_bindings_t *b;
396                 for (b = el->el_map.help; b->name; b++)
397                         if (b->func == cmdnum)
398                                 break;
399                 if (b->name)
400                         (void) el->el_err_printf(el,
401                                                    "Executing %s\r\n", b->name);
402                 else
403                         (void) el->el_err_printf(el,
404                                                    "Error command = %d\r\n", cmdnum);
405         }
406 #endif /* DEBUG_READ */
407         retval = (*el->el_map.func[cmdnum]) (el, ch);
408
409         /* save the last command here */
410         el->el_state.lastcmd = cmdnum;
411
412         /* use any return value */
413         switch (retval) {
414                 case CC_CURSOR:
415                         el->el_state.argument = 1;
416                         el->el_state.doingarg = 0;
417                         re_refresh_cursor(el);
418                         break;
419
420                 case CC_REDISPLAY:
421                         re_clear_lines(el);
422                         re_clear_display(el);
423                         /* FALLTHROUGH */
424
425                 case CC_REFRESH:
426                         el->el_state.argument = 1;
427                         el->el_state.doingarg = 0;
428                         re_refresh(el);
429                         break;
430
431                 case CC_REFRESH_BEEP:
432                         el->el_state.argument = 1;
433                         el->el_state.doingarg = 0;
434                         re_refresh(el);
435                         term_beep(el);
436                         break;
437
438                 case CC_NORM:   /* normal char */
439                         el->el_state.argument = 1;
440                         el->el_state.doingarg = 0;
441                         break;
442
443                 case CC_ARGHACK:        /* Suggested by Rich Salz */
444                         /* <rsalz@pineapple.bbn.com> */
445                         break;  /* keep going... */
446
447                 case CC_EOF:    /* end of file typed */
448                         *num = 0;
449                         break;
450
451                 case CC_NEWLINE:        /* normal end of line */
452                         *num = el->el_line.lastchar - el->el_line.buffer;
453                         break;
454
455                 case CC_FATAL:  /* fatal error, reset to known state */
456 #ifdef DEBUG_READ
457                         (void) el->el_err_printf(el,
458                                                    "*** editor fatal ERROR ***\r\n\r\n");
459 #endif /* DEBUG_READ */
460                         /* put (real) cursor in a known place */
461                         re_clear_display(el);   /* reset the display stuff */
462                         ch_reset(el);   /* reset the input pointers */
463                         re_refresh(el); /* print the prompt again */
464                         el->el_state.argument = 1;
465                         el->el_state.doingarg = 0;
466                         break;
467
468                 case CC_ERROR:
469                 default:        /* functions we don't know about */
470 #ifdef DEBUG_READ
471                         (void) el->el_err_printf(el,
472                                                    "*** editor ERROR ***\r\n\r\n");
473 #endif /* DEBUG_READ */
474                         el->el_state.argument = 1;
475                         el->el_state.doingarg = 0;
476                         term_beep(el);
477                         term__flush();
478                         break;
479         }
480         return 1;
481 }
482
483 public int
484 el_eagain(EditLine *el)
485 {
486         return ISEAGAIN(el);
487 }
488
489 public const char *
490 el_gets(EditLine *el, int *nread)
491 {
492         el_action_t cmdnum = 0;
493         int num;                /* how many chars we have read at NL */
494         char ch;
495 #ifdef FIONREAD
496         c_macro_t *ma = &el->el_chared.c_macro;
497 #endif /* FIONREAD */
498
499         if (nread)
500                 *nread = 0;
501
502         if(el_eagain(el)) {
503                 el->el_nb_state = 0;
504                 goto eagain_resume;
505         }
506
507         if (el->el_flags & HANDLE_SIGNALS)
508                 sig_set(el);
509
510         if (el->el_flags & NO_TTY) {
511                 char *cp = el->el_line.buffer;
512                 size_t idx;
513
514 #if _WIN32
515                 printf("%s", el->el_prompt.p_func(el));
516 #endif
517
518                 while (read_char(el, cp) == 1) {
519                         /* make sure there is space for next character */
520                         if (cp + 1 >= el->el_line.limit) {
521                                 idx = (cp - el->el_line.buffer);
522                                 if (!ch_enlargebufs(el, 2))
523                                         break;
524                                 cp = &el->el_line.buffer[idx];
525                         }
526                         cp++;
527                         if (cp[-1] == '\r' || cp[-1] == '\n')
528                                 break;
529                 }
530
531                 el->el_line.cursor = el->el_line.lastchar = cp;
532                 *cp = '\0';
533                 if (nread)
534                         *nread = el->el_line.cursor - el->el_line.buffer;
535                 return (el->el_line.buffer);
536         }
537         re_clear_display(el);   /* reset the display stuff */
538         ch_reset(el);
539
540 #ifdef FIONREAD
541         if (el->el_tty.t_mode == EX_IO && ma->level < 0) {
542                 long chrs = 0;
543
544                 (void) ioctl(el->el_infd, FIONREAD, (ioctl_t) & chrs);
545                 if (chrs == 0) {
546                         if (tty_rawmode(el) < 0) {
547                                 if (nread)
548                                         *nread = 0;
549                                 return (NULL);
550                         }
551                 }
552         }
553 #endif /* FIONREAD */
554
555         re_refresh(el);         /* print the prompt */
556
557         if (el->el_flags & EDIT_DISABLED) {
558                 char *cp = el->el_line.buffer;
559                 size_t idx;
560
561                 term__flush();
562
563                 while (read_char(el, cp) == 1) {
564                         /* make sure there is space next character */
565                         if (cp + 1 >= el->el_line.limit) {
566                                 idx = (cp - el->el_line.buffer);
567                                 if (!ch_enlargebufs(el, 2))
568                                         break;
569                                 cp = &el->el_line.buffer[idx];
570                         }
571                         cp++;
572                         if (cp[-1] == '\r' || cp[-1] == '\n')
573                                 break;
574                 }
575
576                 el->el_line.cursor = el->el_line.lastchar = cp;
577                 *cp = '\0';
578                 if (nread)
579                         *nread = el->el_line.cursor - el->el_line.buffer;
580                 return (el->el_line.buffer);
581         }
582  eagain_resume:
583         for (num = OKCMD; num == OKCMD;) {      /* while still editing this
584                                                  * line */
585 #ifdef DEBUG_EDIT
586                 read_debug(el);
587 #endif /* DEBUG_EDIT */
588                 /* if EOF or error */
589                 if ((num = read_getcmd(el, &cmdnum, &ch)) != OKCMD) {
590 #ifdef DEBUG_READ
591                         (void) el->el_err_printf(el,
592                             "Returning from el_gets %d\r\n", num);
593 #endif /* DEBUG_READ */
594                         if(num == EAGAINCMD) {
595                                 el->el_nb_state = EAGAINCMD;
596                                 return NULL;
597                         }
598                         break;
599                 }
600                 el_gets_dispatch(el, cmdnum, ch, &num);
601         }
602         el->el_nb_state = 0;
603
604                                 /* make sure the tty is set up correctly */
605         (void) tty_cookedmode(el);
606         term__flush();          /* flush any buffered output */
607         if (el->el_flags & HANDLE_SIGNALS)
608                 sig_clr(el);
609         if (nread)
610                 *nread = num;
611         return (num ? el->el_line.buffer : NULL);
612 }
Note: See TracBrowser for help on using the browser.