ncbi_conn_streambuf.cpp
上传用户:yhdzpy8989
上传日期:2007-06-13
资源大小:13604k
文件大小:15k
源码类别:

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: ncbi_conn_streambuf.cpp,v $
  4.  * PRODUCTION Revision 1000.5  2004/06/01 18:44:44  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R6.46
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: ncbi_conn_streambuf.cpp,v 1000.5 2004/06/01 18:44:44 gouriano Exp $
  10.  * ===========================================================================
  11.  *
  12.  *                            PUBLIC DOMAIN NOTICE
  13.  *               National Center for Biotechnology Information
  14.  *
  15.  *  This software/database is a "United States Government Work" under the
  16.  *  terms of the United States Copyright Act.  It was written as part of
  17.  *  the author's official duties as a United States Government employee and
  18.  *  thus cannot be copyrighted.  This software/database is freely available
  19.  *  to the public for use. The National Library of Medicine and the U.S.
  20.  *  Government have not placed any restriction on its use or reproduction.
  21.  *
  22.  *  Although all reasonable efforts have been taken to ensure the accuracy
  23.  *  and reliability of the software and data, the NLM and the U.S.
  24.  *  Government do not and cannot warrant the performance or results that
  25.  *  may be obtained by using this software or data. The NLM and the U.S.
  26.  *  Government disclaim all warranties, express or implied, including
  27.  *  warranties of performance, merchantability or fitness for any particular
  28.  *  purpose.
  29.  *
  30.  *  Please cite the author in any work or product based on this material.
  31.  *
  32.  * ===========================================================================
  33.  *
  34.  * Author:  Anton Lavrentiev, Denis Vakatov
  35.  *
  36.  * File Description:
  37.  *   CONN-based C++ stream buffer
  38.  *
  39.  */
  40. #include <ncbi_pch.hpp>
  41. #include "ncbi_conn_streambuf.hpp"
  42. #include <corelib/ncbidbg.hpp>
  43. #include <connect/ncbi_conn_exception.hpp>
  44. #include <memory>
  45. #define LOG_IF_ERROR(status, msg) x_LogIfError(__FILE__, __LINE__, status, msg)
  46. BEGIN_NCBI_SCOPE
  47. CConn_Streambuf::CConn_Streambuf(CONNECTOR connector, const STimeout* timeout,
  48.                                  streamsize buf_size, bool tie)
  49.     : m_Conn(0), m_ReadBuf(0), m_BufSize(buf_size ? buf_size : 1),
  50.       m_Tie(tie), x_Pos((CT_OFF_TYPE)(0))
  51. {
  52.     if ( !connector ) {
  53.         ERR_POST("CConn_Streambuf::CConn_Streambuf(): NULL connector");
  54.         return;
  55.     }
  56.     if (LOG_IF_ERROR(CONN_Create(connector, &m_Conn),
  57.                      "CConn_Streambuf(): CONN_Create() failed") !=eIO_Success){
  58.         return;
  59.     }
  60.     _ASSERT(m_Conn != 0);
  61.     CONN_SetTimeout(m_Conn, eIO_Open,  timeout);
  62.     CONN_SetTimeout(m_Conn, eIO_Read,  timeout);
  63.     CONN_SetTimeout(m_Conn, eIO_Write, timeout);
  64.     CONN_SetTimeout(m_Conn, eIO_Close, timeout);
  65.     m_ReadBuf  = buf_size ? new CT_CHAR_TYPE[m_BufSize << 1] : &x_Buf;
  66.     m_WriteBuf = buf_size ? m_ReadBuf + m_BufSize            : 0;
  67.     setg(m_ReadBuf,  m_ReadBuf, m_ReadBuf);  // Empty get area
  68.     setp(m_WriteBuf, m_WriteBuf + buf_size); // Put area (if any)
  69. }
  70. CConn_Streambuf::~CConn_Streambuf()
  71. {
  72.     sync();
  73.     EIO_Status status;
  74.     if (m_Conn  &&  (status = CONN_Close(m_Conn)) != eIO_Success) {
  75.         _TRACE("CConn_Streambuf::~CConn_Streambuf(): "
  76.                "CONN_Close() failed (" << IO_StatusStr(status) << ")");
  77.     }
  78.     if (m_ReadBuf != &x_Buf)
  79.         delete[] m_ReadBuf;
  80. }
  81. CT_INT_TYPE CConn_Streambuf::overflow(CT_INT_TYPE c)
  82. {
  83.     if ( !m_Conn )
  84.         return CT_EOF;
  85.     if ( m_WriteBuf ) {
  86.         // send buffer
  87.         size_t n_write = pptr() - m_WriteBuf;
  88.         if ( n_write ) {
  89.             size_t n_written;
  90.             n_write *= sizeof(CT_CHAR_TYPE);
  91.             LOG_IF_ERROR(CONN_Write(m_Conn, m_WriteBuf, n_write,
  92.                                     &n_written, eIO_WritePlain),
  93.                          "overflow(): CONN_Write() failed");
  94.             if ( !n_written )
  95.                 return CT_EOF;
  96.             n_written /= sizeof(CT_CHAR_TYPE);
  97.             // update buffer content (get rid of data just sent)
  98.             if (n_written != n_write) {
  99.                 memmove(m_WriteBuf, m_WriteBuf + n_written,
  100.                         (n_write - n_written)*sizeof(CT_CHAR_TYPE));
  101.             }
  102.             x_Pos += (CT_OFF_TYPE)(n_written);
  103.             setp(m_WriteBuf + n_write - n_written, m_WriteBuf + m_BufSize);
  104.         }
  105.         // store char
  106.         return CT_EQ_INT_TYPE(c, CT_EOF)
  107.             ? CT_NOT_EOF(CT_EOF) : sputc(CT_TO_CHAR_TYPE(c));
  108.     }
  109.     if ( !CT_EQ_INT_TYPE(c, CT_EOF) ) {
  110.         // send char
  111.         size_t n_written;
  112.         CT_CHAR_TYPE b = CT_TO_CHAR_TYPE(c);
  113.         LOG_IF_ERROR(CONN_Write(m_Conn, &b, sizeof(b),
  114.                                 &n_written, eIO_WritePlain),
  115.                      "overflow(): CONN_Write(1) failed");
  116.         return n_written == sizeof(b) ? c : CT_EOF;
  117.     } else if (CONN_Flush(m_Conn) != eIO_Success)
  118.         return CT_EOF;
  119.     return CT_NOT_EOF(CT_EOF);
  120. }
  121. CT_INT_TYPE CConn_Streambuf::underflow(void)
  122. {
  123.     if ( !m_Conn )
  124.         return CT_EOF;
  125.     // flush output buffer, if tied up to it
  126.     if ( m_Tie ) {
  127.         _VERIFY(sync() == 0);
  128.     }
  129.     _ASSERT(!gptr()  ||  gptr() >= egptr());
  130. #ifdef NCBI_COMPILER_MIPSPRO
  131.     if (m_MIPSPRO_ReadsomeGptrSetLevel  &&  m_MIPSPRO_ReadsomeGptr != gptr())
  132.         return CT_EOF;
  133.     m_MIPSPRO_ReadsomeGptr = (CT_CHAR_TYPE*)(-1L);
  134. #endif
  135.     // read from connection
  136.     size_t     n_read;
  137.     EIO_Status status = CONN_Read(m_Conn, m_ReadBuf,
  138.                                   m_BufSize*sizeof(CT_CHAR_TYPE),
  139.                                   &n_read, eIO_ReadPlain);
  140.     if ( !n_read ) {
  141.         if (status != eIO_Closed)
  142.             LOG_IF_ERROR(status, "underflow(): CONN_Read() failed");
  143.         return CT_EOF;
  144.     }
  145.     // update input buffer with data just read
  146.     setg(m_ReadBuf, m_ReadBuf, m_ReadBuf + n_read/sizeof(CT_CHAR_TYPE));
  147.     return CT_TO_INT_TYPE(*m_ReadBuf);
  148. }
  149. streamsize CConn_Streambuf::xsgetn(CT_CHAR_TYPE* buf, streamsize m)
  150. {
  151.     if ( !m_Conn )
  152.         return 0;
  153.     // flush output buffer, if tied up to it
  154.     if ( m_Tie ) {
  155.         _VERIFY(sync() == 0);
  156.     }
  157.     if (m <= 0)
  158.         return 0;
  159.     size_t n = (size_t) m;
  160.     size_t n_read;
  161.     // read from the memory buffer
  162.     if (gptr()  &&  gptr() < egptr()) {
  163.         n_read = egptr() - gptr();
  164.         if (n_read > n)
  165.             n_read = n;
  166.         memcpy(buf, gptr(), n_read*sizeof(CT_CHAR_TYPE));
  167.         gbump((int) n_read);
  168.         buf += n_read;
  169.         n   -= n_read;
  170.     } else
  171.         n_read = 0;
  172.     if (n == 0)
  173.         return (streamsize) n_read;
  174.     do {
  175.         size_t       x_read = n < (size_t) m_BufSize ? m_BufSize : n;
  176.         CT_CHAR_TYPE* x_buf = n < (size_t) m_BufSize ? m_ReadBuf : buf;
  177.         EIO_Status   status = CONN_Read(m_Conn, x_buf,
  178.                                         x_read*sizeof(CT_CHAR_TYPE),
  179.                                         &x_read, eIO_ReadPlain);
  180.         if (!(x_read /= sizeof(CT_CHAR_TYPE)))
  181.             break;
  182.         // satisfy "usual backup condition", see standard: 27.5.2.4.3.13
  183.         if (x_buf == m_ReadBuf) {
  184.             size_t xx_read = x_read;
  185.             if (x_read > n)
  186.                 x_read = n;
  187.             memcpy(buf, m_ReadBuf, x_read*sizeof(CT_CHAR_TYPE));
  188.             setg(m_ReadBuf, m_ReadBuf + x_read, m_ReadBuf + xx_read);
  189.         } else {
  190.             _ASSERT(x_read <= n);
  191.             size_t xx_read = x_read > (size_t) m_BufSize ? m_BufSize : x_read;
  192.             memcpy(m_ReadBuf,buf+x_read-xx_read,xx_read*sizeof(CT_CHAR_TYPE));
  193.             setg(m_ReadBuf, m_ReadBuf + xx_read, m_ReadBuf + xx_read);
  194.         }
  195.         n_read += x_read;
  196.         if (status != eIO_Success)
  197.             break;
  198.         buf    += x_read;
  199.         n      -= x_read;
  200.     } while ( n );
  201.     return (streamsize) n_read;
  202. }
  203. streamsize CConn_Streambuf::showmanyc(void)
  204. {
  205.     if ( !m_Conn )
  206.         return -1;
  207.     // flush output buffer, if tied up to it
  208.     if ( m_Tie ) {
  209.         _VERIFY(sync() == 0);
  210.     }
  211.     _ASSERT(!gptr()  ||  gptr() >= egptr());
  212.     switch (CONN_Wait(m_Conn, eIO_Read, CONN_GetTimeout(m_Conn, eIO_Read))) {
  213.     case eIO_Success:
  214.         return  1;      // can read at least 1 byte
  215.     case eIO_Closed:
  216.         return -1;      // EOF
  217.     default:
  218.         return  0;      // no data available immediately
  219.     }
  220. }
  221. int CConn_Streambuf::sync(void)
  222. {
  223.     if ( !m_Conn )
  224.         return -1;
  225.     do {
  226.         if (CT_EQ_INT_TYPE(overflow(CT_EOF), CT_EOF))
  227.             return -1;
  228.     } while (m_WriteBuf  &&  pptr() > m_WriteBuf);
  229.     return 0;
  230. }
  231. CNcbiStreambuf* CConn_Streambuf::setbuf(CT_CHAR_TYPE* /*buf*/,
  232.                                         streamsize    /*buf_size*/)
  233. {
  234.     NCBI_THROW(CConnException, eConn, "CConn_Streambuf::setbuf() not allowed");
  235.     /*NOTREACHED*/
  236.     return this; /*dummy for compiler*/
  237. }
  238. CT_POS_TYPE CConn_Streambuf::seekoff(CT_OFF_TYPE off, IOS_BASE::seekdir whence,
  239.                                      IOS_BASE::openmode which)
  240. {
  241.     if (off == 0  &&  whence == IOS_BASE::cur  &&  which == IOS_BASE::out)
  242.         return x_Pos + (CT_OFF_TYPE)(pptr() ? pptr() - m_WriteBuf : 0);
  243.     return (CT_POS_TYPE)((CT_OFF_TYPE)(-1));
  244. }
  245. EIO_Status CConn_Streambuf::x_LogIfError(const char* file, int line,
  246.                                          EIO_Status status, const string& msg)
  247. {
  248.     if (status != eIO_Success) {
  249.         CNcbiDiag(file, line) << "CConn_Streambuf::" << msg <<
  250.             " (" << IO_StatusStr(status) << ")" << Endm;
  251.     }
  252.     return status;
  253. }
  254. END_NCBI_SCOPE
  255. /*
  256.  * ---------------------------------------------------------------------------
  257.  * $Log: ncbi_conn_streambuf.cpp,v $
  258.  * Revision 1000.5  2004/06/01 18:44:44  gouriano
  259.  * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R6.46
  260.  *
  261.  * Revision 6.46  2004/05/17 20:58:13  gorelenk
  262.  * Added include of PCH ncbi_pch.hpp
  263.  *
  264.  * Revision 6.45  2004/02/23 15:23:39  lavr
  265.  * New (last) parameter "how" added in CONN_Write() API call
  266.  *
  267.  * Revision 6.44  2004/01/14 22:21:39  vasilche
  268.  * Removed duplicate default arguments.
  269.  *
  270.  * Revision 6.43  2004/01/14 20:24:29  lavr
  271.  * CConnStreambuf::seekoff(0, cur, out) added and implemented
  272.  *
  273.  * Revision 6.42  2004/01/09 17:39:15  lavr
  274.  * Define and use internal 1-byte buffer for unbuffered streams' get ops
  275.  *
  276.  * Revision 6.41  2003/11/12 17:45:20  lavr
  277.  * Minor cosmetic fix
  278.  *
  279.  * Revision 6.40  2003/11/12 16:40:13  ivanov
  280.  * Fixed initial setup of get pointers (by Anton Lavrentiev)
  281.  *
  282.  * Revision 6.39  2003/11/04 03:09:28  lavr
  283.  * xsgetn() fixed to advance buffer pointer when reading
  284.  *
  285.  * Revision 6.38  2003/11/03 20:06:49  lavr
  286.  * Fix log message of the previous commit:
  287.  * CConn_Streambuf::xsgetn() made standard-conforming
  288.  *
  289.  * Revision 6.36  2003/10/22 18:16:09  lavr
  290.  * More consistent use of buffer pointers in the implementation
  291.  *
  292.  * Revision 6.35  2003/10/07 19:59:40  lavr
  293.  * Replace '==' with (better) 'CT_EQ_INT_TYPE'
  294.  *
  295.  * Revision 6.34  2003/09/23 21:05:50  lavr
  296.  * Rearranged included headers
  297.  *
  298.  * Revision 6.33  2003/05/31 05:24:43  lavr
  299.  * NOTREACHED added after exception throw
  300.  *
  301.  * Revision 6.32  2003/05/20 19:07:57  lavr
  302.  * Constructor changed (assert -> _ASSERT);  better destructor
  303.  *
  304.  * Revision 6.31  2003/05/20 18:24:06  lavr
  305.  * Set non-zero ptrs (but still empty buf) in constructor to explicitly show
  306.  * (to the stream level) that this streambuf has a memory-resident buffer
  307.  *
  308.  * Revision 6.30  2003/05/20 18:05:53  lavr
  309.  * x_LogIfError() to accept and print approproate file location
  310.  *
  311.  * Revision 6.29  2003/05/20 16:46:29  lavr
  312.  * Check for NULL connection in every streambuf method before proceding
  313.  *
  314.  * Revision 6.28  2003/05/12 18:32:27  lavr
  315.  * Modified not to throw exceptions from stream buffer; few more improvements
  316.  *
  317.  * Revision 6.27  2003/04/25 15:20:37  lavr
  318.  * Avoid GCC signed/unsigned warning by explicit cast
  319.  *
  320.  * Revision 6.26  2003/04/11 17:57:11  lavr
  321.  * Define xsgetn() unconditionally
  322.  *
  323.  * Revision 6.25  2003/03/30 07:00:09  lavr
  324.  * MIPS-specific workaround for lamely-designed stream read ops
  325.  *
  326.  * Revision 6.24  2003/03/28 03:58:08  lavr
  327.  * CConn_Streambuf::xsgetn(): tiny formal fix in backup condition
  328.  *
  329.  * Revision 6.23  2003/03/28 03:30:36  lavr
  330.  * Define CConn_Streambuf::xsgetn() unconditionally of compiler
  331.  *
  332.  * Revision 6.22  2002/12/19 17:24:08  lavr
  333.  * Take advantage of new CConnException
  334.  *
  335.  * Revision 6.21  2002/10/28 15:46:20  lavr
  336.  * Use "ncbi_ansi_ext.h" privately
  337.  *
  338.  * Revision 6.20  2002/08/28 03:40:54  lavr
  339.  * Better buffer filling in xsgetn()
  340.  *
  341.  * Revision 6.19  2002/08/27 20:27:36  lavr
  342.  * xsgetn(): if reading from external source try to pull as much as possible
  343.  *
  344.  * Revision 6.18  2002/08/07 16:32:12  lavr
  345.  * Changed EIO_ReadMethod enums accordingly
  346.  *
  347.  * Revision 6.17  2002/06/06 19:03:25  lavr
  348.  * Take advantage of CConn_Exception class and do not throw from destructor
  349.  * Some housekeeping: log moved to the end
  350.  *
  351.  * Revision 6.16  2002/02/05 22:04:12  lavr
  352.  * Included header files rearranged
  353.  *
  354.  * Revision 6.15  2002/02/05 16:05:26  lavr
  355.  * List of included header files revised
  356.  *
  357.  * Revision 6.14  2002/02/04 20:19:55  lavr
  358.  * +xsgetn() for MIPSPro compiler (buggy version supplied with std.library)
  359.  * More assert()'s inserted into the code to check standard compliance
  360.  *
  361.  * Revision 6.13  2002/01/30 20:09:00  lavr
  362.  * Define xsgetn() for WorkShop compiler also; few patches in underflow();
  363.  * sync() properly redesigned (now standard-conformant)
  364.  *
  365.  * Revision 6.12  2002/01/28 20:20:18  lavr
  366.  * Use auto_ptr only in constructor; satisfy "usual backup cond" in xsgetn()
  367.  *
  368.  * Revision 6.11  2001/12/07 22:58:44  lavr
  369.  * More comments added
  370.  *
  371.  * Revision 6.10  2001/05/29 19:35:21  grichenk
  372.  * Fixed non-blocking stream reading for GCC
  373.  *
  374.  * Revision 6.9  2001/05/17 15:02:50  lavr
  375.  * Typos corrected
  376.  *
  377.  * Revision 6.8  2001/05/14 16:47:45  lavr
  378.  * streambuf::xsgetn commented out as it badly interferes
  379.  * with truly-blocking stream reading via istream::read.
  380.  *
  381.  * Revision 6.7  2001/05/11 20:40:48  lavr
  382.  * Workaround of compiler warning about comparison of streamsize and size_t
  383.  *
  384.  * Revision 6.6  2001/05/11 14:04:07  grichenk
  385.  * +CConn_Streambuf::xsgetn(), +CConn_Streambuf::showmanyc()
  386.  *
  387.  * Revision 6.5  2001/03/26 18:36:39  lavr
  388.  * CT_EQ_INT_TYPE used throughout to compare CT_INT_TYPE values
  389.  *
  390.  * Revision 6.4  2001/03/24 00:34:40  lavr
  391.  * Accurate conversions between CT_CHAR_TYPE and CT_INT_TYPE
  392.  * (BUGFIX: promotion of (signed char)255 to int caused EOF (-1) gets returned)
  393.  *
  394.  * Revision 6.3  2001/01/12 23:49:20  lavr
  395.  * Timeout and GetCONN method added
  396.  *
  397.  * Revision 6.2  2001/01/11 23:04:06  lavr
  398.  * Bugfixes; tie is now done at streambuf level, not in iostream
  399.  *
  400.  * Revision 6.1  2001/01/09 23:34:51  vakatov
  401.  * Initial revision (draft, not tested in run-time)
  402.  *
  403.  * ===========================================================================
  404.  */