Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members

BufStream.C

Go to the documentation of this file.
00001 // Copyright (C) 2004, Kenneth C. Schalk
00002 
00003 // This file is part of Vesta.
00004 
00005 // Vesta is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU Lesser General Public
00007 // License as published by the Free Software Foundation; either
00008 // version 2.1 of the License, or (at your option) any later version.
00009 
00010 // Vesta is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013 // Lesser General Public License for more details.
00014 
00015 // You should have received a copy of the GNU Lesser General Public
00016 // License along with Vesta; if not, write to the Free Software
00017 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018 
00019 // Last modified on Sun Apr 17 22:45:24 EDT 2005 by ken@xorian.net        
00020 
00021 #include <assert.h>
00022 #include <string.h>
00023 
00024 #include "BufStream.H"
00025 #include "Basics.H"
00026 
00027 Basics::BufStreambuf::BufStreambuf(unsigned int initial_buf_len)
00028   : buf(NEW_PTRFREE_ARRAY(char, initial_buf_len)),
00029     buf_len(initial_buf_len), delete_buf(true), allocate_new_buf(true),
00030     get_pos(0), put_pos(0), valid_limit(0)
00031 {
00032   setp(buf, buf+(buf_len-1));
00033 }
00034 
00035 void Basics::BufStreambuf::update_get_pos()
00036 {
00037   if(gptr() != 0)
00038     get_pos = gptr() - buf;
00039 }
00040 
00041 void Basics::BufStreambuf::update_put_pos()
00042 {
00043   if(pptr() != 0)
00044     put_pos = pptr() - buf;
00045   if(put_pos > valid_limit)
00046     valid_limit = put_pos;
00047 }
00048 
00049 bool Basics::BufStreambuf::alloc_if_needed(unsigned int new_byte_count)
00050 {
00051   // Figure out how many characters have been written already
00052   update_put_pos();
00053 
00054   // Do we need to more space to fit this byte into the buffer
00055   // (leaving room for a terminating null byte)?
00056   if(((unsigned int) valid_limit + new_byte_count + 1) > buf_len)
00057     {
00058       // If we're not supposed to allocate a new buffer, we can't
00059       // write this byte.
00060       if(!allocate_new_buf)
00061         {
00062           return false;
00063         }
00064 
00065       // Figure out where in the buffer the get pointer is.
00066       update_get_pos();
00067 
00068       // Determine the size of the new buffer we'll allocate.  Don't
00069       // allocate more than BUFSIZ extra bytes beyond what we need for
00070       // the current write.
00071       unsigned int new_buf_len;
00072       if((buf_len + new_byte_count) < BUFSIZ)
00073         new_buf_len = (buf_len + new_byte_count) * 2;
00074       else
00075         new_buf_len = buf_len + new_byte_count + BUFSIZ;
00076 
00077       // Allocate the new buffer.
00078       char *new_buf = NEW_PTRFREE_ARRAY(char, new_buf_len);
00079 
00080       // Copy the existing bytes.
00081       memcpy(new_buf, buf, valid_limit);
00082 
00083       // Delete the old buffer if we need to.
00084       if(delete_buf)
00085         delete [] buf;
00086 
00087       // This is our buffer now.
00088       buf = new_buf;
00089       buf_len = new_buf_len;
00090 
00091       // The put area is the new buffer.  Make sure to mark the
00092       // already written portion as used.
00093       setp(buf, buf+(buf_len-1));
00094       pbump(put_pos);
00095 
00096       // Update the get area for the new buffer as well.
00097       setg(buf, buf+get_pos, buf+valid_limit);
00098 
00099       // We're responsible for deleting this new buffer.
00100       delete_buf = true;
00101 
00102       // It better be big enough.
00103       assert(((unsigned int) valid_limit  + new_byte_count + 1) < buf_len);
00104     }
00105 
00106   return true;
00107 }
00108 
00109 Basics::BufStreambuf::pos_type
00110 Basics::BufStreambuf::seekoff(off_type offset,
00111                               seekdir way,
00112                               openmode mode)
00113 {
00114   pos_type result = 0;
00115 
00116   if(mode & std::ios::out)
00117     {
00118       update_put_pos();
00119 
00120       if(way == std::ios::beg)
00121         put_pos = offset;
00122       else if(way == std::ios::cur)
00123         put_pos += offset;
00124       else
00125         put_pos = valid_limit + offset;
00126 
00127       if(put_pos < 0)
00128         put_pos = 0;
00129       if(put_pos > valid_limit)
00130         put_pos = valid_limit;
00131 
00132       if((buf != 0) && (buf_len > 0) && (put_pos < (pos_type) (buf_len-1)))
00133         setp(buf+put_pos, buf+(buf_len-1));
00134       else
00135         setp(0,0);
00136 
00137       result = put_pos;
00138     }
00139 
00140   if(mode & std::ios::in)
00141     {
00142       update_get_pos();
00143 
00144       if(way == std::ios::beg)
00145         get_pos = offset;
00146       else if(way == std::ios::cur)
00147         get_pos += offset;
00148       else
00149         get_pos = valid_limit + offset;
00150 
00151       if(get_pos < 0)
00152         get_pos = 0;
00153       if(get_pos > valid_limit)
00154         get_pos = valid_limit;
00155 
00156       // If we have data and the get position is within the valid
00157       // portion...
00158       if((buf != 0) && (valid_limit > 0) && (get_pos < valid_limit))
00159         // Set the get area
00160         setg(buf, buf+get_pos, buf+valid_limit);
00161       else
00162         setg(0,0,0);
00163 
00164       result = get_pos;
00165     }
00166 
00167   return result;
00168 }
00169 
00170 Basics::BufStreambuf::pos_type
00171 Basics::BufStreambuf::seekpos(pos_type pos, 
00172                               openmode mode)
00173 {
00174   // Check to see how much has been written up to now, as that affects
00175   // where we can seek to.
00176   update_put_pos();
00177 
00178   if(pos < 0)
00179     pos = 0;
00180   if(pos > valid_limit)
00181     pos = valid_limit;
00182 
00183   if(mode & std::ios::in)
00184     {
00185       get_pos = pos;
00186 
00187       // If we have data and the get position is within the valid
00188       // portion...
00189       if((buf != 0) && (valid_limit > 0) && (get_pos < valid_limit))
00190         // Set the get area
00191         setg(buf, buf+get_pos, buf+valid_limit);
00192       else
00193         setg(0,0,0);
00194     }
00195 
00196   if(mode & std::ios::out)
00197     {
00198       put_pos = pos;
00199 
00200       assert(buf != 0);
00201       assert(put_pos <= (pos_type) (buf_len-1));
00202       setp(buf+put_pos, buf+(buf_len-1));
00203     }
00204 
00205   return pos;
00206 }
00207 
00208 int Basics::BufStreambuf::underflow()
00209 {
00210   // Check to see how much has been written (as that can affect how
00211   // much can be read).
00212   update_put_pos();
00213 
00214   update_get_pos();
00215 
00216   // If we have data and the get position is within the valid
00217   // portion...
00218   if((buf != 0) && (valid_limit > 0) && (get_pos < valid_limit))
00219     {
00220       // Set the get area
00221       setg(buf, buf+get_pos, buf+valid_limit);
00222 
00223       // Return the first character of the get area.
00224       return ((*gptr())&0x00ff);
00225     }
00226 
00227   // If we make it here, we have no data to use.
00228   return EOF;
00229 }
00230 
00231 std::streamsize Basics::BufStreambuf::xsgetn(char* s, std::streamsize n)
00232 {
00233   std::streamsize result = 0;
00234 
00235   // Check to see how much has been written (as that can affect how
00236   // much can be read).
00237   update_put_pos();
00238 
00239   update_get_pos();
00240 
00241   if(buf != 0)
00242     {
00243       if(get_pos < valid_limit)
00244         {
00245           unsigned int unread_count = valid_limit - get_pos;
00246 
00247           unsigned int use_count = (unread_count < n) ? unread_count : n;
00248 
00249           memcpy(s, buf + get_pos, use_count);
00250         
00251           result += use_count;
00252           get_pos += (pos_type) use_count;
00253         }
00254 
00255       // Set the get area
00256       setg(buf, buf+get_pos, buf+valid_limit);
00257     }
00258 
00259   return result;
00260 }
00261 
00262 int Basics::BufStreambuf::overflow(int c)
00263 {
00264   // Append the byte to be written.
00265   if(c != EOF)
00266     {
00267       // If we don't have enough space and can't allocate more, we
00268       // can't write this byte.
00269       if(!alloc_if_needed(1))
00270         return EOF;
00271 
00272       assert(pptr() != 0);
00273 
00274       *(pptr()) = (char) c;
00275       pbump(1);
00276     }
00277 
00278   // Indicate that everything is fine by returning the character
00279   // passed (converting an EOF into a non-EOF).
00280   return (c & 0x00ff);
00281 }
00282 
00283 std::streamsize Basics::BufStreambuf::xsputn(const char* s, std::streamsize n)
00284 {
00285   // If we don't have enough space and can't allocate more, we can't
00286   // write these bytes.
00287   if(!alloc_if_needed(n))
00288     return -1;
00289 
00290   assert(pptr() != 0);
00291 
00292   // Copy these
00293   memcpy(pptr(), s, n);
00294   pbump(n);
00295   return n;
00296 }

Generated on Mon May 8 00:48:28 2006 for Vesta by  doxygen 1.4.2