#include "sfhdr.h"
#if !_PACKAGE_ast
#ifndef FIONREAD
#if _sys_ioctl
#include <sys/ioctl.h>
#endif
#endif
#endif
#define STREAM_PEEK 001
#define SOCKET_PEEK 002
#if __STD_C
ssize_t sfpkrd(int fd, Void_t* argbuf, size_t n, int rc, long tm, int action)
#else
ssize_t sfpkrd(fd, argbuf, n, rc, tm, action)
int fd;
Void_t* argbuf;
size_t n;
int rc;
long tm;
int action;
#endif
{
reg ssize_t r;
reg int ntry, t;
reg char *buf = (char*)argbuf, *endbuf;
if(rc < 0 && tm < 0 && action <= 0)
return read(fd,buf,n);
t = (action > 0 || rc >= 0) ? (STREAM_PEEK|SOCKET_PEEK) : 0;
#if !_stream_peek
t &= ~STREAM_PEEK;
#endif
#if !_socket_peek
t &= ~SOCKET_PEEK;
#endif
for(ntry = 0; ntry < 2; ++ntry)
{
r = -1;
#if _stream_peek
if((t&STREAM_PEEK) && (ntry == 1 || tm < 0) )
{
struct strpeek pbuf;
pbuf.flags = 0;
pbuf.ctlbuf.maxlen = -1;
pbuf.ctlbuf.len = 0;
pbuf.ctlbuf.buf = NIL(char*);
pbuf.databuf.maxlen = n;
pbuf.databuf.buf = buf;
pbuf.databuf.len = 0;
if((r = ioctl(fd,I_PEEK,&pbuf)) < 0)
{ if(errno == EINTR)
return -1;
t &= ~STREAM_PEEK;
}
else
{ t &= ~SOCKET_PEEK;
if(r > 0 && (r = pbuf.databuf.len) <= 0)
{ if(action <= 0)
r = read(fd,buf,1);
return r;
}
if(r == 0)
r = -1;
else if(r > 0)
break;
}
}
#endif
if(ntry == 1)
break;
while(tm >= 0 || action > 0 ||
((t&STREAM_PEEK) && rc >= 0) ||
(t&SOCKET_PEEK) )
{ r = -2;
#if _lib_poll
if(r == -2)
{
struct pollfd po;
po.fd = fd;
po.events = POLLIN;
po.revents = 0;
if((r = SFPOLL(&po,1,tm)) < 0)
{ if(errno == EINTR)
return -1;
else if(errno == EAGAIN)
{ errno = 0;
continue;
}
else r = -2;
}
else r = (po.revents&POLLIN) ? 1 : -1;
}
#endif
#if _lib_select
if(r == -2)
{
#if _hpux_threads && vt_threaded
#define fd_set int
#endif
fd_set rd;
struct timeval tmb, *tmp;
FD_ZERO(&rd);
FD_SET(fd,&rd);
if(tm < 0)
tmp = NIL(struct timeval*);
else
{ tmp = &tmb;
tmb.tv_sec = tm/SECOND;
tmb.tv_usec = (tm%SECOND)*SECOND;
}
r = select(fd+1,&rd,NIL(fd_set*),NIL(fd_set*),tmp);
if(r < 0)
{ if(errno == EINTR)
return -1;
else if(errno == EAGAIN)
{ errno = 0;
continue;
}
else r = -2;
}
else r = FD_ISSET(fd,&rd) ? 1 : -1;
}
#endif
if(r == -2)
{
#if !_lib_poll && !_lib_select
#ifdef FIONREAD
long nsec = tm < 0 ? 0 : (tm+999)/1000;
while(nsec > 0 && r < 0)
{ long avail = -1;
if((r = ioctl(fd,FIONREAD,&avail)) < 0)
{ if(errno == EINTR)
return -1;
else if(errno == EAGAIN)
{ errno = 0;
continue;
}
else
{ r = -2;
break;
}
}
else r = avail <= 0 ? -1 : (ssize_t)avail;
if(r < 0 && nsec-- > 0)
sleep(1);
}
#endif
#endif
}
if(r > 0)
{ if(action <= 0 && rc < 0)
return read(fd,buf,n);
else r = -1;
}
else if(tm >= 0)
return -1;
else r = -1;
break;
}
#if _socket_peek
if(t&SOCKET_PEEK)
{
while((r = recv(fd,(char*)buf,n,MSG_PEEK)) < 0)
{ if(errno == EINTR)
return -1;
else if(errno == EAGAIN)
{ errno = 0;
continue;
}
t &= ~SOCKET_PEEK;
break;
}
if(r >= 0)
{ t &= ~STREAM_PEEK;
if(r > 0)
break;
else
{ if(action <= 0)
r = read(fd,buf,1);
return r;
}
}
}
#endif
}
if(r < 0)
{ if(tm >= 0 || action > 0)
return -1;
else
{
if((action = action ? -action : 1) > (int)n)
action = n;
r = 0;
while((t = read(fd,buf,action)) > 0)
{ r += t;
for(endbuf = buf+t; buf < endbuf;)
if(*buf++ == rc)
action -= 1;
if(action == 0 || (int)(n-r) < action)
break;
}
return r == 0 ? t : r;
}
}
if(rc >= 0)
{ reg char* sp;
t = action == 0 ? 1 : action < 0 ? -action : action;
for(endbuf = (sp = buf)+r; sp < endbuf; )
if(*sp++ == rc)
if((t -= 1) == 0)
break;
r = sp - buf;
}
if(action <= 0)
r = read(fd,buf,r);
return r;
}