]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libedit/read.c
Followup to r347996
[FreeBSD/FreeBSD.git] / lib / libedit / read.c
1 /*      $NetBSD: read.c,v 1.86 2016/03/02 19:24:20 christos 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. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34
35 #include "config.h"
36 #if !defined(lint) && !defined(SCCSID)
37 #if 0
38 static char sccsid[] = "@(#)read.c      8.1 (Berkeley) 6/4/93";
39 #else
40 __RCSID("$NetBSD: read.c,v 1.86 2016/03/02 19:24:20 christos Exp $");
41 #endif
42 #endif /* not lint && not SCCSID */
43 #include <sys/cdefs.h>
44 __FBSDID("$FreeBSD$");
45
46 /*
47  * read.c: Clean this junk up! This is horrible code.
48  *         Terminal read functions
49  */
50 #include <ctype.h>
51 #include <errno.h>
52 #include <fcntl.h>
53 #include <limits.h>
54 #include <stdlib.h>
55 #include <string.h>
56 #include <unistd.h>
57
58 #include "el.h"
59
60 #define OKCMD   -1      /* must be -1! */
61
62 private int     read__fixio(int, int);
63 private int     read_preread(EditLine *);
64 private int     read_char(EditLine *, wchar_t *);
65 private int     read_getcmd(EditLine *, el_action_t *, Char *);
66 private void    read_pop(c_macro_t *);
67
68 /* read_init():
69  *      Initialize the read stuff
70  */
71 protected int
72 read_init(EditLine *el)
73 {
74         /* builtin read_char */
75         el->el_read.read_char = read_char;
76         return 0;
77 }
78
79
80 /* el_read_setfn():
81  *      Set the read char function to the one provided.
82  *      If it is set to EL_BUILTIN_GETCFN, then reset to the builtin one.
83  */
84 protected int
85 el_read_setfn(EditLine *el, el_rfunc_t rc)
86 {
87         el->el_read.read_char = (rc == EL_BUILTIN_GETCFN) ? read_char : rc;
88         return 0;
89 }
90
91
92 /* el_read_getfn():
93  *      return the current read char function, or EL_BUILTIN_GETCFN
94  *      if it is the default one
95  */
96 protected el_rfunc_t
97 el_read_getfn(EditLine *el)
98 {
99        return el->el_read.read_char == read_char ?
100             EL_BUILTIN_GETCFN : el->el_read.read_char;
101 }
102
103
104 #ifndef MIN
105 #define MIN(A,B) ((A) < (B) ? (A) : (B))
106 #endif
107
108 #ifdef DEBUG_EDIT
109 private void
110 read_debug(EditLine *el)
111 {
112
113         if (el->el_line.cursor > el->el_line.lastchar)
114                 (void) fprintf(el->el_errfile, "cursor > lastchar\r\n");
115         if (el->el_line.cursor < el->el_line.buffer)
116                 (void) fprintf(el->el_errfile, "cursor < buffer\r\n");
117         if (el->el_line.cursor > el->el_line.limit)
118                 (void) fprintf(el->el_errfile, "cursor > limit\r\n");
119         if (el->el_line.lastchar > el->el_line.limit)
120                 (void) fprintf(el->el_errfile, "lastchar > limit\r\n");
121         if (el->el_line.limit != &el->el_line.buffer[EL_BUFSIZ - 2])
122                 (void) fprintf(el->el_errfile, "limit != &buffer[EL_BUFSIZ-2]\r\n");
123 }
124 #endif /* DEBUG_EDIT */
125
126
127 /* read__fixio():
128  *      Try to recover from a read error
129  */
130 /* ARGSUSED */
131 private int
132 read__fixio(int fd __attribute__((__unused__)), int e)
133 {
134
135         switch (e) {
136         case -1:                /* Make sure that the code is reachable */
137
138 #ifdef EWOULDBLOCK
139         case EWOULDBLOCK:
140 #ifndef TRY_AGAIN
141 #define TRY_AGAIN
142 #endif
143 #endif /* EWOULDBLOCK */
144
145 #if defined(POSIX) && defined(EAGAIN)
146 #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
147         case EAGAIN:
148 #ifndef TRY_AGAIN
149 #define TRY_AGAIN
150 #endif
151 #endif /* EWOULDBLOCK && EWOULDBLOCK != EAGAIN */
152 #endif /* POSIX && EAGAIN */
153
154                 e = 0;
155 #ifdef TRY_AGAIN
156 #if defined(F_SETFL) && defined(O_NDELAY)
157                 if ((e = fcntl(fd, F_GETFL, 0)) == -1)
158                         return -1;
159
160                 if (fcntl(fd, F_SETFL, e & ~O_NDELAY) == -1)
161                         return -1;
162                 else
163                         e = 1;
164 #endif /* F_SETFL && O_NDELAY */
165
166 #ifdef FIONBIO
167                 {
168                         int zero = 0;
169
170                         if (ioctl(fd, FIONBIO, &zero) == -1)
171                                 return -1;
172                         else
173                                 e = 1;
174                 }
175 #endif /* FIONBIO */
176
177 #endif /* TRY_AGAIN */
178                 return e ? 0 : -1;
179
180         case EINTR:
181                 return 0;
182
183         default:
184                 return -1;
185         }
186 }
187
188
189 /* read_preread():
190  *      Try to read the stuff in the input queue;
191  */
192 private int
193 read_preread(EditLine *el)
194 {
195         int chrs = 0;
196
197         if (el->el_tty.t_mode == ED_IO)
198                 return 0;
199
200 #ifndef WIDECHAR
201 /* FIONREAD attempts to buffer up multiple bytes, and to make that work
202  * properly with partial wide/UTF-8 characters would need some careful work. */
203 #ifdef FIONREAD
204         (void) ioctl(el->el_infd, FIONREAD, &chrs);
205         if (chrs > 0) {
206                 char buf[EL_BUFSIZ];
207
208                 chrs = read(el->el_infd, buf,
209                     (size_t) MIN(chrs, EL_BUFSIZ - 1));
210                 if (chrs > 0) {
211                         buf[chrs] = '\0';
212                         el_push(el, buf);
213                 }
214         }
215 #endif /* FIONREAD */
216 #endif
217         return chrs > 0;
218 }
219
220
221 /* el_push():
222  *      Push a macro
223  */
224 public void
225 FUN(el,push)(EditLine *el, const Char *str)
226 {
227         c_macro_t *ma = &el->el_chared.c_macro;
228
229         if (str != NULL && ma->level + 1 < EL_MAXMACRO) {
230                 ma->level++;
231                 if ((ma->macro[ma->level] = Strdup(str)) != NULL)
232                         return;
233                 ma->level--;
234         }
235         terminal_beep(el);
236         terminal__flush(el);
237 }
238
239
240 /* read_getcmd():
241  *      Get next command from the input stream, return OKCMD on success.
242  *      Character values > 255 are not looked up in the map, but inserted.
243  */
244 private int
245 read_getcmd(EditLine *el, el_action_t *cmdnum, Char *ch)
246 {
247         static const Char meta = (Char)0x80;
248         el_action_t cmd;
249         wchar_t wc;
250         int num;
251
252         el->el_errno = 0;
253         do {
254                 if ((num = el_wgetc(el, &wc)) != 1) {/* if EOF or error */
255                         el->el_errno = num == 0 ? 0 : errno;
256                         return 0;       /* not OKCMD */
257                 }
258                 *ch = (Char)wc;
259
260 #ifdef  KANJI
261                 if ((*ch & meta)) {
262                         el->el_state.metanext = 0;
263                         cmd = CcViMap[' '];
264                         break;
265                 } else
266 #endif /* KANJI */
267
268                 if (el->el_state.metanext) {
269                         el->el_state.metanext = 0;
270                         *ch |= meta;
271                 }
272 #ifdef WIDECHAR
273                 if (*ch >= N_KEYS)
274                         cmd = ED_INSERT;
275                 else
276 #endif
277                         cmd = el->el_map.current[(unsigned char) *ch];
278                 if (cmd == ED_SEQUENCE_LEAD_IN) {
279                         keymacro_value_t val;
280                         switch (keymacro_get(el, ch, &val)) {
281                         case XK_CMD:
282                                 cmd = val.cmd;
283                                 break;
284                         case XK_STR:
285                                 FUN(el,push)(el, val.str);
286                                 break;
287 #ifdef notyet
288                         case XK_EXE:
289                                 /* XXX: In the future to run a user function */
290                                 RunCommand(val.str);
291                                 break;
292 #endif
293                         default:
294                                 EL_ABORT((el->el_errfile, "Bad XK_ type \n"));
295                                 break;
296                         }
297                 }
298                 if (el->el_map.alt == NULL)
299                         el->el_map.current = el->el_map.key;
300         } while (cmd == ED_SEQUENCE_LEAD_IN);
301         *cmdnum = cmd;
302         return OKCMD;
303 }
304
305 /* read_char():
306  *      Read a character from the tty.
307  */
308 private int
309 read_char(EditLine *el, wchar_t *cp)
310 {
311         ssize_t num_read;
312         int tried = 0;
313         char cbuf[MB_LEN_MAX];
314         size_t cbp = 0;
315         int save_errno = errno;
316
317  again:
318         el->el_signal->sig_no = 0;
319         while ((num_read = read(el->el_infd, cbuf + cbp, (size_t)1)) == -1) {
320                 int e = errno;
321                 switch (el->el_signal->sig_no) {
322                 case SIGCONT:
323                         FUN(el,set)(el, EL_REFRESH);
324                         /*FALLTHROUGH*/
325                 case SIGWINCH:
326                         sig_set(el);
327                         goto again;
328                 default:
329                         break;
330                 }
331                 if (!tried && read__fixio(el->el_infd, e) == 0) {
332                         errno = save_errno;
333                         tried = 1;
334                 } else {
335                         errno = e;
336                         *cp = L'\0';
337                         return -1;
338                 }
339         }
340
341         /* Test for EOF */
342         if (num_read == 0) {
343                 *cp = L'\0';
344                 return 0;
345         }
346
347         for (;;) {
348
349                 ++cbp;
350                 switch (ct_mbrtowc(cp, cbuf, cbp)) {
351                 case (size_t)-1:
352                         if (cbp > 1) {
353                                 /*
354                                  * Invalid sequence, discard all bytes
355                                  * except the last one.
356                                  */
357                                 cbuf[0] = cbuf[cbp - 1];
358                                 cbp = 0;
359                                 break;
360                         } else {
361                                 /* Invalid byte, discard it. */
362                                 cbp = 0;
363                                 goto again;
364                         }
365                 case (size_t)-2:
366                         if (cbp >= MB_LEN_MAX) {
367                                 errno = EILSEQ;
368                                 *cp = L'\0';
369                                 return -1;
370                         }
371                         /* Incomplete sequence, read another byte. */
372                         goto again;
373                 default:
374                         /* Valid character, process it. */
375                         return 1;
376                 }
377         }
378 }
379
380 /* read_pop():
381  *      Pop a macro from the stack
382  */
383 private void
384 read_pop(c_macro_t *ma)
385 {
386         int i;
387
388         el_free(ma->macro[0]);
389         for (i = 0; i < ma->level; i++)
390                 ma->macro[i] = ma->macro[i + 1];
391         ma->level--;
392         ma->offset = 0;
393 }
394
395 /* el_wgetc():
396  *      Read a wide character
397  */
398 public int
399 el_wgetc(EditLine *el, wchar_t *cp)
400 {
401         int num_read;
402         c_macro_t *ma = &el->el_chared.c_macro;
403
404         terminal__flush(el);
405         for (;;) {
406                 if (ma->level < 0) {
407                         if (!read_preread(el))
408                                 break;
409                 }
410
411                 if (ma->level < 0)
412                         break;
413
414                 if (ma->macro[0][ma->offset] == '\0') {
415                         read_pop(ma);
416                         continue;
417                 }
418
419                 *cp = ma->macro[0][ma->offset++];
420
421                 if (ma->macro[0][ma->offset] == '\0') {
422                         /* Needed for QuoteMode On */
423                         read_pop(ma);
424                 }
425
426                 return 1;
427         }
428
429 #ifdef DEBUG_READ
430         (void) fprintf(el->el_errfile, "Turning raw mode on\n");
431 #endif /* DEBUG_READ */
432         if (tty_rawmode(el) < 0)/* make sure the tty is set up correctly */
433                 return 0;
434
435 #ifdef DEBUG_READ
436         (void) fprintf(el->el_errfile, "Reading a character\n");
437 #endif /* DEBUG_READ */
438         num_read = (*el->el_read.read_char)(el, cp);
439         if (num_read < 0)
440                 el->el_errno = errno;
441 #ifdef DEBUG_READ
442         (void) fprintf(el->el_errfile, "Got it %lc\n", *cp);
443 #endif /* DEBUG_READ */
444         return num_read;
445 }
446
447 protected void
448 read_prepare(EditLine *el)
449 {
450         if (el->el_flags & HANDLE_SIGNALS)
451                 sig_set(el);
452         if (el->el_flags & NO_TTY)
453                 return;
454         if ((el->el_flags & (UNBUFFERED|EDIT_DISABLED)) == UNBUFFERED)
455                 tty_rawmode(el);
456
457         /* This is relatively cheap, and things go terribly wrong if
458            we have the wrong size. */
459         el_resize(el);
460         re_clear_display(el);   /* reset the display stuff */
461         ch_reset(el, 0);
462         re_refresh(el);         /* print the prompt */
463
464         if (el->el_flags & UNBUFFERED)
465                 terminal__flush(el);
466 }
467
468 protected void
469 read_finish(EditLine *el)
470 {
471         if ((el->el_flags & UNBUFFERED) == 0)
472                 (void) tty_cookedmode(el);
473         if (el->el_flags & HANDLE_SIGNALS)
474                 sig_clr(el);
475 }
476
477 public const Char *
478 FUN(el,gets)(EditLine *el, int *nread)
479 {
480         int retval;
481         el_action_t cmdnum = 0;
482         int num;                /* how many chars we have read at NL */
483         wchar_t wc;
484         Char ch, *cp;
485         int crlf = 0;
486         int nrb;
487 #ifdef FIONREAD
488         c_macro_t *ma = &el->el_chared.c_macro;
489 #endif /* FIONREAD */
490
491         if (nread == NULL)
492                 nread = &nrb;
493         *nread = 0;
494
495         if (el->el_flags & NO_TTY) {
496                 size_t idx;
497
498                 cp = el->el_line.buffer;
499                 while ((num = (*el->el_read.read_char)(el, &wc)) == 1) {
500                         *cp = (Char)wc;
501                         /* make sure there is space for next character */
502                         if (cp + 1 >= el->el_line.limit) {
503                                 idx = (size_t)(cp - el->el_line.buffer);
504                                 if (!ch_enlargebufs(el, (size_t)2))
505                                         break;
506                                 cp = &el->el_line.buffer[idx];
507                         }
508                         cp++;
509                         if (el->el_flags & UNBUFFERED)
510                                 break;
511                         if (cp[-1] == '\r' || cp[-1] == '\n')
512                                 break;
513                 }
514                 if (num == -1) {
515                         if (errno == EINTR)
516                                 cp = el->el_line.buffer;
517                         el->el_errno = errno;
518                 }
519
520                 goto noedit;
521         }
522
523
524 #ifdef FIONREAD
525         if (el->el_tty.t_mode == EX_IO && ma->level < 0) {
526                 long chrs = 0;
527
528                 (void) ioctl(el->el_infd, FIONREAD, &chrs);
529                 if (chrs == 0) {
530                         if (tty_rawmode(el) < 0) {
531                                 errno = 0;
532                                 *nread = 0;
533                                 return NULL;
534                         }
535                 }
536         }
537 #endif /* FIONREAD */
538
539         if ((el->el_flags & UNBUFFERED) == 0)
540                 read_prepare(el);
541
542         if (el->el_flags & EDIT_DISABLED) {
543                 size_t idx;
544
545                 if ((el->el_flags & UNBUFFERED) == 0)
546                         cp = el->el_line.buffer;
547                 else
548                         cp = el->el_line.lastchar;
549
550                 terminal__flush(el);
551
552                 while ((num = (*el->el_read.read_char)(el, &wc)) == 1) {
553                         *cp = (Char)wc;
554                         /* make sure there is space next character */
555                         if (cp + 1 >= el->el_line.limit) {
556                                 idx = (size_t)(cp - el->el_line.buffer);
557                                 if (!ch_enlargebufs(el, (size_t)2))
558                                         break;
559                                 cp = &el->el_line.buffer[idx];
560                         }
561                         cp++;
562                         crlf = cp[-1] == '\r' || cp[-1] == '\n';
563                         if (el->el_flags & UNBUFFERED)
564                                 break;
565                         if (crlf)
566                                 break;
567                 }
568
569                 if (num == -1) {
570                         if (errno == EINTR)
571                                 cp = el->el_line.buffer;
572                         el->el_errno = errno;
573                 }
574
575                 goto noedit;
576         }
577
578         for (num = OKCMD; num == OKCMD;) {      /* while still editing this
579                                                  * line */
580 #ifdef DEBUG_EDIT
581                 read_debug(el);
582 #endif /* DEBUG_EDIT */
583                 /* if EOF or error */
584                 if ((num = read_getcmd(el, &cmdnum, &ch)) != OKCMD) {
585                         num = -1;
586 #ifdef DEBUG_READ
587                         (void) fprintf(el->el_errfile,
588                             "Returning from el_gets %d\n", num);
589 #endif /* DEBUG_READ */
590                         break;
591                 }
592                 if (el->el_errno == EINTR) {
593                         el->el_line.buffer[0] = '\0';
594                         el->el_line.lastchar =
595                             el->el_line.cursor = el->el_line.buffer;
596                         break;
597                 }
598                 if ((size_t)cmdnum >= el->el_map.nfunc) {       /* BUG CHECK command */
599 #ifdef DEBUG_EDIT
600                         (void) fprintf(el->el_errfile,
601                             "ERROR: illegal command from key 0%o\r\n", ch);
602 #endif /* DEBUG_EDIT */
603                         continue;       /* try again */
604                 }
605                 /* now do the real command */
606 #ifdef DEBUG_READ
607                 {
608                         el_bindings_t *b;
609                         for (b = el->el_map.help; b->name; b++)
610                                 if (b->func == cmdnum)
611                                         break;
612                         if (b->name)
613                                 (void) fprintf(el->el_errfile,
614                                     "Executing " FSTR "\n", b->name);
615                         else
616                                 (void) fprintf(el->el_errfile,
617                                     "Error command = %d\n", cmdnum);
618                 }
619 #endif /* DEBUG_READ */
620                 /* vi redo needs these way down the levels... */
621                 el->el_state.thiscmd = cmdnum;
622                 el->el_state.thisch = ch;
623                 if (el->el_map.type == MAP_VI &&
624                     el->el_map.current == el->el_map.key &&
625                     el->el_chared.c_redo.pos < el->el_chared.c_redo.lim) {
626                         if (cmdnum == VI_DELETE_PREV_CHAR &&
627                             el->el_chared.c_redo.pos != el->el_chared.c_redo.buf
628                             && Isprint(el->el_chared.c_redo.pos[-1]))
629                                 el->el_chared.c_redo.pos--;
630                         else
631                                 *el->el_chared.c_redo.pos++ = ch;
632                 }
633                 retval = (*el->el_map.func[cmdnum]) (el, ch);
634 #ifdef DEBUG_READ
635                 (void) fprintf(el->el_errfile,
636                         "Returned state %d\n", retval );
637 #endif /* DEBUG_READ */
638
639                 /* save the last command here */
640                 el->el_state.lastcmd = cmdnum;
641
642                 /* use any return value */
643                 switch (retval) {
644                 case CC_CURSOR:
645                         re_refresh_cursor(el);
646                         break;
647
648                 case CC_REDISPLAY:
649                         re_clear_lines(el);
650                         re_clear_display(el);
651                         /* FALLTHROUGH */
652
653                 case CC_REFRESH:
654                         re_refresh(el);
655                         break;
656
657                 case CC_REFRESH_BEEP:
658                         re_refresh(el);
659                         terminal_beep(el);
660                         break;
661
662                 case CC_NORM:   /* normal char */
663                         break;
664
665                 case CC_ARGHACK:        /* Suggested by Rich Salz */
666                         /* <rsalz@pineapple.bbn.com> */
667                         continue;       /* keep going... */
668
669                 case CC_EOF:    /* end of file typed */
670                         if ((el->el_flags & UNBUFFERED) == 0)
671                                 num = 0;
672                         else if (num == -1) {
673                                 *el->el_line.lastchar++ = CONTROL('d');
674                                 el->el_line.cursor = el->el_line.lastchar;
675                                 num = 1;
676                         }
677                         break;
678
679                 case CC_NEWLINE:        /* normal end of line */
680                         num = (int)(el->el_line.lastchar - el->el_line.buffer);
681                         break;
682
683                 case CC_FATAL:  /* fatal error, reset to known state */
684 #ifdef DEBUG_READ
685                         (void) fprintf(el->el_errfile,
686                             "*** editor fatal ERROR ***\r\n\n");
687 #endif /* DEBUG_READ */
688                         /* put (real) cursor in a known place */
689                         re_clear_display(el);   /* reset the display stuff */
690                         ch_reset(el, 1);        /* reset the input pointers */
691                         re_refresh(el); /* print the prompt again */
692                         break;
693
694                 case CC_ERROR:
695                 default:        /* functions we don't know about */
696 #ifdef DEBUG_READ
697                         (void) fprintf(el->el_errfile,
698                             "*** editor ERROR ***\r\n\n");
699 #endif /* DEBUG_READ */
700                         terminal_beep(el);
701                         terminal__flush(el);
702                         break;
703                 }
704                 el->el_state.argument = 1;
705                 el->el_state.doingarg = 0;
706                 el->el_chared.c_vcmd.action = NOP;
707                 if (el->el_flags & UNBUFFERED)
708                         break;
709         }
710
711         terminal__flush(el);            /* flush any buffered output */
712         /* make sure the tty is set up correctly */
713         if ((el->el_flags & UNBUFFERED) == 0) {
714                 read_finish(el);
715                 *nread = num != -1 ? num : 0;
716         } else {
717                 *nread = (int)(el->el_line.lastchar - el->el_line.buffer);
718         }
719         goto done;
720 noedit:
721         el->el_line.cursor = el->el_line.lastchar = cp;
722         *cp = '\0';
723         *nread = (int)(el->el_line.cursor - el->el_line.buffer);
724 done:
725         if (*nread == 0) {
726                 if (num == -1) {
727                         *nread = -1;
728                         errno = el->el_errno;
729                 }
730                 return NULL;
731         } else
732                 return el->el_line.buffer;
733 }