lib/fdbuf/fdibuf.cc
changeset 0 6f7a81934006
equal deleted inserted replaced
-1:000000000000 0:6f7a81934006
       
     1 // Copyright (C) 1999,2000 Bruce Guenter <bruceg@em.ca>
       
     2 //
       
     3 // This program is free software; you can redistribute it and/or modify
       
     4 // it under the terms of the GNU General Public License as published by
       
     5 // the Free Software Foundation; either version 2 of the License, or
       
     6 // (at your option) any later version.
       
     7 //
       
     8 // This program is distributed in the hope that it will be useful,
       
     9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       
    11 // GNU General Public License for more details.
       
    12 //
       
    13 // You should have received a copy of the GNU General Public License
       
    14 // along with this program; if not, write to the Free Software
       
    15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
       
    16 
       
    17 #include "fdbuf.h"
       
    18 #include <errno.h>
       
    19 #include <fcntl.h>
       
    20 #include <string.h>
       
    21 #include <unistd.h>
       
    22 
       
    23 ///////////////////////////////////////////////////////////////////////////////
       
    24 // Class fdibuf
       
    25 ///////////////////////////////////////////////////////////////////////////////
       
    26 fdibuf::fdibuf(int fdesc, bool dc, unsigned bufsz)
       
    27   : fdbuf(fdesc, dc, bufsz)
       
    28 {
       
    29 }
       
    30 
       
    31 fdibuf::fdibuf(const char* filename, unsigned bufsz)
       
    32   : fdbuf(open(filename, O_RDONLY), true, bufsz)
       
    33 {
       
    34   if(fd == -1) {
       
    35     flags = flag_error;
       
    36     errnum = errno;
       
    37   }
       
    38 }
       
    39 
       
    40 fdibuf::~fdibuf()
       
    41 {
       
    42 }
       
    43 
       
    44 bool fdibuf::eof() const
       
    45 {
       
    46   return (flags & flag_eof) && (bufstart >= buflength);
       
    47 }
       
    48 
       
    49 bool fdibuf::operator!() const
       
    50 {
       
    51   return eof() || error() || closed();
       
    52 }
       
    53 
       
    54 // refill is protected -- no locking
       
    55 bool fdibuf::refill()
       
    56 {
       
    57   if(flags)
       
    58     return false;
       
    59   if(bufstart != 0) {
       
    60     if(bufstart < buflength) {
       
    61       buflength -= bufstart;
       
    62       memcpy(buf, buf+bufstart, buflength);
       
    63     } else
       
    64       buflength = 0;
       
    65     bufstart = 0;
       
    66   }
       
    67   unsigned oldbuflength = buflength;
       
    68   if(buflength < bufsize) {
       
    69     ssize_t red = ::read(fd, buf+buflength, bufsize-buflength);
       
    70     if(red == -1) {
       
    71       errnum = errno;
       
    72       flags |= flag_error;
       
    73     }
       
    74     else if(red == 0)
       
    75       flags |= flag_eof;
       
    76     else {
       
    77       buflength += red;
       
    78       offset += red;
       
    79     }
       
    80   }
       
    81   return buflength > oldbuflength;
       
    82 }
       
    83 
       
    84 bool fdibuf::get(char& ch)
       
    85 {
       
    86   lock();
       
    87   count = 0;
       
    88   if(bufstart >= buflength)
       
    89     refill();
       
    90   bool r = true;
       
    91   if(eof() || error())
       
    92     r = false;
       
    93   else {
       
    94     ch = buf[bufstart++];
       
    95     count = 1;
       
    96   }
       
    97   unlock();
       
    98   return r;
       
    99 }
       
   100 
       
   101 bool fdibuf::read_large(char* data, unsigned datalen)
       
   102 {
       
   103   lock();
       
   104   count = 0;
       
   105 
       
   106   // If there's any content in the buffer, memcpy it out first.
       
   107   unsigned len = buflength - bufstart;
       
   108   if(len > datalen)
       
   109     len = datalen;
       
   110   memcpy(data, buf+bufstart, len);
       
   111   data += len;
       
   112   datalen -= len;
       
   113   bufstart += len;
       
   114   count += len;
       
   115 
       
   116   // After the buffer is empty and there's still data to read,
       
   117   // read it straight from the fd instead of copying it through the buffer.
       
   118   while(datalen > 0) {
       
   119     ssize_t red = ::read(fd, data, datalen);
       
   120     if(red == -1) {
       
   121       errnum = errno;
       
   122       flags |= flag_error;
       
   123       break;
       
   124     }
       
   125     else if(red == 0) {
       
   126       flags |= flag_eof;
       
   127       break;
       
   128     }
       
   129     data += red;
       
   130     datalen -= red;
       
   131     offset += red;
       
   132     count += red;
       
   133   }
       
   134   unlock();
       
   135   return datalen == 0;
       
   136 }
       
   137 
       
   138 bool fdibuf::read(char* data, unsigned datalen)
       
   139 {
       
   140   if(datalen >= bufsize)
       
   141     return read_large(data, datalen);
       
   142   lock();
       
   143   count = 0;
       
   144   char* ptr = data;
       
   145   while(datalen && !eof()) {
       
   146     if(bufstart >= buflength)
       
   147       refill();
       
   148     unsigned len = buflength-bufstart;
       
   149     if(len > datalen)
       
   150       len = datalen;
       
   151     memcpy(ptr, buf+bufstart, len);
       
   152     bufstart += len;
       
   153     datalen -= len;
       
   154     ptr += len;
       
   155     count += len;
       
   156   }
       
   157   unlock();
       
   158   return !datalen;
       
   159 }
       
   160 
       
   161 bool fdibuf::seek(unsigned o)
       
   162 {
       
   163   lock();
       
   164   unsigned buf_start = offset - buflength;
       
   165   if(o >= buf_start && o < offset) {
       
   166     bufstart = o - buf_start;
       
   167   }
       
   168   else {
       
   169     if(lseek(fd, o, SEEK_SET) != (off_t)o) {
       
   170       errnum = errno;
       
   171       flags |= flag_error;
       
   172       unlock();
       
   173       return false;
       
   174     }
       
   175     offset = o;
       
   176     buflength = bufstart = 0;
       
   177   }
       
   178   count = 0;
       
   179   flags &= ~flag_eof;
       
   180   unlock();
       
   181   return true;
       
   182 }
       
   183 
       
   184 bool fdibuf::seekfwd(unsigned o)
       
   185 {
       
   186   return seek(tell() + o);
       
   187 }
       
   188 
       
   189 ///////////////////////////////////////////////////////////////////////////////
       
   190 // Globals
       
   191 ///////////////////////////////////////////////////////////////////////////////
       
   192 fdibuf fin(0);