wvstreamclone.cc

00001 /*
00002  * Worldvisions Weaver Software:
00003  *   Copyright (C) 1997-2002 Net Integration Technologies, Inc.
00004  * 
00005  * WvStreamClone simply forwards all requests to the "cloned" stream.
00006  * 
00007  * NOTE: this file is a pain to maintain, because many of these functions
00008  * are almost (but not quite) exactly like the ones in WvStream.  If
00009  * WvStream changes, you need to change this too.
00010  * 
00011  * See wvstreamclone.h.
00012  */
00013 #include "wvstreamclone.h"
00014 #include "wvmoniker.h"
00015 
00016 #ifdef _MSC_VER
00017 #pragma warning(disable : 4073)
00018 #pragma init_seg(lib)
00019 #endif
00020 
00021 static IWvStream *creator(WvStringParm s)
00022 {
00023     return new WvStreamClone(wvcreate<IWvStream>(s));
00024 }
00025 
00026 static WvMoniker<IWvStream> reg("clone", creator);
00027 
00028 
00029 WvStreamClone::WvStreamClone(IWvStream *_cloned) 
00030     : cloned(0), 
00031       disassociate_on_close(false), 
00032       my_type("WvStreamClone:(none)")
00033 {
00034     setclone(_cloned);
00035     // the sub-stream will force its own values, if it really wants.
00036     force_select(false, false, false);
00037 }
00038 
00039 
00040 WvStreamClone::~WvStreamClone()
00041 {
00042     //fprintf(stderr, "%p destroying: clone is %p\n", this, cloned);
00043     close();
00044     WVRELEASE(cloned);
00045 }
00046 
00047 
00048 void WvStreamClone::noread()
00049 {
00050     // unlike nowrite(), it is safe to call cloned->noread() immediately.
00051     // That will pass the shutdown(SHUT_RD) on to the deepest stream right
00052     // away, but won't close anything until all the inbufs are empty.
00053     if (cloned)
00054         cloned->noread();
00055     WvStream::noread();
00056 }
00057 
00058 
00059 void WvStreamClone::nowrite()
00060 {
00061     // this sets stop_write.  We call cloned->nowrite() in flush_internal()
00062     // when our outbuf is flushed (because until then, we *do* want to be
00063     // able to write to the clone).
00064     if (cloned && !outbuf.used())
00065         cloned->nowrite();
00066     WvStream::nowrite();
00067 }
00068 
00069 
00070 void WvStreamClone::close()
00071 {
00072     // fprintf(stderr, "%p closing substream %p\n", this, cloned);
00073     if (cloned)
00074         cloned->setclosecallback(0); // prevent recursion!
00075     WvStream::close();
00076     if (disassociate_on_close)
00077         setclone(NULL);
00078     if (cloned)
00079         cloned->close();
00080 }
00081 
00082 
00083 bool WvStreamClone::flush_internal(time_t msec_timeout)
00084 {
00085     if (cloned)
00086     {
00087         if (stop_write && !outbuf.used())
00088             cloned->nowrite();
00089         return cloned->flush(msec_timeout);
00090     }
00091     else
00092         return true;
00093 }
00094 
00095 
00096 size_t WvStreamClone::uread(void *buf, size_t size)
00097 {
00098     // we use cloned->read() here, not uread(), since we want the _clone_
00099     // to own the input buffer, not the main stream.
00100     if (cloned)
00101     {
00102         size_t len = 0;
00103         if (cloned->isok())
00104             len = cloned->read(buf, size);
00105         if (len == 0 && !cloned->isok())
00106             close();
00107         return len;
00108     }
00109     else
00110         return 0;
00111 }
00112 
00113 
00114 size_t WvStreamClone::uwrite(const void *buf, size_t size)
00115 {
00116     // we use cloned->write() here, not uwrite(), since we want the _clone_
00117     // to own the output buffer, not the main stream.
00118     if (cloned)
00119         return cloned->write(buf, size);
00120     else
00121         return 0;
00122 }
00123 
00124 
00125 bool WvStreamClone::isok() const
00126 {
00127     if (geterr())
00128         return false;
00129     if (!cloned)
00130         return false;
00131     return WvStream::isok();
00132     
00133     // don't do this: cloned's closecallback will close us when needed.
00134     // return cloned->isok();
00135 }
00136 
00137 
00138 int WvStreamClone::geterr() const
00139 {
00140     if (WvStream::geterr())
00141         return WvStream::geterr();
00142     if (cloned)
00143         return cloned->geterr();
00144     return EIO;
00145 }
00146 
00147 
00148 WvString WvStreamClone::errstr() const
00149 {
00150     if (WvStream::geterr())
00151         return WvStream::errstr();
00152     if (cloned)
00153         return cloned->errstr();
00154     return "No child stream!";
00155 }
00156 
00157 
00158 void WvStreamClone::close_callback(WvStream &s)
00159 {
00160     if (cloned == &s)
00161     {
00162         //fprintf(stderr, "streamclone-closecb: %d/%d/%d/%d/%d\n",
00163         //      stop_read, stop_write, outbuf.used(), inbuf.used(), closed);
00164         nowrite();
00165         noread();
00166         // close();
00167         //fprintf(stderr, "streamclone-closecb2: %d/%d/%d/%d/%d\n",
00168         //      stop_read, stop_write, outbuf.used(), inbuf.used(), closed);
00169     }
00170 }
00171 
00172 
00173 void WvStreamClone::setclone(IWvStream *newclone)
00174 {
00175     if (cloned)
00176         cloned->setclosecallback(0);
00177     cloned = newclone;
00178     closed = stop_read = stop_write = false;
00179     if (cloned)
00180         cloned->setclosecallback(IWvStreamCallback(this, &WvStreamClone::close_callback));
00181     
00182     if (newclone != NULL)
00183         my_type = WvString("WvStreamClone:%s", newclone->wstype());
00184     else
00185         my_type = "WvStreamClone:(none)";
00186 }
00187 
00188 
00189 void WvStreamClone::pre_select(SelectInfo &si)
00190 {
00191     SelectRequest oldwant = si.wants;
00192     WvStream::pre_select(si);
00193 
00194     if (cloned && cloned->isok())
00195     {
00196         if (!si.inherit_request)
00197         {
00198             si.wants.readable |= readcb;
00199             si.wants.writable |= writecb;
00200             si.wants.isexception |= exceptcb;
00201         }
00202         
00203         if (outbuf.used() || autoclose_time)
00204             si.wants.writable = true;
00205 
00206         cloned->pre_select(si);
00207         si.wants = oldwant;
00208     }
00209 }
00210 
00211 
00212 bool WvStreamClone::post_select(SelectInfo &si)
00213 {
00214     SelectRequest oldwant = si.wants;
00215     // This currently always returns false, but we prolly should
00216     // still have it here in case it ever becomes useful
00217     bool result = WvStream::post_select(si);
00218     bool val, want_write;
00219     
00220     if (cloned && cloned->should_flush())
00221         flush(0);
00222 
00223     if (cloned && cloned->isok())
00224     {
00225         if (!si.inherit_request)
00226         {
00227             si.wants.readable |= readcb;
00228             si.wants.writable |= writecb;
00229             si.wants.isexception |= exceptcb;
00230         }
00231 
00232         val = cloned->post_select(si);
00233         want_write = si.wants.writable;
00234         si.wants = oldwant;
00235         
00236         // return result if they're looking for writable and we still
00237         // have data in outbuf - the writable is for flushing, not for you!
00238         if (want_write && outbuf.used())
00239             return result;
00240         else if (val && si.wants.readable && read_requires_writable
00241                  && !read_requires_writable->select(0, false, true))
00242             return result;
00243         else if (val && si.wants.writable && write_requires_readable
00244                  && !write_requires_readable->select(0, true, false))
00245             return result;
00246         else
00247             return val || result;
00248     }
00249     
00250     return result;
00251 }
00252 
00253 
00254 const WvAddr *WvStreamClone::src() const
00255 {
00256     if (cloned)
00257         return cloned->src();
00258     return NULL;
00259 }
00260 
00261 
00262 void WvStreamClone::execute()
00263 {
00264     WvStream::execute();
00265     if (cloned) cloned->callback();
00266 }

Generated on Thu Jan 24 16:50:57 2008 for WvStreams by  doxygen 1.5.4