Logo Search packages:      
Sourcecode: ksh version File versions  Download package

sfpkrd.c

/***********************************************************************
*                                                                      *
*               This software is part of the ast package               *
*          Copyright (c) 1985-2010 AT&T Intellectual Property          *
*                      and is licensed under the                       *
*                  Common Public License, Version 1.0                  *
*                    by AT&T Intellectual Property                     *
*                                                                      *
*                A copy of the License is available at                 *
*            http://www.opensource.org/licenses/cpl1.0.txt             *
*         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
*                                                                      *
*              Information and Software Systems Research               *
*                            AT&T Research                             *
*                           Florham Park NJ                            *
*                                                                      *
*                 Glenn Fowler <gsf@research.att.com>                  *
*                  David Korn <dgk@research.att.com>                   *
*                   Phong Vo <kpv@research.att.com>                    *
*                                                                      *
***********************************************************************/
#include    "sfhdr.h"
#if !_PACKAGE_ast
#ifndef FIONREAD
#if _sys_ioctl
#include    <sys/ioctl.h>
#endif
#endif
#endif

/*    Read/Peek a record from an unseekable device
**
**    Written by Kiem-Phong Vo.
*/

#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;   /* file descriptor */
Void_t*     argbuf;     /* buffer to read data */
size_t      n;    /* buffer size */
int   rc;   /* record character */
long  tm;   /* time-out */
int   action;     /* >0: peeking, if rc>=0, get action records,
               <0: no peeking, if rc>=0, get -action records,
               =0: no peeking, if rc>=0, must get a single record
            */
#endif
{
      reg ssize_t r;
      reg int           ntry, t;
      reg char    *buf = (char*)argbuf, *endbuf;

      if(rc < 0 && tm < 0 && action <= 0)
            return sysreadf(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)   /* read past eof */
                                    r = sysreadf(fd,buf,1);
                              return r;
                        }
                        if(r == 0)
                              r = -1;
                        else if(r > 0)
                              break;
                  }
            }
#endif /* stream_peek */

            if(ntry == 1)
                  break;

            /* poll or select to see if data is present.  */
            while(tm >= 0 || action > 0 ||
                  /* block until there is data before peeking again */
                  ((t&STREAM_PEEK) && rc >= 0) ||
                  /* let select be interrupted instead of recv which autoresumes */
                  (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 /*_lib_poll*/
#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 /*_lib_select*/
                  if(r == -2)
                  {
#if !_lib_poll && !_lib_select      /* both poll and select can't be used */
#ifdef FIONREAD               /* quick and dirty check for availability */
                        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  /* ioctl failed completely */
                                    {     r = -2;
                                          break;
                                    }
                              }
                              else  r = avail <= 0 ? -1 : (ssize_t)avail;

                              if(r < 0 && nsec-- > 0)
                                    sleep(1);
                        }
#endif
#endif
                  }

                  if(r > 0)         /* there is data now */
                  {     if(action <= 0 && rc < 0)
                              return sysreadf(fd,buf,n);
                        else  r = -1;
                  }
                  else if(tm >= 0)  /* timeout exceeded */
                        return -1;
                  else  r = -1;
                  break;
            }

#if _socket_peek
            if(t&SOCKET_PEEK)
            {
#if __MACH__ && __APPLE__
                  /*
                   * work around macos 10.4 recv(MSG_PEEK) bug that consumes pipe() data
                   */

                  struct stat st;
                  static int  recv_peek_ok;
                  if (!recv_peek_ok)
                  {
                        int   fds[2];
                        char  tst[2];
                        tst[0] = 'a';
                        tst[1] = 'z';
                        recv_peek_ok = (!pipe(fds) && write(fds[1], tst, 2) && recv(fds[0], tst, 1, MSG_PEEK) == 1 && tst[0] == 'a' && recv(fds[0], tst, 1, MSG_PEEK) == 1 && tst[0] == 'a') ? 1 : -1;
                        close(fds[0]);
                        close(fds[1]);
                  }
                  if (recv_peek_ok < 0 && !fstat(fd, &st) && !S_ISSOCK(st.st_mode))
                  {
                        r = -1;
                        t &= ~SOCKET_PEEK;
                  }
                  else
#endif
                  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  /* read past eof */
                        {     if(action <= 0)
                                    r = sysreadf(fd,buf,1);
                              return r;
                        }
                  }
            }
#endif
      }

      if(r < 0)
      {     if(tm >= 0 || action > 0)
                  return -1;
            else /* get here means: tm < 0 && action <= 0 && rc >= 0 */
            {     /* number of records read at a time */
                  if((action = action ? -action : 1) > (int)n)
                        action = n;
                  r = 0;
                  while((t = sysreadf(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;
            }
      }

      /* successful peek, find the record end */
      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;
      }

      /* advance */
      if(action <= 0)
            r = sysreadf(fd,buf,r);

      return r;
}

Generated by  Doxygen 1.6.0   Back to index