Updated libedit to NetBSD upstream

Note: This unconditionally assumes wchar_t support.  May need revision
if some platforms prove problematic.
This commit is contained in:
Viktor Dukhovni
2016-11-13 15:49:16 +11:00
parent e1c1cdb1b6
commit 77ff7185d7
55 changed files with 6113 additions and 4536 deletions

View File

@@ -1,4 +1,4 @@
/* $NetBSD: read.c,v 1.58 2011/02/18 20:53:05 christos Exp $ */
/* $NetBSD: read.c,v 1.101 2016/05/25 13:01:11 christos Exp $ */
/*-
* Copyright (c) 1992, 1993
@@ -37,49 +37,90 @@
#if 0
static char sccsid[] = "@(#)read.c 8.1 (Berkeley) 6/4/93";
#else
__RCSID("$NetBSD: read.c,v 1.58 2011/02/18 20:53:05 christos Exp $");
__RCSID("$NetBSD: read.c,v 1.101 2016/05/25 13:01:11 christos Exp $");
#endif
#endif /* not lint && not SCCSID */
/*
* read.c: Clean this junk up! This is horrible code.
* Terminal read functions
* read.c: Terminal read functions
*/
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "el.h"
#include "fcns.h"
#include "read.h"
#define OKCMD -1 /* must be -1! */
#define EL_MAXMACRO 10
private int read__fixio(int, int);
private int read_preread(EditLine *);
private int read_char(EditLine *, Char *);
private int read_getcmd(EditLine *, el_action_t *, Char *);
private void read_pop(c_macro_t *);
struct macros {
wchar_t **macro;
int level;
int offset;
};
struct el_read_t {
struct macros macros;
el_rfunc_t read_char; /* Function to read a character. */
int read_errno;
};
static int read__fixio(int, int);
static int read_char(EditLine *, wchar_t *);
static int read_getcmd(EditLine *, el_action_t *, wchar_t *);
static void read_clearmacros(struct macros *);
static void read_pop(struct macros *);
static const wchar_t *noedit_wgets(EditLine *, int *);
/* read_init():
* Initialize the read stuff
*/
protected int
libedit_private int
read_init(EditLine *el)
{
struct macros *ma;
if ((el->el_read = el_malloc(sizeof(*el->el_read))) == NULL)
return -1;
ma = &el->el_read->macros;
if ((ma->macro = el_malloc(EL_MAXMACRO *
sizeof(*ma->macro))) == NULL) {
free(el->el_read);
return -1;
}
ma->level = -1;
ma->offset = 0;
/* builtin read_char */
el->el_read.read_char = read_char;
el->el_read->read_char = read_char;
return 0;
}
/* el_read_end():
* Free the data structures used by the read stuff.
*/
libedit_private void
read_end(struct el_read_t *el_read)
{
read_clearmacros(&el_read->macros);
el_free(el_read->macros.macro);
el_read->macros.macro = NULL;
}
/* el_read_setfn():
* Set the read char function to the one provided.
* If it is set to EL_BUILTIN_GETCFN, then reset to the builtin one.
*/
protected int
el_read_setfn(EditLine *el, el_rfunc_t rc)
libedit_private int
el_read_setfn(struct el_read_t *el_read, el_rfunc_t rc)
{
el->el_read.read_char = (rc == EL_BUILTIN_GETCFN) ? read_char : rc;
el_read->read_char = (rc == EL_BUILTIN_GETCFN) ? read_char : rc;
return 0;
}
@@ -88,42 +129,19 @@ el_read_setfn(EditLine *el, el_rfunc_t rc)
* return the current read char function, or EL_BUILTIN_GETCFN
* if it is the default one
*/
protected el_rfunc_t
el_read_getfn(EditLine *el)
libedit_private el_rfunc_t
el_read_getfn(struct el_read_t *el_read)
{
return (el->el_read.read_char == read_char) ?
EL_BUILTIN_GETCFN : el->el_read.read_char;
return el_read->read_char == read_char ?
EL_BUILTIN_GETCFN : el_read->read_char;
}
#ifndef MIN
#define MIN(A,B) ((A) < (B) ? (A) : (B))
#endif
#ifdef DEBUG_EDIT
private void
read_debug(EditLine *el)
{
if (el->el_line.cursor > el->el_line.lastchar)
(void) fprintf(el->el_errfile, "cursor > lastchar\r\n");
if (el->el_line.cursor < el->el_line.buffer)
(void) fprintf(el->el_errfile, "cursor < buffer\r\n");
if (el->el_line.cursor > el->el_line.limit)
(void) fprintf(el->el_errfile, "cursor > limit\r\n");
if (el->el_line.lastchar > el->el_line.limit)
(void) fprintf(el->el_errfile, "lastchar > limit\r\n");
if (el->el_line.limit != &el->el_line.buffer[EL_BUFSIZ - 2])
(void) fprintf(el->el_errfile, "limit != &buffer[EL_BUFSIZ-2]\r\n");
}
#endif /* DEBUG_EDIT */
/* read__fixio():
* Try to recover from a read error
*/
/* ARGSUSED */
private int
static int
read__fixio(int fd __attribute__((__unused__)), int e)
{
@@ -133,7 +151,7 @@ read__fixio(int fd __attribute__((__unused__)), int e)
#ifdef EWOULDBLOCK
case EWOULDBLOCK:
#ifndef TRY_AGAIN
#define TRY_AGAIN
#define TRY_AGAIN
#endif
#endif /* EWOULDBLOCK */
@@ -141,7 +159,7 @@ read__fixio(int fd __attribute__((__unused__)), int e)
#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
case EAGAIN:
#ifndef TRY_AGAIN
#define TRY_AGAIN
#define TRY_AGAIN
#endif
#endif /* EWOULDBLOCK && EWOULDBLOCK != EAGAIN */
#endif /* POSIX && EAGAIN */
@@ -150,10 +168,10 @@ read__fixio(int fd __attribute__((__unused__)), int e)
#ifdef TRY_AGAIN
#if defined(F_SETFL) && defined(O_NDELAY)
if ((e = fcntl(fd, F_GETFL, 0)) == -1)
return (-1);
return -1;
if (fcntl(fd, F_SETFL, e & ~O_NDELAY) == -1)
return (-1);
return -1;
else
e = 1;
#endif /* F_SETFL && O_NDELAY */
@@ -162,95 +180,62 @@ read__fixio(int fd __attribute__((__unused__)), int e)
{
int zero = 0;
if (ioctl(fd, FIONBIO, (ioctl_t) & zero) == -1)
return (-1);
if (ioctl(fd, FIONBIO, &zero) == -1)
return -1;
else
e = 1;
}
#endif /* FIONBIO */
#endif /* TRY_AGAIN */
return (e ? 0 : -1);
return e ? 0 : -1;
case EINTR:
return (0);
return 0;
default:
return (-1);
return -1;
}
}
/* read_preread():
* Try to read the stuff in the input queue;
*/
private int
read_preread(EditLine *el)
{
int chrs = 0;
if (el->el_tty.t_mode == ED_IO)
return (0);
#ifndef WIDECHAR
/* FIONREAD attempts to buffer up multiple bytes, and to make that work
* properly with partial wide/UTF-8 characters would need some careful work. */
#ifdef FIONREAD
(void) ioctl(el->el_infd, FIONREAD, (ioctl_t) & chrs);
if (chrs > 0) {
char buf[EL_BUFSIZ];
chrs = read(el->el_infd, buf,
(size_t) MIN(chrs, EL_BUFSIZ - 1));
if (chrs > 0) {
buf[chrs] = '\0';
el_push(el, buf);
}
}
#endif /* FIONREAD */
#endif
return (chrs > 0);
}
/* el_push():
* Push a macro
*/
public void
FUN(el,push)(EditLine *el, const Char *str)
void
el_wpush(EditLine *el, const wchar_t *str)
{
c_macro_t *ma = &el->el_chared.c_macro;
struct macros *ma = &el->el_read->macros;
if (str != NULL && ma->level + 1 < EL_MAXMACRO) {
ma->level++;
if ((ma->macro[ma->level] = Strdup(str)) != NULL)
if ((ma->macro[ma->level] = wcsdup(str)) != NULL)
return;
ma->level--;
}
term_beep(el);
term__flush(el);
terminal_beep(el);
terminal__flush(el);
}
/* read_getcmd():
* Return next command from the input stream.
* Get next command from the input stream,
* return 0 on success or -1 on EOF or error.
* Character values > 255 are not looked up in the map, but inserted.
*/
private int
read_getcmd(EditLine *el, el_action_t *cmdnum, Char *ch)
static int
read_getcmd(EditLine *el, el_action_t *cmdnum, wchar_t *ch)
{
static const wchar_t meta = (wchar_t)0x80;
el_action_t cmd;
int num;
el->el_errno = 0;
do {
if ((num = FUN(el,getc)(el, ch)) != 1) {/* if EOF or error */
el->el_errno = num == 0 ? 0 : errno;
return (num);
}
if ((num = el_wgetc(el, ch)) != 1)
return -1;
#ifdef KANJI
if ((*ch & 0200)) {
if ((*ch & meta)) {
el->el_state.metanext = 0;
cmd = CcViMap[' '];
break;
@@ -259,71 +244,52 @@ read_getcmd(EditLine *el, el_action_t *cmdnum, Char *ch)
if (el->el_state.metanext) {
el->el_state.metanext = 0;
*ch |= 0200;
*ch |= meta;
}
#ifdef WIDECHAR
if (*ch >= N_KEYS)
cmd = ED_INSERT;
if (*ch >= N_KEYS)
cmd = ED_INSERT;
else
#endif
cmd = el->el_map.current[(unsigned char) *ch];
cmd = el->el_map.current[(unsigned char) *ch];
if (cmd == ED_SEQUENCE_LEAD_IN) {
key_value_t val;
switch (key_get(el, ch, &val)) {
keymacro_value_t val;
switch (keymacro_get(el, ch, &val)) {
case XK_CMD:
cmd = val.cmd;
break;
case XK_STR:
FUN(el,push)(el, val.str);
el_wpush(el, val.str);
break;
#ifdef notyet
case XK_EXE:
/* XXX: In the future to run a user function */
RunCommand(val.str);
break;
#endif
case XK_NOD:
return -1;
default:
EL_ABORT((el->el_errfile, "Bad XK_ type \n"));
break;
}
}
if (el->el_map.alt == NULL)
el->el_map.current = el->el_map.key;
} while (cmd == ED_SEQUENCE_LEAD_IN);
*cmdnum = cmd;
return (OKCMD);
return 0;
}
#ifdef WIDECHAR
/* utf8_islead():
* Test whether a byte is a leading byte of a UTF-8 sequence.
*/
private int
utf8_islead(unsigned char c)
{
return (c < 0x80) || /* single byte char */
(c >= 0xc2 && c <= 0xf4); /* start of multibyte sequence */
}
#endif
/* read_char():
* Read a character from the tty.
*/
private int
read_char(EditLine *el, Char *cp)
static int
read_char(EditLine *el, wchar_t *cp)
{
ssize_t num_read;
int tried = 0;
char cbuf[MB_LEN_MAX];
int cbp = 0;
int bytes = 0;
char cbuf[MB_LEN_MAX];
size_t cbp = 0;
int save_errno = errno;
again:
el->el_signal->sig_no = 0;
while ((num_read = read(el->el_infd, cbuf + cbp, 1)) == -1) {
while ((num_read = read(el->el_infd, cbuf + cbp, (size_t)1)) == -1) {
int e = errno;
switch (el->el_signal->sig_no) {
case SIGCONT:
el_set(el, EL_REFRESH);
el_wset(el, EL_REFRESH);
/*FALLTHROUGH*/
case SIGWINCH:
sig_set(el);
@@ -331,44 +297,69 @@ read_char(EditLine *el, Char *cp)
default:
break;
}
if (!tried && read__fixio(el->el_infd, errno) == 0)
if (!tried && read__fixio(el->el_infd, e) == 0) {
errno = save_errno;
tried = 1;
else {
*cp = '\0';
return (-1);
} else {
errno = e;
*cp = L'\0';
return -1;
}
}
#ifdef WIDECHAR
if (el->el_flags & CHARSET_IS_UTF8) {
if (!utf8_islead((unsigned char)cbuf[0]))
goto again; /* discard the byte we read and try again */
/* Test for EOF */
if (num_read == 0) {
*cp = L'\0';
return 0;
}
for (;;) {
mbstate_t mbs;
++cbp;
if ((bytes = ct_mbtowc(cp, cbuf, cbp)) == -1) {
ct_mbtowc_reset;
if (cbp >= MB_LEN_MAX) { /* "shouldn't happen" */
*cp = '\0';
return (-1);
/* This only works because UTF8 is stateless. */
memset(&mbs, 0, sizeof(mbs));
switch (mbrtowc(cp, cbuf, cbp, &mbs)) {
case (size_t)-1:
if (cbp > 1) {
/*
* Invalid sequence, discard all bytes
* except the last one.
*/
cbuf[0] = cbuf[cbp - 1];
cbp = 0;
break;
} else {
/* Invalid byte, discard it. */
cbp = 0;
goto again;
}
case (size_t)-2:
/*
* We don't support other multibyte charsets.
* The second condition shouldn't happen
* and is here merely for additional safety.
*/
if ((el->el_flags & CHARSET_IS_UTF8) == 0 ||
cbp >= MB_LEN_MAX) {
errno = EILSEQ;
*cp = L'\0';
return -1;
}
/* Incomplete sequence, read another byte. */
goto again;
default:
/* Valid character, process it. */
return 1;
}
} else /* we don't support other multibyte charsets */
#endif
*cp = (unsigned char)cbuf[0];
if ((el->el_flags & IGNORE_EXTCHARS) && bytes > 1) {
cbp = 0; /* skip this character */
goto again;
}
return (int)num_read;
}
/* read_pop():
* Pop a macro from the stack
*/
private void
read_pop(c_macro_t *ma)
static void
read_pop(struct macros *ma)
{
int i;
@@ -379,22 +370,25 @@ read_pop(c_macro_t *ma)
ma->offset = 0;
}
/* el_getc():
* Read a character
*/
public int
FUN(el,getc)(EditLine *el, Char *cp)
static void
read_clearmacros(struct macros *ma)
{
while (ma->level >= 0)
el_free(ma->macro[ma->level--]);
ma->offset = 0;
}
/* el_wgetc():
* Read a wide character
*/
int
el_wgetc(EditLine *el, wchar_t *cp)
{
struct macros *ma = &el->el_read->macros;
int num_read;
c_macro_t *ma = &el->el_chared.c_macro;
term__flush(el);
terminal__flush(el);
for (;;) {
if (ma->level < 0) {
if (!read_preread(el))
break;
}
if (ma->level < 0)
break;
@@ -410,30 +404,26 @@ FUN(el,getc)(EditLine *el, Char *cp)
read_pop(ma);
}
return (1);
return 1;
}
#ifdef DEBUG_READ
(void) fprintf(el->el_errfile, "Turning raw mode on\n");
#endif /* DEBUG_READ */
if (tty_rawmode(el) < 0)/* make sure the tty is set up correctly */
return (0);
return 0;
#ifdef DEBUG_READ
(void) fprintf(el->el_errfile, "Reading a character\n");
#endif /* DEBUG_READ */
num_read = (*el->el_read.read_char)(el, cp);
#ifdef WIDECHAR
if (el->el_flags & NARROW_READ)
*cp = *(char *)(void *)cp;
#endif
#ifdef DEBUG_READ
(void) fprintf(el->el_errfile, "Got it %c\n", *cp);
#endif /* DEBUG_READ */
return (num_read);
num_read = (*el->el_read->read_char)(el, cp);
/*
* Remember the original reason of a read failure
* such that el_wgets() can restore it after doing
* various cleanup operation that might change errno.
*/
if (num_read < 0)
el->el_read->read_errno = errno;
return num_read;
}
protected void
libedit_private void
read_prepare(EditLine *el)
{
if (el->el_flags & HANDLE_SIGNALS)
@@ -447,14 +437,14 @@ read_prepare(EditLine *el)
we have the wrong size. */
el_resize(el);
re_clear_display(el); /* reset the display stuff */
ch_reset(el, 0);
ch_reset(el);
re_refresh(el); /* print the prompt */
if (el->el_flags & UNBUFFERED)
term__flush(el);
terminal__flush(el);
}
protected void
libedit_private void
read_finish(EditLine *el)
{
if ((el->el_flags & UNBUFFERED) == 0)
@@ -463,61 +453,59 @@ read_finish(EditLine *el)
sig_clr(el);
}
public const Char *
FUN(el,gets)(EditLine *el, int *nread)
static const wchar_t *
noedit_wgets(EditLine *el, int *nread)
{
el_line_t *lp = &el->el_line;
int num;
while ((num = (*el->el_read->read_char)(el, lp->lastchar)) == 1) {
if (lp->lastchar + 1 >= lp->limit &&
!ch_enlargebufs(el, (size_t)2))
break;
lp->lastchar++;
if (el->el_flags & UNBUFFERED ||
lp->lastchar[-1] == '\r' ||
lp->lastchar[-1] == '\n')
break;
}
if (num == -1 && errno == EINTR)
lp->lastchar = lp->buffer;
lp->cursor = lp->lastchar;
*lp->lastchar = '\0';
*nread = (int)(lp->lastchar - lp->buffer);
return *nread ? lp->buffer : NULL;
}
const wchar_t *
el_wgets(EditLine *el, int *nread)
{
int retval;
el_action_t cmdnum = 0;
int num; /* how many chars we have read at NL */
Char ch, *cp;
int crlf = 0;
wchar_t ch;
int nrb;
#ifdef FIONREAD
c_macro_t *ma = &el->el_chared.c_macro;
#endif /* FIONREAD */
if (nread == NULL)
nread = &nrb;
*nread = 0;
el->el_read->read_errno = 0;
if (el->el_flags & NO_TTY) {
size_t idx;
cp = el->el_line.buffer;
while ((num = (*el->el_read.read_char)(el, cp)) == 1) {
/* make sure there is space for next character */
if (cp + 1 >= el->el_line.limit) {
idx = (cp - el->el_line.buffer);
if (!ch_enlargebufs(el, 2))
break;
cp = &el->el_line.buffer[idx];
}
cp++;
if (el->el_flags & UNBUFFERED)
break;
if (cp[-1] == '\r' || cp[-1] == '\n')
break;
}
if (num == -1) {
if (errno == EINTR)
cp = el->el_line.buffer;
el->el_errno = errno;
}
goto noedit;
el->el_line.lastchar = el->el_line.buffer;
return noedit_wgets(el, nread);
}
#ifdef FIONREAD
if (el->el_tty.t_mode == EX_IO && ma->level < 0) {
long chrs = 0;
if (el->el_tty.t_mode == EX_IO && el->el_read->macros.level < 0) {
int chrs = 0;
(void) ioctl(el->el_infd, FIONREAD, (ioctl_t) & chrs);
(void) ioctl(el->el_infd, FIONREAD, &chrs);
if (chrs == 0) {
if (tty_rawmode(el) < 0) {
errno = 0;
*nread = 0;
return (NULL);
return NULL;
}
}
}
@@ -527,81 +515,19 @@ FUN(el,gets)(EditLine *el, int *nread)
read_prepare(el);
if (el->el_flags & EDIT_DISABLED) {
size_t idx;
if ((el->el_flags & UNBUFFERED) == 0)
cp = el->el_line.buffer;
else
cp = el->el_line.lastchar;
term__flush(el);
while ((num = (*el->el_read.read_char)(el, cp)) == 1) {
/* make sure there is space next character */
if (cp + 1 >= el->el_line.limit) {
idx = (cp - el->el_line.buffer);
if (!ch_enlargebufs(el, 2))
break;
cp = &el->el_line.buffer[idx];
}
cp++;
crlf = cp[-1] == '\r' || cp[-1] == '\n';
if (el->el_flags & UNBUFFERED)
break;
if (crlf)
break;
}
if (num == -1) {
if (errno == EINTR)
cp = el->el_line.buffer;
el->el_errno = errno;
}
goto noedit;
el->el_line.lastchar = el->el_line.buffer;
terminal__flush(el);
return noedit_wgets(el, nread);
}
for (num = OKCMD; num == OKCMD;) { /* while still editing this
* line */
#ifdef DEBUG_EDIT
read_debug(el);
#endif /* DEBUG_EDIT */
for (num = -1; num == -1;) { /* while still editing this line */
/* if EOF or error */
if ((num = read_getcmd(el, &cmdnum, &ch)) != OKCMD) {
#ifdef DEBUG_READ
(void) fprintf(el->el_errfile,
"Returning from el_gets %d\n", num);
#endif /* DEBUG_READ */
if (read_getcmd(el, &cmdnum, &ch) == -1)
break;
}
if (el->el_errno == EINTR) {
el->el_line.buffer[0] = '\0';
el->el_line.lastchar =
el->el_line.cursor = el->el_line.buffer;
break;
}
if ((unsigned int)cmdnum >= (unsigned int)el->el_map.nfunc) { /* BUG CHECK command */
#ifdef DEBUG_EDIT
(void) fprintf(el->el_errfile,
"ERROR: illegal command from key 0%o\r\n", ch);
#endif /* DEBUG_EDIT */
if ((size_t)cmdnum >= el->el_map.nfunc) /* BUG CHECK command */
continue; /* try again */
}
/* now do the real command */
#ifdef DEBUG_READ
{
el_bindings_t *b;
for (b = el->el_map.help; b->name; b++)
if (b->func == cmdnum)
break;
if (b->name)
(void) fprintf(el->el_errfile,
"Executing %s\n", b->name);
else
(void) fprintf(el->el_errfile,
"Error command = %d\n", cmdnum);
}
#endif /* DEBUG_READ */
/* vi redo needs these way down the levels... */
el->el_state.thiscmd = cmdnum;
el->el_state.thisch = ch;
@@ -610,16 +536,12 @@ FUN(el,gets)(EditLine *el, int *nread)
el->el_chared.c_redo.pos < el->el_chared.c_redo.lim) {
if (cmdnum == VI_DELETE_PREV_CHAR &&
el->el_chared.c_redo.pos != el->el_chared.c_redo.buf
&& Isprint(el->el_chared.c_redo.pos[-1]))
&& iswprint(el->el_chared.c_redo.pos[-1]))
el->el_chared.c_redo.pos--;
else
*el->el_chared.c_redo.pos++ = ch;
}
retval = (*el->el_map.func[cmdnum]) (el, ch);
#ifdef DEBUG_READ
(void) fprintf(el->el_errfile,
"Returned state %d\n", retval );
#endif /* DEBUG_READ */
/* save the last command here */
el->el_state.lastcmd = cmdnum;
@@ -641,7 +563,7 @@ FUN(el,gets)(EditLine *el, int *nread)
case CC_REFRESH_BEEP:
re_refresh(el);
term_beep(el);
terminal_beep(el);
break;
case CC_NORM: /* normal char */
@@ -666,24 +588,17 @@ FUN(el,gets)(EditLine *el, int *nread)
break;
case CC_FATAL: /* fatal error, reset to known state */
#ifdef DEBUG_READ
(void) fprintf(el->el_errfile,
"*** editor fatal ERROR ***\r\n\n");
#endif /* DEBUG_READ */
/* put (real) cursor in a known place */
re_clear_display(el); /* reset the display stuff */
ch_reset(el, 1); /* reset the input pointers */
re_refresh(el); /* print the prompt again */
ch_reset(el); /* reset the input pointers */
read_clearmacros(&el->el_read->macros);
re_refresh(el); /* print the prompt again */
break;
case CC_ERROR:
default: /* functions we don't know about */
#ifdef DEBUG_READ
(void) fprintf(el->el_errfile,
"*** editor ERROR ***\r\n\n");
#endif /* DEBUG_READ */
term_beep(el);
term__flush(el);
terminal_beep(el);
terminal__flush(el);
break;
}
el->el_state.argument = 1;
@@ -693,24 +608,19 @@ FUN(el,gets)(EditLine *el, int *nread)
break;
}
term__flush(el); /* flush any buffered output */
terminal__flush(el); /* flush any buffered output */
/* make sure the tty is set up correctly */
if ((el->el_flags & UNBUFFERED) == 0) {
read_finish(el);
*nread = num != -1 ? num : 0;
} else {
} else
*nread = (int)(el->el_line.lastchar - el->el_line.buffer);
}
goto done;
noedit:
el->el_line.cursor = el->el_line.lastchar = cp;
*cp = '\0';
*nread = (int)(el->el_line.cursor - el->el_line.buffer);
done:
if (*nread == 0) {
if (num == -1) {
*nread = -1;
errno = el->el_errno;
if (el->el_read->read_errno)
errno = el->el_read->read_errno;
}
return NULL;
} else