home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-387-Vol-3of3.iso / c / cuj9301.zip / 1101046A < prev    next >
Text File  |  1992-11-09  |  16KB  |  580 lines

  1. #if !defined TSTREAM_H
  2. #define TSTREAM_H
  3.  
  4. #include <iostream.h>    // for base class definitions
  5.  
  6. // class tbuf<>.  Derived publicly from streambuf to 
  7. // allow class ios which contains pointer to streambuf
  8. // access to virtual functions.  tbuf<> implements 
  9. // basic buffering, reading, writing and seeking on
  10. // a stream.  It also provides open, close, attach, 
  11. // and utility functions.
  12. template <class T>
  13. class tbuf : public streambuf {
  14. public:
  15. // openProtection provides a default parameter to the 
  16. // open functions to specify what protection a file 
  17. // will be created with.  You can ignore this if it is
  18. // not necessary
  19. static const int openProtect;
  20. // tbufSize specifies the default buffer size.  It is 
  21. // set to 516 bytes.  
  22. static const int tbufSize;
  23. // Default contructor.  Make a buffer without a 
  24. // stream attached.  mode has a dual meaning, if it 
  25. // is zero it means that any operation is allowable, 
  26. // and the stream should not be deleted when closing.  
  27.     tbuf()
  28.         : stream(0), mode(0), opened(0)
  29.     {
  30.         makbuf();
  31.     }
  32. // create buffer and attach to t.  t is assumed to be
  33. // already opened in read/write mode.  t will not be
  34. // deleted or closed when closing this buffer
  35.     tbuf(T &t)    
  36.         : stream(&t), mode(0), opened(1)
  37.     {
  38.         makbuf();
  39.     }
  40. // create buffer from parameters, and attach to t.
  41.     tbuf(T &t, char* b, int l)    
  42.         : stream(&t), mode(0), opened(1)
  43.     {
  44.         setbuf(b, l);
  45.     }
  46. // destroy buffer.  If mode is not zero, t will be 
  47. // closed and deleted.  Otherwise just flush the 
  48. // output buffer.
  49.     ~tbuf()
  50.     {                
  51.         if(mode)
  52.             close();
  53.         else
  54.             overflow(EOF);
  55.     }
  56. // return open status
  57.     int is_open() const 
  58.     { 
  59.         return opened; 
  60.     }
  61. // return reference to stream
  62.     T &fd() const 
  63.     { 
  64.         return *stream; 
  65.     }
  66. // open stream.  mode must not be zero.  stream will 
  67. // be closed and deleted when closing buffer.
  68.     tbuf *open(const char *name, int mode, 
  69.                        int prot = tbuf::openProtect);
  70. // close buffer and optionally delete stream.
  71.     tbuf *close();              
  72. // attach stream to buffer.  Stream is assumed to
  73. // be opened in read/write mode.
  74.     tbuf *attach(T &);  
  75. // write buffer to stream and reset pointers.
  76.     virtual int overflow(int = EOF);
  77. // read data into buffer and reset pointers.
  78.     virtual int underflow();
  79. // sync input and output.
  80.     virtual int sync();    
  81. // seek to offset and flush output buffers.
  82.     virtual long seekoff(long, ios::seek_dir, int);
  83. // set buffer.  For unbuffered i/o set char * to 0.
  84.     virtual streambuf *setbuf(char  *, int);
  85. protected:
  86.     int putBackSize() 
  87.     { 
  88.         return (blen() > 8) ? 4 : 1; 
  89.     }    
  90.     void resetpg(int end = 0);
  91.     void makbuf() 
  92.     { 
  93.         setbuf(new char[tbufSize], tbufSize); 
  94.     }
  95.     int unbuffered() 
  96.     { 
  97.         return streambuf::unbuffered() | !base(); 
  98.     }
  99.     T     *stream;        
  100.     int   mode;       
  101.     short opened; 
  102.     char  lookAhead[2];      
  103. };
  104.  
  105. template <class T> 
  106. const int tbuf<T>::tbufSize = 516;
  107. template <class T> 
  108. const int tbuf<T>::openProtect = 0;
  109.  
  110. // Attach an open stream to this buffer.  When this 
  111. // buffer is closed don't try to close stream.  If 
  112. // not yet buffered, try to create a buffer.  Reset 
  113. // the put and get pointers.  Return 0 on error, or 
  114. // this if OK.
  115. template <class T>
  116. tbuf<T>* tbuf<T>::attach(T &t)
  117. {
  118.     if(opened)        // if already opened, return 0
  119.         return 0;
  120.     stream = &t;    // attach stream.
  121.     opened = 1;     // set to opened.
  122.     mode = 0;       // buffer doesn't own stream.
  123.     if(!base())        // if no buffer yet...
  124.         makbuf();    // try to make one.
  125.     else
  126.         resetpg();    // reset put and get pointers.
  127.     return this;
  128. }
  129.  
  130. // Close buffer, and optionally stream attached to it.
  131. // Flush buffer if data inside.  Return 0 on error or
  132. // this if OK.
  133. template <class T>
  134. tbuf<T>* tbuf<T>::close()
  135. {
  136.     if(!*stream)    // if stream closed, 
  137.         opened = 0;    // set opened off.
  138.     if(!opened)        // if not on return 0.
  139.         return 0;       
  140.     int ret = 0;       
  141.     if(out_waiting())    // if output in buffer.
  142.             // flush output buffer.
  143.         ret = (overflow(EOF) == EOF) ? 1 : 0;    
  144.     if(mode)        // if mode is 0, don't
  145.         delete stream;    // close or delete stream.
  146.     opened = 0;        // set opened off.
  147.     return ret ? 0 : this;
  148. }
  149.  
  150. // Write data from buffer to stream.  This function 
  151. // is called when the buffer is full and we need to 
  152. // output more characters.  The parameter c is the 
  153. // character that caused the overflow.  If the 
  154. // stream is buffered, it will be placed in the 
  155. // buffer, otherwise it is written to the stream.
  156. // If input char is EOF, don't write, just flush.  
  157. // Returns EOF on error, or 1 on success.  
  158. template <class T>
  159. int tbuf<T>::overflow(int c)
  160. {
  161.     if(!opened ||     // check to see if stream
  162.         mode == 0 ||     // is on and mode is out.
  163.         !(mode&ios::out))
  164.         return EOF;            
  165.     if(unbuffered())
  166.     {
  167.         if(c != EOF)
  168.         {        // if unbuffered, 
  169.             char b = c;    // write single char
  170.             if(stream->write(&b, 1) != 1)
  171.                 return EOF;
  172.         }
  173.     }
  174.     else        // else if buffered.
  175.     {
  176.         if(sync() != 0)    // sync input and output 
  177.             return EOF;    // when writing
  178.         resetpg(1);    // reset the put/get pointers
  179.         if(c != EOF)
  180.         {
  181.             sputc(c);    // add c to the buffer
  182.             gbump(1);   // move the get pointer
  183.         }
  184.     }
  185.     return 1;        // return OK
  186. }
  187.  
  188. // Open stream.  If mode ios::ate (at end) is on, 
  189. // seek to end
  190. template <class T>
  191. tbuf<T>* tbuf<T>::open(const char* n, int m, int p)
  192. {
  193.     if(opened || !m)    // if already on, or no mode,
  194.         return 0;    // return error.
  195.     stream = new T;    // make new stream pointer.
  196.     stream->open(n, m, p);// open stream.
  197.     if(!*stream)    // if stream not open,
  198.         return 0;    // return error.
  199.     opened = 1;        // set to on.
  200.     mode = m;        // remeber mode.
  201.     if((mode & ios::ate) &&    
  202.            stream->seek(0L, ios::end) == EOF)
  203.         return 0;    // seek to end if ios::ate. 
  204.     resetpg();        // reset put/get pointers.
  205.     return this;    // return OK.
  206. }
  207.  
  208. // Set the buffer, reset the put/get pointers.  
  209. // Return 0 on error, this if OK.
  210. template <class T>
  211. streambuf* tbuf<T>::setbuf(char* b, int l)
  212. {
  213.     if(!b)        // turn off buffering.
  214.     {
  215.         streambuf::unbuffered(1);
  216.         return this;
  217.     }
  218.     if(opened && base())// check if stream is opened,
  219.         return 0;       // , and no buffer yet.
  220.     setb(b, b+l, 0);    // set buffer pointers.
  221.     resetpg();        // reset put/get pointers.
  222.     return this;    // return OK.
  223. }
  224.  
  225. // Seek to offset.  dir indicates the relativity of 
  226. // the offset, ethier from beginning, current postion,
  227. // or end (ios::beg, ios::cur, ios::end).  
  228. // First make sure there's nothing in the buffer.
  229. template <class T>
  230. long tbuf<T>::seekoff(long off, ios::seek_dir dir, 
  231.                              int /* mode ignored */)
  232. {
  233.     long loff = off;
  234.     int count = out_waiting();    // flush output first.
  235.     if(count)
  236.     {       
  237.         if(stream->write(pbase(), count) != count)
  238.             return EOF;
  239.     }
  240.     else if(dir == ios::cur && // if relative seek,
  241.             (count = in_avail()) != 0)
  242.         loff -= count;        // discount input.
  243.     resetpg();            // reset pointers.
  244.     return stream->seek(loff, dir);
  245. }
  246.  
  247. // sync input and output buffer pointers.  If output
  248. // is waiting, write it, if input is waiting, 
  249. // back up to read it again
  250. template <class T>
  251. int tbuf<T>::sync()
  252. {
  253.     if (!opened)        // check if opened.
  254.         return EOF;
  255.     int count = out_waiting();    // check for output,
  256.     if(count)            // in buffer.
  257.     {
  258.         if(stream->write(pbase(), count) != count)
  259.             return EOF;        // write output. 
  260.         resetpg(1);
  261.     }
  262.     else if(in_avail())        // check for input
  263.     {                // in buffer
  264.         long pos = stream->seek(long(-in_avail()), 
  265.                                          ios::cur);
  266.         setg(eback(), gptr(), gptr());
  267.         setp(gptr(), gptr());    // set up to re-read.
  268.         if(pos == EOF)
  269.             return EOF;
  270.     }
  271.     return 0;
  272. }
  273.  
  274. // Read from stream to fill buffer.  Must be opened and
  275. // in input mode.  If there is input in the buffer,
  276. // return it.  Otherwise call sync, read from stream,
  277. // and set pointers.  If the input is unbuffered,
  278. // use the lookahead buffer.
  279. template <class T>
  280. int tbuf<T>::underflow()
  281. {
  282.     if(!opened || mode == 0 || !(mode&ios::in))
  283.         return EOF;    // check for correct mode.
  284.     if(in_avail())        // if available from buffer,
  285.         return *gptr()&0xFF;    // don't bother.
  286.     int c;  
  287.     int count;  
  288.     if(unbuffered())        // if unbuffered.
  289.     {     
  290.         count = stream->read(lookAhead, 1);
  291.         if(count == EOF)    // read one char
  292.         {            // into look ahead
  293.             c = EOF;        // buffer.
  294.             setg(0, 0, 0);    
  295.         }
  296.         else
  297.         {
  298.             c = lookAhead[0]&0xFF;
  299.             setg(lookAhead, lookAhead, lookAhead+1);
  300.         }
  301.     }
  302.     else            // else buffered.
  303.     {     
  304.         if(sync() != 0)        // sync pointers.
  305.             return EOF;
  306.         int pb = putBackSize();
  307.         char *b = base();    // read into buffer.
  308.         count = stream->read(b+pb, blen()-pb);
  309.         if(count == EOF)    // check read return.
  310.             return EOF;
  311.         setg(b, b+pb, b+pb+count);
  312.         setp(b+pb, b+pb);    // set pointers.
  313.         if(count)        // return first char.
  314.             c = *gptr()&0xFF;
  315.     }
  316.     if(!count)
  317.         c = EOF;    
  318.     return c;
  319. }
  320.  
  321. // reset the put and get pointers.  If end is
  322. // true set the end pointers to the end of 
  323. // the buffer.
  324. template<class T>
  325. void tbuf<T>::resetpg(int end)
  326. {    
  327.     char *buf = base();    // get the start of buffer.
  328.     char *sbuf = buf + (buf ? putBackSize() : 0);
  329.     char *ebuf;        // set start and end pointers.
  330.     if(end)
  331.         ebuf = buf + blen();
  332.     else
  333.         ebuf = sbuf;
  334.     setp(sbuf, ebuf);    // set put pointer
  335.     setg(buf, sbuf, sbuf);// set get pointer
  336. }
  337.  
  338. // tstreambase is virtually derived from ios.  ios
  339. // does not define any functionality for tstreambase
  340. // but allows communication between tstreambase and
  341. // istream, ostream and stream classes.  The functions
  342. // defined in tstreambase typically call the same 
  343. // named function for its tbuf<> member and set ios 
  344. // status flags.  When a tstreambase is constructed
  345. // ios is initialized with a pointer to the tbuf<> 
  346. // member.  ios see this pointer as a streambuf
  347. // pointer, and only has access to tbuf<> through the 
  348. // virtual functions, overflow, underflow, sync, and 
  349. // seekoff.
  350. template <class T>
  351. class  tstreambase : virtual public ios {
  352. public:
  353. // Default constructor.  Make an unattached
  354. // buffer, and initialize ios with it's pointer.
  355.     tstreambase()
  356.         : tbbuf()
  357.     {
  358.         ios::init(&tbbuf);
  359.     }
  360. // Make a buffer attach to named stream, and open
  361. // stream
  362.     tstreambase(const char* n, int m, 
  363.                   int p = tbuf<T>::openProtect)
  364.         : tbbuf()
  365.     {
  366.         ios::init(&tbbuf);
  367.         open(n, m, p);
  368.     }
  369. // Make a buffer attached to already opened stream.
  370.     tstreambase(T &f)
  371.         : tbbuf(f)
  372.     {
  373.         ios::init(&tbbuf);
  374.     }
  375. // Make a buffer using parameters, and attach
  376. // to already opened stream.
  377.     tstreambase(T &f, char* b, int l)
  378.         : tbbuf(f, b, l)
  379.     {
  380.         ios::init(&tbbuf);
  381.     }
  382. // Destroy buffer
  383.     ~tstreambase()
  384.     {
  385.         ;
  386.     }
  387. // close attached stream and set ios flags.
  388.     void close()
  389.     {
  390.         if(tbbuf.close())
  391.             clear(ios::goodbit);
  392.         else
  393.             setstate(ios::failbit);
  394.     }
  395. // set buffer and set ios flags.
  396.     void tstreambase::setbuf(char* b, int l)
  397.     {
  398.         if(tbbuf.setbuf(b, l))
  399.             clear(ios::goodbit);
  400.         else
  401.             setstate(ios::failbit);
  402.     }
  403. // open stream and set ios flags.
  404.     void open(const char  *, int, 
  405.                     int = tbuf<T>::openProtect);
  406. // attach opened stream and set ios flags.
  407.     void attach(T &);
  408. // return the buffer.
  409.     tbuf<T> *rdbuf() 
  410.     { 
  411.         return &tbbuf; 
  412.     }
  413. private:
  414.     tbuf<T> tbbuf;
  415. };
  416.  
  417. // Attempt to open tbuf<>, and set ios flags 
  418. // accordingly.  Opening an already open stream 
  419. // results in an error.  If ios::app (append to 
  420. // file) is set, also set ios::out.  If ios::out 
  421. // is set, and ios::app, ios::in, and ios::ate 
  422. // (start at end) are not set, set the ios::trunc bit.
  423. template <class T>
  424. void tstreambase<T>::open(const char *n, int m, int p)
  425. {
  426.     if(m & ios::app)
  427.         m |= ios::out;  
  428.     else if((m & (ios::out|ios::ate|ios::app|ios::in)) 
  429.                                           == ios::out)
  430.         m |= ios::trunc; 
  431.     if(tbbuf.is_open())
  432.         clear(ios::failbit);        
  433.     else if(tbbuf.open(n, m, p))
  434.         clear(ios::goodbit);        
  435.     else
  436.         clear(ios::badbit);     
  437. }
  438.  
  439. // Attach an opened stream to buffer, and set the ios
  440. // bits accordingly.
  441. template <class T>
  442. void tstreambase<T>::attach(T &f)
  443. {
  444.     if(tbbuf.is_open())
  445.         setstate(ios::failbit);
  446.     else if(tbbuf.attach(f))
  447.         clear(ios::goodbit);
  448.     else
  449.         clear(ios::badbit);
  450. }
  451.  
  452. // The itstream, otstream and tstream class are merely
  453. // "shell" classes, and serve only to combine the 
  454. // functionality of it's base class.  The only functions
  455. // defined are the constructor and destructors, and 
  456. // open and rdbuf.  There are no addition data members
  457. // and all functions call directly the functions of the
  458. // base class.  The default open mode is ios::in for
  459. // itstream, ios::out for otstream, and both for 
  460. // tstream.
  461. template <class T>
  462. class  itstream : public tstreambase<T>, 
  463.                               public istream {
  464. public:
  465.     itstream() 
  466.     {
  467.         ;
  468.     }
  469.     itstream(const  char* n, int m = ios::in, 
  470.                         int p = tbuf<T>::openProtect) 
  471.         : tstreambase<T>(n, m | ios::in, p)       
  472.     {
  473.         ;
  474.     }
  475.     itstream(T &f) 
  476.         : tstreambase<T>(f)
  477.     {
  478.         ;
  479.     }
  480.     itstream(T &f,  char* b, int l) 
  481.         : tstreambase<T>(f, b, l)
  482.     {
  483.         ;
  484.     }
  485.     ~itstream()
  486.     {
  487.         ;
  488.     }
  489.     tbuf<T> *rdbuf() 
  490.     { 
  491.         return tstreambase<T>::rdbuf(); 
  492.     }
  493.     void open(const char  *n, int m = ios::in, 
  494.                        int p = tbuf<T>::openProtect)
  495.     {
  496.         tstreambase<T>::open(n, m | ios::in, p);
  497.     }
  498. };
  499.  
  500. template <class T>
  501. class  otstream : public tstreambase<T>, 
  502.                                 public ostream {
  503. public:
  504.     otstream() 
  505.     {
  506.         ;
  507.     }
  508.     otstream(const char* n, int m = ios::out, 
  509.                     int p = tbuf<T>::openProtect) 
  510.         : tstreambase<T>(n, m | ios::out, p)
  511.     {
  512.         ;
  513.     }
  514.     otstream(T &f) 
  515.         : tstreambase<T>(f)
  516.     {
  517.         ;
  518.     }
  519.     otstream(T &f, char* b, int l) 
  520.         : tstreambase<T>(f, b, l)
  521.     {
  522.         ;
  523.     }
  524.     ~otstream()
  525.     {
  526.         ;
  527.     }
  528.     tbuf<T> *rdbuf() 
  529.     { 
  530.         return tstreambase<T>::rdbuf(); 
  531.     }
  532.     void open(const char  *n, int m = ios::out, 
  533.                      int p = tbuf<T>::openProtect)
  534.     {
  535.         tstreambase<T>::open(n, m | ios::out, p);
  536.     }
  537. };
  538.  
  539. template <class T>
  540. class  tstream : public tstreambase<T>, 
  541.                             public iostream {
  542. public:
  543.     tstream() 
  544.     {
  545.         ;
  546.     }
  547.     tstream(const char  *n, int m, 
  548.                   int p = tbuf<T>::openProtect)
  549.         : tstreambase<T>(n, m, p)
  550.     {
  551.         ;
  552.     }
  553.     tstream(T &f) 
  554.         : tstreambase<T>(f)
  555.     {
  556.         ;
  557.     }
  558.     tstream(T &f, char *b, int l) 
  559.         : tstreambase<T>(f, b, l), iostream()
  560.     {
  561.         ;
  562.     }
  563.     ~tstream()
  564.     {
  565.         ;
  566.     }
  567.     tbuf<T>  *rdbuf() 
  568.     {
  569.         return tstreambase<T>::rdbuf();
  570.     }
  571.     void open(const char *n, int m, 
  572.               int p = tbuf<T>::openProtect)
  573.     {
  574.         tstreambase<T>::open(n, m, p);
  575.     }
  576. };
  577.  
  578. #endif
  579.  
  580.