[med-svn] [bamtools] 01/08: Imported Upstream version 2.3.0+dfsg

Andreas Tille tille at debian.org
Wed Apr 2 13:31:04 UTC 2014


This is an automated email from the git hooks/post-receive script.

tille pushed a commit to branch debian
in repository bamtools.

commit bfd618f4f7aa2f73bab5b585749d9b6b989f4c5c
Author: Andreas Tille <tille at debian.org>
Date:   Wed Apr 2 13:11:36 2014 +0200

    Imported Upstream version 2.3.0+dfsg
---
 CMakeLists.txt                            |   4 +-
 docs/Doxyfile                             |   2 +-
 src/api/CMakeLists.txt                    |  14 +-
 src/api/SamHeader.cpp                     |   1 +
 src/api/internal/bam/BamMultiReader_p.cpp |   4 +-
 src/api/internal/index/CMakeLists.txt     |   4 +-
 src/api/internal/io/BamHttp_p.cpp         | 394 ++++++++++++++++++++----------
 src/api/internal/io/BamHttp_p.h           |   8 +-
 src/api/internal/io/CMakeLists.txt        |  22 +-
 src/api/internal/io/HttpHeader_p.h        |   2 +-
 src/api/internal/io/RollingBuffer_p.cpp   |   6 +-
 src/api/internal/io/TcpSocket_p.cpp       |   6 +-
 src/api/internal/io/TcpSocket_p.h         |   6 +-
 src/api/internal/sam/CMakeLists.txt       |   4 +-
 src/api/internal/utils/CMakeLists.txt     |   4 +-
 src/toolkit/CMakeLists.txt                |   2 +-
 src/toolkit/bamtools_convert.cpp          |   2 +-
 src/toolkit/bamtools_coverage.cpp         |   3 +-
 src/toolkit/bamtools_filter.cpp           |  28 ++-
 src/toolkit/bamtools_random.cpp           |  24 +-
 src/toolkit/bamtools_resolve.cpp          |  20 +-
 src/toolkit/bamtools_split.cpp            |  23 +-
 src/utils/CMakeLists.txt                  |   4 +-
 src/utils/bamtools_filter_engine.h        |   5 +-
 24 files changed, 396 insertions(+), 196 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3e81b1a..9b97fa0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -31,8 +31,8 @@ ensure_out_of_source_build( "
 
 # set BamTools version information
 set( BamTools_VERSION_MAJOR 2 )
-set( BamTools_VERSION_MINOR 2 )
-set( BamTools_VERSION_BUILD 3 )
+set( BamTools_VERSION_MINOR 3 )
+set( BamTools_VERSION_BUILD 0 )
 
 # set our library and executable destination dirs
 set( EXECUTABLE_OUTPUT_PATH "${CMAKE_SOURCE_DIR}/bin" )
diff --git a/docs/Doxyfile b/docs/Doxyfile
index ff88c61..410ea27 100644
--- a/docs/Doxyfile
+++ b/docs/Doxyfile
@@ -31,7 +31,7 @@ PROJECT_NAME           = BamTools
 # This could be handy for archiving the generated documentation or 
 # if some version control system is used.
 
-PROJECT_NUMBER         = 2.2.3
+PROJECT_NUMBER         = 2.3.0
 
 # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) 
 # base path where the generated documentation will be put. 
diff --git a/src/api/CMakeLists.txt b/src/api/CMakeLists.txt
index 66eb35f..7e3d3ca 100644
--- a/src/api/CMakeLists.txt
+++ b/src/api/CMakeLists.txt
@@ -13,7 +13,7 @@ add_definitions( -DBAMTOOLS_API_LIBRARY ) # (for proper exporting of library sym
 add_definitions( -fPIC ) # (attempt to force PIC compiling on CentOS, not being set on shared libs by CMake)
 
 # fetch all internal source files
-add_subdirectory ( internal )
+add_subdirectory( internal )
 
 # make list of all API source files
 set( BamToolsAPISources
@@ -34,7 +34,7 @@ set( BamToolsAPISources
 # create main BamTools API shared library
 add_library( BamTools SHARED ${BamToolsAPISources} )
 set_target_properties( BamTools PROPERTIES
-                       SOVERSION "2.2.3"
+                       SOVERSION "2.3.0"
                        OUTPUT_NAME "bamtools" )
 
 # create main BamTools API static library
@@ -44,17 +44,17 @@ set_target_properties( BamTools-static PROPERTIES
                        PREFIX "lib" )
 
 # link libraries automatically with zlib (and Winsock2, if applicable)
-if( _WIN32 )
+if( WIN32 )
     set( APILibs z ws2_32 )
-else( _WIN32 )
+else()
     set( APILibs z )
-endif( _WIN32 )
+endif()
 
-target_link_libraries( BamTools ${APILibs} )
+target_link_libraries( BamTools        ${APILibs} )
 target_link_libraries( BamTools-static ${APILibs} )
 
 # set library install destinations
-install( TARGETS BamTools LIBRARY DESTINATION "lib/bamtools" RUNTIME DESTINATION "bin")
+install( TARGETS BamTools        LIBRARY DESTINATION "lib/bamtools" RUNTIME DESTINATION "bin")
 install( TARGETS BamTools-static ARCHIVE DESTINATION "lib/bamtools")
 
 # export API headers
diff --git a/src/api/SamHeader.cpp b/src/api/SamHeader.cpp
index 967957a..9221944 100644
--- a/src/api/SamHeader.cpp
+++ b/src/api/SamHeader.cpp
@@ -73,6 +73,7 @@ SamHeader::SamHeader(const SamHeader& other)
     , ReadGroups(other.ReadGroups)
     , Programs(other.Programs)
     , Comments(other.Comments)
+    , m_errorString(other.GetErrorString())
 { }
 
 /*! \fn SamHeader::~SamHeader(void)
diff --git a/src/api/internal/bam/BamMultiReader_p.cpp b/src/api/internal/bam/BamMultiReader_p.cpp
index 08d445d..310d837 100644
--- a/src/api/internal/bam/BamMultiReader_p.cpp
+++ b/src/api/internal/bam/BamMultiReader_p.cpp
@@ -2,7 +2,7 @@
 // BamMultiReader_p.cpp (c) 2010 Derek Barnett, Erik Garrison
 // Marth Lab, Department of Biology, Boston College
 // ---------------------------------------------------------------------------
-// Last modified: 14 January 2013 (DB)
+// Last modified: 24 July 2013 (DB)
 // ---------------------------------------------------------------------------
 // Functionality for simultaneously reading multiple BAM files
 // *************************************************************************
@@ -184,7 +184,7 @@ IMultiMerger* BamMultiReaderPrivate::CreateAlignmentCache(void) {
             m_mergeOrder = BamMultiReader::MergeByCoordinate;
 
         // if BAM files are sorted by read name
-        if ( header.SortOrder == Constants::SAM_HD_SORTORDER_QUERYNAME )
+        else if ( header.SortOrder == Constants::SAM_HD_SORTORDER_QUERYNAME )
             m_mergeOrder = BamMultiReader::MergeByName;
 
         // otherwise, sorting is either "unknown" or marked as "unsorted"
diff --git a/src/api/internal/index/CMakeLists.txt b/src/api/internal/index/CMakeLists.txt
index 1c78cb9..d6a7df6 100644
--- a/src/api/internal/index/CMakeLists.txt
+++ b/src/api/internal/index/CMakeLists.txt
@@ -5,9 +5,9 @@
 # src/api/internal/index
 # ==========================
 
-set ( InternalIndexDir "${InternalDir}/index" )
+set( InternalIndexDir "${InternalDir}/index" )
 
-set ( InternalIndexSources
+set( InternalIndexSources
         ${InternalIndexDir}/BamIndexFactory_p.cpp
         ${InternalIndexDir}/BamStandardIndex_p.cpp
         ${InternalIndexDir}/BamToolsIndex_p.cpp
diff --git a/src/api/internal/io/BamHttp_p.cpp b/src/api/internal/io/BamHttp_p.cpp
index 377be82..b089172 100644
--- a/src/api/internal/io/BamHttp_p.cpp
+++ b/src/api/internal/io/BamHttp_p.cpp
@@ -2,7 +2,7 @@
 // BamHttp_p.cpp (c) 2011 Derek Barnett
 // Marth Lab, Department of Biology, Boston College
 // ---------------------------------------------------------------------------
-// Last modified: 8 December 2011 (DB)
+// Last modified: 24 July 2013 (DB)
 // ---------------------------------------------------------------------------
 // Provides reading/writing of BAM files on HTTP server
 // ***************************************************************************
@@ -16,6 +16,7 @@ using namespace BamTools::Internal;
 
 #include <cassert>
 #include <cctype>
+#include <cstdlib>
 #include <algorithm>
 #include <sstream>
 using namespace std;
@@ -34,9 +35,11 @@ static const size_t HTTP_PREFIX_LENGTH = 7;
 static const string DOUBLE_NEWLINE = "\n\n";
 
 static const string GET_METHOD   = "GET";
+static const string HEAD_METHOD  = "HEAD";
 static const string HOST_HEADER  = "Host";
 static const string RANGE_HEADER = "Range";
 static const string BYTES_PREFIX = "bytes=";
+static const string CONTENT_LENGTH_HEADER = "Content-Length";
 
 static const char HOST_SEPARATOR  = '/';
 static const char PROXY_SEPARATOR = ':';
@@ -75,7 +78,8 @@ BamHttp::BamHttp(const string& url)
     , m_response(0)
     , m_isUrlParsed(false)
     , m_filePosition(-1)
-    , m_endRangeFilePosition(-1)
+    , m_fileEndPosition(-1)
+    , m_rangeEndPosition(-1)
 {
     ParseUrl(url);
 }
@@ -88,25 +92,24 @@ BamHttp::~BamHttp(void) {
         delete m_socket;
 }
 
-void BamHttp::Close(void) {
-
-    // disconnect socket
-    m_socket->DisconnectFromHost();
-
-    // clean up request & response
-    if ( m_request )  {
-        delete m_request;
-        m_request = 0;
-    }
+void BamHttp::ClearResponse(void) {
     if ( m_response ) {
         delete m_response;
         m_response = 0;
     }
+}
 
-    // reset state - necessary??
+void BamHttp::Close(void) {
+
+    // disconnect socket & clear related resources
+    DisconnectSocket();
+
+    // reset state
     m_isUrlParsed = false;
-    m_filePosition = -1;
-    m_endRangeFilePosition = -1;
+    m_filePosition     = -1;
+    m_fileEndPosition  = -1;
+    m_rangeEndPosition = -1;
+    m_mode = IBamIODevice::NotOpen;
 }
 
 bool BamHttp::ConnectSocket(void) {
@@ -115,23 +118,7 @@ bool BamHttp::ConnectSocket(void) {
 
     // any state checks, etc?
     if ( !m_socket->ConnectToHost(m_hostname, m_port, m_mode) ) {
-        // TODO: set error string
-        return false;
-    }
-
-    // attempt initial request
-    m_filePosition = 0;
-    m_endRangeFilePosition = -1;
-    if ( !SendRequest() ) {
-        // TODO: set error string
-        Close();
-        return false;
-    }
-
-    // wait for response from server
-    if ( !ReceiveResponse() ) {
-        // TODO: set error string
-        Close();
+        SetErrorString("BamHttp::ConnectSocket", m_socket->GetErrorString());
         return false;
     }
 
@@ -139,10 +126,21 @@ bool BamHttp::ConnectSocket(void) {
     return true;
 }
 
+void BamHttp::DisconnectSocket(void) {
+
+    // disconnect socket & clean up
+    m_socket->DisconnectFromHost();
+    ClearResponse();
+    if ( m_request )  {
+        delete m_request;
+        m_request = 0;
+    }
+}
+
 bool BamHttp::EnsureSocketConnection(void) {
     if ( m_socket->IsConnected() )
         return true;
-    else return ConnectSocket();
+    return ConnectSocket();
 }
 
 bool BamHttp::IsOpen(void) const {
@@ -168,6 +166,20 @@ bool BamHttp::Open(const IBamIODevice::OpenMode mode) {
         return false;
     }
 
+    // initialize our file positions
+    m_filePosition     = 0;
+    m_fileEndPosition  = 0;
+    m_rangeEndPosition = 0;
+
+    // attempt to send initial request (just 'HEAD' to check connection)
+    if ( !SendHeadRequest() ) {
+        SetErrorString("BamHttp::Open", m_socket->GetErrorString());
+        return false;
+    }
+
+    // clear response from HEAD request, not needed
+    ClearResponse();
+
     // return success
     return true;
 }
@@ -216,62 +228,90 @@ int64_t BamHttp::Read(char* data, const unsigned int numBytes) {
     if ( !IsOpen() )
         return -1;
 
-    // read until hit desired @numBytes
-    int64_t bytesReadSoFar = 0;
-    while ( bytesReadSoFar < numBytes ) {
-
-        // calculate number of bytes we're going to try to read this iteration
-        const size_t remainingBytes = ( numBytes - bytesReadSoFar );
+    int64_t numBytesReadSoFar = 0;
+    while ( numBytesReadSoFar < numBytes ) {
 
-        // if socket has access to entire file contents
-        // i.e. we received response with full data (status code == 200)
-        if ( m_endRangeFilePosition < 0 ) {
+        const size_t remaining = static_cast<size_t>( numBytes - numBytesReadSoFar );
 
-            // try to read 'remainingBytes' from socket
-            const int64_t socketBytesRead = ReadFromSocket(data+bytesReadSoFar, remainingBytes);
-            if ( socketBytesRead < 0 ) // error
+        // if we're not holding a valid GET reponse, get one
+        if ( m_response == 0 ) {
+            if ( !SendGetRequest(remaining) )
                 return -1;
-            else if ( socketBytesRead == 0 ) // EOF
-                return bytesReadSoFar;
-            bytesReadSoFar += socketBytesRead;
-            m_filePosition += socketBytesRead;
         }
+        BT_ASSERT_X(m_response, "null HTTP response");
 
-        // socket has access to a range of data (might already be in buffer)
-        // i.e. we received response with partial data (status code == 206)
-        else {
+        // check response status code
+        const int statusCode = m_response->GetStatusCode();
+
+        // if we receieved full file contents in response
+        if ( statusCode == 200 ) {
+
+            // try to read 'remaining' bytes from socket
+            const int64_t socketBytesRead = ReadFromSocket(data+numBytesReadSoFar, remaining);
+
+            // if error
+            if ( socketBytesRead < 0 ) {
+                SetErrorString("BamHttp::Read", m_socket->GetErrorString());
+                return -1;
+            }
+
+            // EOF
+            else if ( socketBytesRead == 0 )
+                return numBytesReadSoFar;
 
-            // there is data left from last request
-            if ( m_endRangeFilePosition > m_filePosition ) {
+            // update counters
+            numBytesReadSoFar += socketBytesRead;
+            m_filePosition    += socketBytesRead;
 
-                // try to read either the total 'remainingBytes' or
-                // whatever we have remaining from last request range
-                const size_t rangeRemainingBytes = m_endRangeFilePosition - m_filePosition;
-                const size_t bytesToRead = std::min(remainingBytes, rangeRemainingBytes);
-                const int64_t socketBytesRead = ReadFromSocket(data+bytesReadSoFar, bytesToRead);
-                if ( socketBytesRead < 0 ) // error
+        }
+
+        // else if we received a range of bytes in response
+        else if ( statusCode == 206 ) {
+
+            // if we've exhausted the last request
+            if ( m_filePosition == m_rangeEndPosition ) {
+                if ( !SendGetRequest(remaining) )
                     return -1;
-                else if ( socketBytesRead == 0 ) // EOF
-                    return bytesReadSoFar;
-                bytesReadSoFar += socketBytesRead;
-                m_filePosition += socketBytesRead;
             }
 
-            // otherwise, this is a 1st-time read or
-            // we already read everything from the last GET request
             else {
 
-                // request for next range
-                if ( !SendRequest(remainingBytes) || !ReceiveResponse() ) {
-                    Close();
+                // try to read 'remaining' bytes from socket
+                const int64_t socketBytesRead = ReadFromSocket(data+numBytesReadSoFar, remaining);
+
+                // if error
+                if ( socketBytesRead < 0 ) {
+                    SetErrorString("BamHttp::Read", m_socket->GetErrorString());
                     return -1;
                 }
+
+                // maybe EOF
+                else if ( socketBytesRead == 0 ) {
+
+                    // if we know we're not at end position, fire off a new request
+                    if ( m_fileEndPosition > 0 && m_filePosition < m_fileEndPosition ) {
+                        if ( !SendGetRequest() )
+                            return -1;
+                    } else
+                        return numBytesReadSoFar;
+                }
+
+                // update counters
+                numBytesReadSoFar += socketBytesRead;
+                m_filePosition    += socketBytesRead;
             }
         }
+
+
+        // else some other HTTP status
+        else {
+            SetErrorString("BamHttp::Read", "unsupported status code in response");
+            return -1;
+        }
     }
 
-    // return actual number bytes successfully read
-    return bytesReadSoFar;
+    // return actual number of bytes read
+    return numBytesReadSoFar;
 }
 
 int64_t BamHttp::ReadFromSocket(char* data, const unsigned int maxNumBytes) {
@@ -280,17 +320,14 @@ int64_t BamHttp::ReadFromSocket(char* data, const unsigned int maxNumBytes) {
 
 bool BamHttp::ReceiveResponse(void) {
 
-    // clear any prior response
-    if ( m_response )
-        delete m_response;
-
-    // make sure we're connected
-    if ( !EnsureSocketConnection() )
-        return false;
-
     // fetch header, up until double new line
     string responseHeader;
     do {
+
+        // make sure we can read a line
+        if ( !m_socket->WaitForReadLine() )
+            return false;
+
         // read line & append to full header
         const string headerLine = m_socket->ReadLine();
         responseHeader += headerLine;
@@ -299,7 +336,7 @@ bool BamHttp::ReceiveResponse(void) {
 
     // sanity check
     if ( responseHeader.empty() ) {
-        // TODO: set error string
+        SetErrorString("BamHttp::ReceiveResponse", "empty HTTP response");
         Close();
         return false;
     }
@@ -307,93 +344,184 @@ bool BamHttp::ReceiveResponse(void) {
     // create response from header text
     m_response = new HttpResponseHeader(responseHeader);
     if ( !m_response->IsValid() ) {
-        // TODO: set error string
+        SetErrorString("BamHttp::ReceiveResponse", "could not parse HTTP response");
         Close();
         return false;
     }
 
-    // if we got range response as requested
-    if ( m_response->GetStatusCode() == 206 )
-        return true;
-
-    // if we got the full file contents instead of range
-    else if ( m_response->GetStatusCode() == 200 ) {
+    // if we get here, success
+    return true;
+}
 
-        // skip up to current file position
-        RaiiBuffer tmp(0x8000);
-        int64_t numBytesRead = 0;
-        while ( numBytesRead < m_filePosition ) {
+bool BamHttp::Seek(const int64_t& position, const int origin) {
 
-            const int64_t remaining = m_filePosition - numBytesRead;
-            const size_t bytesToRead = static_cast<size_t>( (remaining > 0x8000) ? 0x8000 : remaining );
-            const int64_t socketBytesRead = ReadFromSocket(tmp.Buffer, bytesToRead);
-            if ( socketBytesRead < 0 ) { // error
-                Close();
-                return false;
-            }
-            else if ( socketBytesRead == 0 ) // EOF
-                break;
+    // if HTTP device not in a valid state
+    if ( !IsOpen() ) {
+        SetErrorString("BamHttp::Seek", "cannot seek on unopen connection");
+        return false;
+    }
 
-            numBytesRead += socketBytesRead;
-        }
+    // reset the connection
+    DisconnectSocket();
+    if ( !ConnectSocket() ) {
+        SetErrorString("BamHttp::Seek", m_socket->GetErrorString());
+        return false;
+    }
 
-        // return success
-        return ( numBytesRead == m_filePosition);
+    // udpate file position
+    switch ( origin ) {
+        case SEEK_CUR : m_filePosition += position; break;
+        case SEEK_SET : m_filePosition  = position; break;
+        default :
+            SetErrorString("BamHttp::Seek", "unsupported seek origin");
+            return false;
     }
 
-    // on any other reponse status
-    // TODO: set error string
-    Close();
-    return false;
+    // return success
+    return true;
 }
 
-bool BamHttp::Seek(const int64_t& position, const int origin) {
+bool BamHttp::SendGetRequest(const size_t numBytes) {
 
-    // if HTTP device not in a valid state
-    if ( !IsOpen() ) {
-        // TODO: set error string
+    // clear previous data
+    ClearResponse();
+    if ( m_request )
+        delete m_request;
+    m_socket->ClearBuffer();
+
+    // make sure we're connected
+    if ( !EnsureSocketConnection() )
+        return false;
+
+    // create range string
+    const int64_t endPosition = m_filePosition + std::max(static_cast<size_t>(0x10000), numBytes);
+    stringstream range("");
+    range << BYTES_PREFIX << m_filePosition << '-' << endPosition;
+
+    // create request
+    m_request = new HttpRequestHeader(GET_METHOD, m_filename);
+    m_request->SetField(HOST_HEADER,  m_hostname);
+    m_request->SetField(RANGE_HEADER, range.str());
+
+    // send request
+    const string requestHeader = m_request->ToString();
+    const size_t headerSize    = requestHeader.size();
+    if ( WriteToSocket(requestHeader.c_str(), headerSize) != headerSize ) {
+        SetErrorString("BamHttp::SendHeadRequest", m_socket->GetErrorString());
         return false;
     }
 
-    // discard socket's buffer contents, update positions, & return success
+    // ensure clean buffer
     m_socket->ClearBuffer();
 
-    if ( origin == SEEK_CUR )
-        m_filePosition += position;
-    else if ( origin == SEEK_SET )
-        m_filePosition = position;
-    else {
-        // TODO: set error string
+    // wait for response
+    if ( !ReceiveResponse() ) {
+        SetErrorString("BamHttp::SendGetRequest", m_socket->GetErrorString());
+        Close();
         return false;
     }
-    m_endRangeFilePosition = m_filePosition;
-    return true;
+    BT_ASSERT_X(m_response, "BamHttp::SendGetRequest : null HttpResponse");
+    BT_ASSERT_X(m_response->IsValid(), "BamHttp::SendGetRequest : invalid HttpResponse");
+
+    // check response status code
+    const int statusCode = m_response->GetStatusCode();
+    switch ( statusCode ) {
+
+        // ranged response, as requested
+        case 206 :
+            // get content length if available
+            if ( m_response->ContainsKey(CONTENT_LENGTH_HEADER) ) {
+                const string contentLengthString = m_response->GetValue(CONTENT_LENGTH_HEADER);
+                m_rangeEndPosition = m_filePosition + atoi( contentLengthString.c_str() );
+            }
+            return true;
+
+        // full contents, not range
+        case 200 :
+        {
+            // skip up to current file position
+            RaiiBuffer tmp(0x8000);
+            int64_t numBytesRead = 0;
+            while ( numBytesRead < m_filePosition ) {
+
+                // read data from response
+                const int64_t remaining = m_filePosition - numBytesRead;
+                const size_t bytesToRead = static_cast<size_t>( (remaining > 0x8000) ? 0x8000 : remaining );
+                const int64_t socketBytesRead = ReadFromSocket(tmp.Buffer, bytesToRead);
+
+                // if error
+                if ( socketBytesRead < 0 ) {
+                    SetErrorString("BamHttp::SendGetRequest", m_socket->GetErrorString());
+                    Close();
+                    return false;
+                }
+
+                // else if EOF
+                else if ( socketBytesRead == 0 && m_socket->BufferBytesAvailable() == 0 )
+                    break;
+
+                // update byte counter
+                numBytesRead += socketBytesRead;
+            }
+
+            // return success
+            return ( numBytesRead == m_filePosition);
+        }
+
+        // any other status codes
+        default:
+            break;
+    }
+
+    // fail on unexpected status code
+    SetErrorString("BamHttp::SendGetRequest", "unsupported status code in response");
+    Close();
+    return false;
 }
 
-bool BamHttp::SendRequest(const size_t numBytes) {
+bool BamHttp::SendHeadRequest(void) {
 
-    // remove any currently active request
+    // ensure clean slate
+    ClearResponse();
     if ( m_request )
         delete m_request;
-
-    // create range string
-    m_endRangeFilePosition = m_filePosition + numBytes;
-    stringstream range("");
-    range << BYTES_PREFIX << m_filePosition << '-' << m_endRangeFilePosition;
+    m_socket->ClearBuffer();
 
     // make sure we're connected
     if ( !EnsureSocketConnection() )
         return false;
 
     // create request
-    m_request = new HttpRequestHeader(GET_METHOD, m_filename);
-    m_request->SetField(HOST_HEADER,  m_hostname);
-    m_request->SetField(RANGE_HEADER, range.str());
+    m_request = new HttpRequestHeader(HEAD_METHOD, m_filename);
+    m_request->SetField(HOST_HEADER, m_hostname);
 
-    // write request to socket
+    // send request
     const string requestHeader = m_request->ToString();
     const size_t headerSize    = requestHeader.size();
-    return ( WriteToSocket(requestHeader.c_str(), headerSize) == headerSize );
+    if ( WriteToSocket(requestHeader.c_str(), headerSize) != headerSize ) {
+        SetErrorString("BamHttp::SendHeadRequest", m_socket->GetErrorString());
+        return false;
+    }
+
+    m_socket->ClearBuffer();
+
+    // wait for response from server
+    if ( !ReceiveResponse() ) {
+        SetErrorString("BamHttp::SendHeadRequest", m_socket->GetErrorString());
+        Close();
+        return false;
+    }
+    BT_ASSERT_X(m_response, "BamHttp::SendHeadRequest : null HttpResponse");
+    BT_ASSERT_X(m_response->IsValid(), "BamHttp::SendHeadRequest : invalid HttpResponse");
+
+    // get content length if available
+    if ( m_response->ContainsKey(CONTENT_LENGTH_HEADER) ) {
+        const string contentLengthString = m_response->GetValue(CONTENT_LENGTH_HEADER);
+        m_fileEndPosition = atoi( contentLengthString.c_str() ) - 1;
+    }
+
+    // return whether we found any errors
+    return m_socket->GetError() == TcpSocket::NoError;
 }
 
 int64_t BamHttp::Tell(void) const {
diff --git a/src/api/internal/io/BamHttp_p.h b/src/api/internal/io/BamHttp_p.h
index 371ccce..cbbc95c 100644
--- a/src/api/internal/io/BamHttp_p.h
+++ b/src/api/internal/io/BamHttp_p.h
@@ -50,12 +50,15 @@ class BamHttp : public IBamIODevice {
 
     // internal methods
     private:
+        void ClearResponse(void);
         bool ConnectSocket(void);
+        void DisconnectSocket(void);
         bool EnsureSocketConnection(void);
         void ParseUrl(const std::string& url);
         int64_t ReadFromSocket(char* data, const unsigned int numBytes);
         bool ReceiveResponse(void);
-        bool SendRequest(const size_t numBytes = 0);
+        bool SendGetRequest(const size_t numBytes = 0x10000);
+        bool SendHeadRequest(void);
         int64_t WriteToSocket(const char* data, const unsigned int numBytes);
 
     // data members
@@ -78,7 +81,8 @@ class BamHttp : public IBamIODevice {
 
         // file position
         int64_t m_filePosition;
-        int64_t m_endRangeFilePosition;
+        int64_t m_fileEndPosition;
+        int64_t m_rangeEndPosition;
 };
 
 } // namespace Internal
diff --git a/src/api/internal/io/CMakeLists.txt b/src/api/internal/io/CMakeLists.txt
index d9da416..28153d5 100644
--- a/src/api/internal/io/CMakeLists.txt
+++ b/src/api/internal/io/CMakeLists.txt
@@ -5,12 +5,12 @@
 # src/api/internal/io
 # ==========================
 
-set ( InternalIODir "${InternalDir}/io" )
+set( InternalIODir "${InternalDir}/io" )
 
 #--------------------------
 # platform-independent IO
 #--------------------------
-set ( CommonIOSources
+set( CommonIOSources
         ${InternalIODir}/BamDeviceFactory_p.cpp
         ${InternalIODir}/BamFile_p.cpp
         ${InternalIODir}/BamFtp_p.cpp
@@ -30,21 +30,17 @@ set ( CommonIOSources
 #------------------------
 # platform-dependent IO
 #------------------------
-if ( _WIN32 )
-    set ( PlatformIOSources
-            ${InternalIODir}/TcpSocketEngine_win_p.cpp
-    )
-else ( _WIN32 )
-    set ( PlatformIOSources
-            ${InternalIODir}/TcpSocketEngine_unix_p.cpp
-    )
-endif ( _WIN32 )
+if( WIN32 )
+    set( PlatformIOSources ${InternalIODir}/TcpSocketEngine_win_p.cpp )
+else()
+    set( PlatformIOSources ${InternalIODir}/TcpSocketEngine_unix_p.cpp )
+endif()
 
 #---------------------------
 # make build-specific list
 #---------------------------
-set ( InternalIOSources 
-        ${CommonIOSources} 
+set( InternalIOSources
+        ${CommonIOSources}
         ${PlatformIOSources} 
 
         PARENT_SCOPE # <-- leave this last
diff --git a/src/api/internal/io/HttpHeader_p.h b/src/api/internal/io/HttpHeader_p.h
index 7a50ff9..6b838ff 100644
--- a/src/api/internal/io/HttpHeader_p.h
+++ b/src/api/internal/io/HttpHeader_p.h
@@ -75,7 +75,7 @@ class HttpRequestHeader : public HttpHeader {
 
     // ctor & dtor
     public:
-        HttpRequestHeader(const std::string& method,      // "GET", "PUT", etc
+        HttpRequestHeader(const std::string& method,      // "GET", "HEAD", ...
                           const std::string& resource,    // filename
                           int majorVersion = 1,           // version info
                           int minorVersion = 1);
diff --git a/src/api/internal/io/RollingBuffer_p.cpp b/src/api/internal/io/RollingBuffer_p.cpp
index 10e7627..c712b57 100644
--- a/src/api/internal/io/RollingBuffer_p.cpp
+++ b/src/api/internal/io/RollingBuffer_p.cpp
@@ -237,7 +237,7 @@ size_t RollingBuffer::ReadLine(char* dest, size_t max) {
         bytesReadSoFar += bytesToRead;
         Free(bytesToRead);
 
-        if ( !((bytesReadSoFar < index+1)&&(bytesReadSoFar < max-1)) )
+        if ( !((bytesReadSoFar < index+1) && (bytesReadSoFar < max-1)) )
             finished = true;
     }
 
@@ -274,7 +274,7 @@ char* RollingBuffer::Reserve(size_t n) {
     if ( (m_tail + n) <= m_data.at(m_tailBufferIndex).Size() ) {
 
         // fetch write pointer at current 'tail', increment tail by @n & return
-        char* ptr = m_data[m_tailBufferIndex].Data() + m_tail;
+        char* ptr = m_data[m_tailBufferIndex].Data(); //+ m_tail;
         m_tail += n;
         return ptr;
     }
@@ -286,7 +286,7 @@ char* RollingBuffer::Reserve(size_t n) {
         m_data[m_tailBufferIndex].Resize(m_tail + n);
 
         // fetch write pointer at current 'tail', increment tail by @n & return
-        char* ptr = m_data[m_tailBufferIndex].Data() + m_tail;
+        char* ptr = m_data[m_tailBufferIndex].Data(); //+ m_tail;
         m_tail += n;
         return ptr;
     }
diff --git a/src/api/internal/io/TcpSocket_p.cpp b/src/api/internal/io/TcpSocket_p.cpp
index 1a5bd86..d390932 100644
--- a/src/api/internal/io/TcpSocket_p.cpp
+++ b/src/api/internal/io/TcpSocket_p.cpp
@@ -27,7 +27,7 @@ namespace BamTools {
 namespace Internal {
 
 // constants
-static const size_t DEFAULT_BUFFER_SIZE = 0x4000;
+static const size_t DEFAULT_BUFFER_SIZE = 0x10000;
 
 } // namespace Internal
 } // namespace BamTools
@@ -43,7 +43,7 @@ TcpSocket::TcpSocket(void)
     , m_engine(0)
     , m_cachedSocketDescriptor(-1)
     , m_readBuffer(DEFAULT_BUFFER_SIZE)
-    , m_error(TcpSocket::UnknownSocketError)
+    , m_error(TcpSocket::NoError)
     , m_state(TcpSocket::UnconnectedState)
 { }
 
@@ -79,7 +79,7 @@ bool TcpSocket::ConnectImpl(const HostInfo& hostInfo,
     m_hostName   = hostInfo.HostName();
     m_mode       = mode;
     m_state      = TcpSocket::UnconnectedState;
-    m_error      = TcpSocket::UnknownSocketError;
+    m_error      = TcpSocket::NoError;
 //    m_localPort  = 0;
     m_remotePort = 0;
 //    m_localAddress.Clear();
diff --git a/src/api/internal/io/TcpSocket_p.h b/src/api/internal/io/TcpSocket_p.h
index a25a11e..2ad2dee 100644
--- a/src/api/internal/io/TcpSocket_p.h
+++ b/src/api/internal/io/TcpSocket_p.h
@@ -28,13 +28,15 @@
 namespace BamTools {
 namespace Internal {
 
+class BamHttp;
 class TcpSocketEngine;
 
 class TcpSocket {
 
     // enums
     public:
-        enum SocketError { UnknownSocketError     = -1
+        enum SocketError { NoError                = -2
+                         , UnknownSocketError     = -1
                          , ConnectionRefusedError = 0
                          , RemoteHostClosedError
                          , HostNotFoundError
@@ -116,6 +118,8 @@ class TcpSocket {
         TcpSocket::SocketError m_error;
         TcpSocket::SocketState m_state;
         std::string m_errorString;
+
+        friend class BamHttp;
 };
 
 } // namespace Internal
diff --git a/src/api/internal/sam/CMakeLists.txt b/src/api/internal/sam/CMakeLists.txt
index 4b2bce2..2f303bd 100644
--- a/src/api/internal/sam/CMakeLists.txt
+++ b/src/api/internal/sam/CMakeLists.txt
@@ -5,9 +5,9 @@
 # src/api/internal/sam
 # ==========================
 
-set ( InternalSamDir "${InternalDir}/sam" )
+set( InternalSamDir "${InternalDir}/sam" )
 
-set ( InternalSamSources
+set( InternalSamSources
         ${InternalSamDir}/SamFormatParser_p.cpp
         ${InternalSamDir}/SamFormatPrinter_p.cpp
         ${InternalSamDir}/SamHeaderValidator_p.cpp
diff --git a/src/api/internal/utils/CMakeLists.txt b/src/api/internal/utils/CMakeLists.txt
index 38a6957..4b1e2c2 100644
--- a/src/api/internal/utils/CMakeLists.txt
+++ b/src/api/internal/utils/CMakeLists.txt
@@ -5,9 +5,9 @@
 # src/api/internal/utils
 # ==========================
 
-set ( InternalUtilsDir "${InternalDir}/utils" )
+set( InternalUtilsDir "${InternalDir}/utils" )
 
-set ( InternalUtilsSources
+set( InternalUtilsSources
         ${InternalUtilsDir}/BamException_p.cpp
 
         PARENT_SCOPE # <-- leave this last
diff --git a/src/toolkit/CMakeLists.txt b/src/toolkit/CMakeLists.txt
index 1be9efb..33b0735 100644
--- a/src/toolkit/CMakeLists.txt
+++ b/src/toolkit/CMakeLists.txt
@@ -31,7 +31,7 @@ add_executable( bamtools_cmd
 
 # set BamTools application properties
 set_target_properties( bamtools_cmd PROPERTIES
-                       VERSION  2.2.3
+                       VERSION  2.3.0
                        OUTPUT_NAME "bamtools"
                      )
 # make version info available in application
diff --git a/src/toolkit/bamtools_convert.cpp b/src/toolkit/bamtools_convert.cpp
index b0aae07..54820e7 100644
--- a/src/toolkit/bamtools_convert.cpp
+++ b/src/toolkit/bamtools_convert.cpp
@@ -423,7 +423,7 @@ void ConvertTool::ConvertToolPrivate::PrintJson(const BamAlignment& a) {
     }
     
     // write alignment's source BAM file
-    m_out << "\"filename\":" << a.Filename << ",";
+    m_out << "\"filename\":\"" << a.Filename << "\",";
 
     // write tag data
     const char* tagData = a.TagData.c_str();
diff --git a/src/toolkit/bamtools_coverage.cpp b/src/toolkit/bamtools_coverage.cpp
index c0ecd8f..6a4493d 100644
--- a/src/toolkit/bamtools_coverage.cpp
+++ b/src/toolkit/bamtools_coverage.cpp
@@ -2,7 +2,7 @@
 // bamtools_coverage.cpp (c) 2010 Derek Barnett, Erik Garrison
 // Marth Lab, Department of Biology, Boston College
 // ---------------------------------------------------------------------------
-// Last modified: 7 April 2011
+// Last modified: 24 July 2013
 // ---------------------------------------------------------------------------
 // Prints coverage data for a single BAM file 
 // ***************************************************************************
@@ -137,6 +137,7 @@ bool CoverageTool::CoverageToolPrivate::Run(void) {
     BamAlignment al;    
     while ( reader.GetNextAlignment(al) ) 
         pileup.AddAlignment(al);
+    pileup.Flush();
     
     // clean up 
     reader.Close();
diff --git a/src/toolkit/bamtools_filter.cpp b/src/toolkit/bamtools_filter.cpp
index 1189981..2f17242 100644
--- a/src/toolkit/bamtools_filter.cpp
+++ b/src/toolkit/bamtools_filter.cpp
@@ -2,7 +2,7 @@
 // bamtools_filter.cpp (c) 2010 Derek Barnett, Erik Garrison
 // Marth Lab, Department of Biology, Boston College
 // ---------------------------------------------------------------------------
-// Last modified: 10 December 2012
+// Last modified: 3 May 2013
 // ---------------------------------------------------------------------------
 // Filters BAM file(s) according to some user-specified criteria
 // ***************************************************************************
@@ -48,6 +48,7 @@ const string ISPROPERPAIR_PROPERTY        = "isProperPair";
 const string ISREVERSESTRAND_PROPERTY     = "isReverseStrand";
 const string ISSECONDMATE_PROPERTY        = "isSecondMate";
 const string ISSINGLETON_PROPERTY         = "isSingleton";
+const string LENGTH_PROPERTY              = "length";
 const string MAPQUALITY_PROPERTY          = "mapQuality";
 const string MATEPOSITION_PROPERTY        = "matePosition";
 const string MATEREFERENCE_PROPERTY       = "mateReference";
@@ -107,6 +108,7 @@ struct BamAlignmentChecker {
                 const bool isSingleton = al.IsPaired() && al.IsMapped() && !al.IsMateMapped();
                 keepAlignment &= valueFilter.check(isSingleton);
             }
+            else if ( propertyName == LENGTH_PROPERTY )               keepAlignment &= valueFilter.check(al.Length);
             else if ( propertyName == MAPQUALITY_PROPERTY )           keepAlignment &= valueFilter.check(al.MapQuality);
             else if ( propertyName == MATEPOSITION_PROPERTY )         keepAlignment &= ( al.IsPaired() && al.IsMateMapped() && valueFilter.check(al.MateRefID) );
             else if ( propertyName == MATEREFERENCE_PROPERTY ) {
@@ -157,6 +159,7 @@ struct BamAlignmentChecker {
         string tagFilterString = entireTagFilterString.substr(3);
 
         // switch on tag type to set tag query value & parse filter token
+        int8_t   asciiFilterValue,   asciiQueryValue;
         int32_t  intFilterValue,    intQueryValue;
         uint32_t uintFilterValue,   uintQueryValue;
         float    realFilterValue,   realQueryValue;
@@ -167,6 +170,17 @@ struct BamAlignmentChecker {
         bool keepAlignment = false;
         switch (tagType) {
 
+            // ASCII tag type
+            case 'A':
+                if ( al.GetTag(tagName, asciiQueryValue) ) {
+                    if ( FilterEngine<BamAlignmentChecker>::parseToken(tagFilterString, asciiFilterValue, compareType) ) {
+                        tagFilter.Value = asciiFilterValue;
+                        tagFilter.Type  = compareType;
+                        keepAlignment   = tagFilter.check(asciiQueryValue);
+                    }
+                }
+                break;
+
             // signed int tag type
             case 'c' :
             case 's' :
@@ -205,7 +219,7 @@ struct BamAlignmentChecker {
                 break;
 
             // string tag type
-            case 'A':
+
             case 'Z':
             case 'H':
                 if ( al.GetTag(tagName, stringQueryValue) ) {
@@ -257,6 +271,7 @@ struct FilterTool::FilterSettings {
     // flags
     bool HasAlignmentFlagFilter;
     bool HasInsertSizeFilter;
+    bool HasLengthFilter;
     bool HasMapQualityFilter;
     bool HasNameFilter;
     bool HasQueryBasesFilter;
@@ -265,8 +280,9 @@ struct FilterTool::FilterSettings {
     // filters
     string AlignmentFlagFilter;
     string InsertSizeFilter;
-    string NameFilter;
+    string LengthFilter;
     string MapQualityFilter;
+    string NameFilter;
     string QueryBasesFilter;
     string TagFilter;  // support multiple ?
 
@@ -314,6 +330,7 @@ struct FilterTool::FilterSettings {
         , OutputFilename(Options::StandardOut())
         , HasAlignmentFlagFilter(false)
         , HasInsertSizeFilter(false)
+        , HasLengthFilter(false)
         , HasMapQualityFilter(false)
         , HasNameFilter(false)
         , HasQueryBasesFilter(false)
@@ -433,6 +450,7 @@ bool FilterTool::FilterToolPrivate::AddPropertyTokensToFilter(const string& filt
         
         // int32_t conversion
         else if ( propertyName == INSERTSIZE_PROPERTY ||
+                  propertyName == LENGTH_PROPERTY ||
                   propertyName == MATEPOSITION_PROPERTY ||
                   propertyName == POSITION_PROPERTY 
                 ) 
@@ -541,6 +559,7 @@ void FilterTool::FilterToolPrivate::InitProperties(void) {
     m_propertyNames.push_back(ISREVERSESTRAND_PROPERTY);
     m_propertyNames.push_back(ISSECONDMATE_PROPERTY);
     m_propertyNames.push_back(ISSINGLETON_PROPERTY);
+    m_propertyNames.push_back(LENGTH_PROPERTY);
     m_propertyNames.push_back(MAPQUALITY_PROPERTY);
     m_propertyNames.push_back(MATEPOSITION_PROPERTY);
     m_propertyNames.push_back(MATEREFERENCE_PROPERTY);
@@ -579,6 +598,7 @@ bool FilterTool::FilterToolPrivate::ParseCommandLine(void) {
     if ( m_settings->HasIsReverseStrandFilter )     propertyTokens.insert( make_pair(ISREVERSESTRAND_PROPERTY,     m_settings->IsReverseStrandFilter) );
     if ( m_settings->HasIsSecondMateFilter )        propertyTokens.insert( make_pair(ISSECONDMATE_PROPERTY,        m_settings->IsSecondMateFilter) );
     if ( m_settings->HasIsSingletonFilter )         propertyTokens.insert( make_pair(ISSINGLETON_PROPERTY,         m_settings->IsSingletonFilter) );
+    if ( m_settings->HasLengthFilter )              propertyTokens.insert( make_pair(LENGTH_PROPERTY,              m_settings->LengthFilter) );
     if ( m_settings->HasMapQualityFilter )          propertyTokens.insert( make_pair(MAPQUALITY_PROPERTY,          m_settings->MapQualityFilter) );
     if ( m_settings->HasNameFilter )                propertyTokens.insert( make_pair(NAME_PROPERTY,                m_settings->NameFilter) );
     if ( m_settings->HasQueryBasesFilter )          propertyTokens.insert( make_pair(QUERYBASES_PROPERTY,          m_settings->QueryBasesFilter) );
@@ -858,6 +878,7 @@ FilterTool::FilterTool(void)
 
     const string flagDesc    = "keep reads with this *exact* alignment flag (for more detailed queries, see below)";
     const string insertDesc  = "keep reads with insert size that matches pattern";
+    const string lengthDesc  = "keep reads with length that matches pattern";
     const string mapQualDesc = "keep reads with map quality that matches pattern";
     const string nameDesc    = "keep reads with name that matches pattern";
     const string queryDesc   = "keep reads with motif that matches pattern";
@@ -865,6 +886,7 @@ FilterTool::FilterTool(void)
 
     Options::AddValueOption("-alignmentFlag", "int",       flagDesc,    "", m_settings->HasAlignmentFlagFilter, m_settings->AlignmentFlagFilter, FilterOpts);
     Options::AddValueOption("-insertSize",    "int",       insertDesc,  "", m_settings->HasInsertSizeFilter,    m_settings->InsertSizeFilter,    FilterOpts);
+    Options::AddValueOption("-length",        "int",       lengthDesc,  "", m_settings->HasLengthFilter,        m_settings->LengthFilter,        FilterOpts);
     Options::AddValueOption("-mapQuality",    "[0-255]",   mapQualDesc, "", m_settings->HasMapQualityFilter,    m_settings->MapQualityFilter,    FilterOpts);
     Options::AddValueOption("-name",          "string",    nameDesc,    "", m_settings->HasNameFilter,          m_settings->NameFilter,          FilterOpts);
     Options::AddValueOption("-queryBases",    "string",    queryDesc,   "", m_settings->HasQueryBasesFilter,    m_settings->QueryBasesFilter,    FilterOpts);
diff --git a/src/toolkit/bamtools_random.cpp b/src/toolkit/bamtools_random.cpp
index 5282f15..367ac58 100644
--- a/src/toolkit/bamtools_random.cpp
+++ b/src/toolkit/bamtools_random.cpp
@@ -2,7 +2,7 @@
 // bamtools_random.cpp (c) 2010 Derek Barnett, Erik Garrison
 // Marth Lab, Department of Biology, Boston College
 // ---------------------------------------------------------------------------
-// Last modified: 10 December 2012 (DB)
+// Last modified: 24 July 2013 (DB)
 // ---------------------------------------------------------------------------
 // Grab a random subset of alignments (testing tool)
 // ***************************************************************************
@@ -46,6 +46,7 @@ struct RandomTool::RandomSettings {
     bool HasInput;
     bool HasInputFilelist;
     bool HasOutput;
+    bool HasRandomNumberSeed;
     bool HasRegion;
     bool IsForceCompression;
 
@@ -54,6 +55,7 @@ struct RandomTool::RandomSettings {
     vector<string> InputFiles;
     string InputFilelist;
     string OutputFilename;
+    unsigned int RandomNumberSeed;
     string Region;
     
     // constructor
@@ -62,10 +64,12 @@ struct RandomTool::RandomSettings {
         , HasInput(false)
         , HasInputFilelist(false)
         , HasOutput(false)
+        , HasRandomNumberSeed(false)
         , HasRegion(false)
         , IsForceCompression(false)
         , AlignmentCount(RANDOM_MAX_ALIGNMENT_COUNT)
         , OutputFilename(Options::StandardOut())
+        , RandomNumberSeed(0)
     { }  
 };  
 
@@ -165,7 +169,10 @@ bool RandomTool::RandomToolPrivate::Run(void) {
     }
 
     // seed our random number generator
-    srand( time(NULL) );
+    if ( m_settings->HasRandomNumberSeed )
+        srand( m_settings->RandomNumberSeed );
+    else
+        srand( time(NULL) );
 
     // grab random alignments
     BamAlignment al;
@@ -235,14 +242,17 @@ RandomTool::RandomTool(void)
     
     // set up options 
     OptionGroup* IO_Opts = Options::CreateOptionGroup("Input & Output");
-    Options::AddValueOption("-in",  "BAM filename", "the input BAM file",  "", m_settings->HasInput,  m_settings->InputFiles,     IO_Opts, Options::StandardIn());
-    Options::AddValueOption("-list",  "filename", "the input BAM file list, one line per file", "", m_settings->HasInputFilelist,  m_settings->InputFilelist, IO_Opts);
-    Options::AddValueOption("-out", "BAM filename", "the output BAM file", "", m_settings->HasOutput, m_settings->OutputFilename, IO_Opts, Options::StandardOut());
+    Options::AddValueOption("-in",     "BAM filename", "the input BAM file",                         "", m_settings->HasInput,          m_settings->InputFiles,     IO_Opts, Options::StandardIn());
+    Options::AddValueOption("-list",   "filename",     "the input BAM file list, one line per file", "", m_settings->HasInputFilelist,  m_settings->InputFilelist,  IO_Opts);
+    Options::AddValueOption("-out",    "BAM filename", "the output BAM file",                        "", m_settings->HasOutput,         m_settings->OutputFilename, IO_Opts, Options::StandardOut());
+    Options::AddValueOption("-region", "REGION",       "only pull random alignments from within this genomic region. Index file is recommended for better performance, and is used automatically if it exists. See \'bamtools help index\' for more details on creating one", "", m_settings->HasRegion, m_settings->Region, IO_Opts);
     Options::AddOption("-forceCompression", "if results are sent to stdout (like when piping to another tool), default behavior is to leave output uncompressed. Use this flag to override and force compression", m_settings->IsForceCompression, IO_Opts);
-    Options::AddValueOption("-region", "REGION", "only pull random alignments from within this genomic region. Index file is recommended for better performance, and is used automatically if it exists. See \'bamtools help index\' for more details on creating one", "", m_settings->HasRegion, m_settings->Region, IO_Opts);
     
     OptionGroup* SettingsOpts = Options::CreateOptionGroup("Settings");
-    Options::AddValueOption("-n", "count", "number of alignments to grab. Note - no duplicate checking is performed", "", m_settings->HasAlignmentCount, m_settings->AlignmentCount, SettingsOpts, RANDOM_MAX_ALIGNMENT_COUNT);
+    Options::AddValueOption("-n", "count", "number of alignments to grab. Note - no duplicate checking is performed", "",
+                            m_settings->HasAlignmentCount, m_settings->AlignmentCount, SettingsOpts, RANDOM_MAX_ALIGNMENT_COUNT);
+    Options::AddValueOption("-seed", "unsigned integer", "random number generator seed (for repeatable results). Current time is used if no seed value is provided.", "",
+                            m_settings->HasRandomNumberSeed, m_settings->RandomNumberSeed, SettingsOpts);
 }
 
 RandomTool::~RandomTool(void) { 
diff --git a/src/toolkit/bamtools_resolve.cpp b/src/toolkit/bamtools_resolve.cpp
index cb42f5b..9e5fb84 100644
--- a/src/toolkit/bamtools_resolve.cpp
+++ b/src/toolkit/bamtools_resolve.cpp
@@ -2,7 +2,7 @@
 // bamtools_resolve.cpp (c) 2011
 // Marth Lab, Department of Biology, Boston College
 // ---------------------------------------------------------------------------
-// Last modified: 14 October 2011
+// Last modified: 24 July 2013 (DB)
 // ---------------------------------------------------------------------------
 // Resolves paired-end reads (marking the IsProperPair flag as needed).
 // ***************************************************************************
@@ -73,6 +73,20 @@ static const string OPTION_FORCEMARKREADGROUPS  = "ForceMarkReadGroups";
 static const string RG_FIELD_DESCRIPTION =
     "#<name> <medianFL> <minFL> <maxFL> <topModelID> <nextTopModelID> <isAmbiguous?>";
 
+static const string MODEL_DESCRIPTION =
+    "# ------------- Model Types Description ---------------\n"
+    "#\n"
+    "#   ID     Position              Orientation           \n"
+    "#    1   mate1 < mate2   mate1:forward, mate2:forward  \n"
+    "#    2   mate1 < mate2   mate1:forward, mate2:reverse  \n"
+    "#    3   mate1 < mate2   mate1:reverse, mate2:forward  \n"
+    "#    4   mate1 < mate2   mate1:reverse, mate2:reverse  \n"
+    "#    5   mate2 < mate1   mate2:forward, mate1:forward  \n"
+    "#    6   mate2 < mate1   mate2:forward, mate1:reverse  \n"
+    "#    7   mate2 < mate1   mate2:reverse, mate1:forward  \n"
+    "#    8   mate2 < mate1   mate2:reverse, mate1:reverse  \n"
+    "# -----------------------------------------------------\n";
+
 // --------------------------------------------------------------------------
 // unique readname file constants
 // --------------------------------------------------------------------------
@@ -731,9 +745,13 @@ void ResolveTool::StatsFileWriter::WriteHeader(void) {
                   << BAMTOOLS_VERSION_BUILD;
 
     // # bamtools resolve (vX.Y.Z)
+    // #
+    // # MODEL DESCRIPTION - see above for actual text
     // \n
 
     m_stream << COMMENT_CHAR << " bamtools resolve (" << versionStream.str() << ")" << endl
+             << COMMENT_CHAR << endl
+             << MODEL_DESCRIPTION
              << endl;
 }
 
diff --git a/src/toolkit/bamtools_split.cpp b/src/toolkit/bamtools_split.cpp
index e6602a9..6425e95 100644
--- a/src/toolkit/bamtools_split.cpp
+++ b/src/toolkit/bamtools_split.cpp
@@ -2,7 +2,7 @@
 // bamtools_split.cpp (c) 2010 Derek Barnett, Erik Garrison
 // Marth Lab, Department of Biology, Boston College
 // ---------------------------------------------------------------------------
-// Last modified: 8 December 2011 (DB)
+// Last modified: 24 July 2013 (DB)
 // ---------------------------------------------------------------------------
 // Splits a BAM file on user-specified property, creating a new BAM output
 // file for each value found
@@ -33,6 +33,7 @@ static const string SPLIT_UNMAPPED_TOKEN  = ".UNMAPPED";
 static const string SPLIT_PAIRED_TOKEN    = ".PAIRED_END";
 static const string SPLIT_SINGLE_TOKEN    = ".SINGLE_END";
 static const string SPLIT_REFERENCE_TOKEN = ".REF_";
+static const string SPLIT_TAG_TOKEN       = ".TAG_";
 
 string GetTimestampString(void) {
 
@@ -70,6 +71,7 @@ struct SplitTool::SplitSettings {
     bool HasInputFilename;
     bool HasCustomOutputStub;
     bool HasCustomRefPrefix;
+    bool HasCustomTagPrefix;
     bool IsSplittingMapped;
     bool IsSplittingPaired;
     bool IsSplittingReference;
@@ -78,6 +80,7 @@ struct SplitTool::SplitSettings {
     // string args
     string CustomOutputStub;
     string CustomRefPrefix;
+    string CustomTagPrefix;
     string InputFilename;
     string TagToSplit;
     
@@ -86,12 +89,14 @@ struct SplitTool::SplitSettings {
         : HasInputFilename(false)
         , HasCustomOutputStub(false)
         , HasCustomRefPrefix(false)
+        , HasCustomTagPrefix(false)
         , IsSplittingMapped(false)
         , IsSplittingPaired(false)
         , IsSplittingReference(false)
         , IsSplittingTag(false)
         , CustomOutputStub("")
         , CustomRefPrefix("")
+        , CustomTagPrefix("")
         , InputFilename(Options::StandardIn())
         , TagToSplit("")
     { } 
@@ -454,6 +459,16 @@ bool SplitTool::SplitToolPrivate::SplitTagImpl(BamAlignment& al) {
     WriterMap outputFiles;
     WriterMapIterator writerIter;
 
+    // determine tag prefix
+    string tagPrefix = SPLIT_TAG_TOKEN;
+    if ( m_settings->HasCustomTagPrefix )
+        tagPrefix = m_settings->CustomTagPrefix;
+
+    // make sure prefix starts with '.'
+    const size_t dotFound = tagPrefix.find('.');
+    if ( dotFound != 0 )
+        tagPrefix = string(".") + tagPrefix;
+
     // local variables
     const string tag = m_settings->TagToSplit;
     BamWriter* writer;
@@ -464,7 +479,7 @@ bool SplitTool::SplitToolPrivate::SplitTagImpl(BamAlignment& al) {
     if ( al.GetTag(tag, currentValue) ) {
       
         // open new BamWriter, save first alignment
-        outputFilenameStream << m_outputFilenameStub << ".TAG_" << tag << "_" << currentValue << ".bam";
+        outputFilenameStream << m_outputFilenameStub << tagPrefix << tag << "_" << currentValue << ".bam";
         writer = new BamWriter;
         if ( !writer->Open(outputFilenameStream.str(), m_header, m_references) ) {
             cerr << "bamtools split ERROR: could not open " << outputFilenameStream.str()
@@ -493,7 +508,7 @@ bool SplitTool::SplitToolPrivate::SplitTagImpl(BamAlignment& al) {
         if ( writerIter == outputFiles.end() ) {
         
             // open new BamWriter
-            outputFilenameStream << m_outputFilenameStub << ".TAG_" << tag << "_" << currentValue << ".bam";
+            outputFilenameStream << m_outputFilenameStub << tagPrefix << tag << "_" << currentValue << ".bam";
             writer = new BamWriter;
             if ( !writer->Open(outputFilenameStream.str(), m_header, m_references) ) {
                 cerr << "bamtool split ERROR: could not open " << outputFilenameStream.str()
@@ -542,6 +557,8 @@ SplitTool::SplitTool(void)
     Options::AddValueOption("-in",   "BAM filename",  "the input BAM file",  "", m_settings->HasInputFilename,  m_settings->InputFilename,  IO_Opts, Options::StandardIn());
     Options::AddValueOption("-refPrefix", "string", "custom prefix for splitting by references. Currently files end with REF_<refName>.bam. This option allows you to replace \"REF_\" with a prefix of your choosing.", "",
                             m_settings->HasCustomRefPrefix, m_settings->CustomRefPrefix, IO_Opts);
+    Options::AddValueOption("-tagPrefix", "string", "custom prefix for splitting by tags. Current files end with TAG_<tagname>_<tagvalue>.bam. This option allows you to replace \"TAG_\" with a prefix of your choosing.", "",
+                            m_settings->HasCustomTagPrefix, m_settings->CustomTagPrefix, IO_Opts);
     Options::AddValueOption("-stub", "filename stub", "prefix stub for output BAM files (default behavior is to use input filename, without .bam extension, as stub). If input is stdin and no stub provided, a timestamp is generated as the stub.", "",
                             m_settings->HasCustomOutputStub, m_settings->CustomOutputStub, IO_Opts);
     
diff --git a/src/utils/CMakeLists.txt b/src/utils/CMakeLists.txt
index 2d91ca3..1c33f4b 100644
--- a/src/utils/CMakeLists.txt
+++ b/src/utils/CMakeLists.txt
@@ -13,7 +13,7 @@ add_definitions( -DBAMTOOLS_UTILS_LIBRARY ) # (for proper exporting of library s
 add_definitions( -fPIC ) # (attempt to force PIC compiling on CentOS, not being set on shared libs by CMake)
 
 # create BamTools utils library
-add_library( BamTools-utils SHARED
+add_library( BamTools-utils STATIC
              bamtools_fasta.cpp
              bamtools_options.cpp
              bamtools_pileup_engine.cpp
@@ -25,6 +25,6 @@ target_link_libraries( BamTools-utils BamTools )
 
 # set BamTools library properties
 set_target_properties( BamTools-utils PROPERTIES
-                       SOVERSION   2.2.0
                        OUTPUT_NAME bamtools-utils
+                       PREFIX "lib"
                      )
diff --git a/src/utils/bamtools_filter_engine.h b/src/utils/bamtools_filter_engine.h
index 2ece5e7..9fb2f59 100644
--- a/src/utils/bamtools_filter_engine.h
+++ b/src/utils/bamtools_filter_engine.h
@@ -2,7 +2,7 @@
 // bamtools_filter_engine.h (c) 2010 Derek Barnett, Erik Garrison
 // Marth Lab, Department of Biology, Boston College
 // ---------------------------------------------------------------------------
-// Last modified: 10 October 2011
+// Last modified: 3 May 2013
 // ---------------------------------------------------------------------------
 // Provides a generic filter engine based on filter-sets of properties,
 // with possible "rules" (compound logical expressions) to create more complex
@@ -294,7 +294,6 @@ bool FilterEngine<FilterChecker>::evaluateFilterRules(const T& query) {
     
     std::stack<bool> resultStack;
     FilterMap::const_iterator filterIter;
-    FilterMap::const_iterator filterEnd  = m_filters.end();
     std::queue<std::string> ruleQueueCopy = m_ruleQueue;
     while ( !ruleQueueCopy.empty() ) {
         const std::string& token = ruleQueueCopy.front();
@@ -325,7 +324,7 @@ bool FilterEngine<FilterChecker>::evaluateFilterRules(const T& query) {
         else {
             // look up PropertyFilter that matches this token 
             filterIter = m_filters.find(token);
-            BAMTOOLS_ASSERT_MESSAGE( (filterIter != filterEnd), "Filter mentioned in rule, not found in FilterEngine" );
+            BAMTOOLS_ASSERT_MESSAGE( (filterIter != m_filters.end() ), "Filter mentioned in rule, not found in FilterEngine" );
             const PropertyFilter& filter = (*filterIter).second;
             bool result = m_checker.check(filter, query);
             resultStack.push( result );

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/bamtools.git



More information about the debian-med-commit mailing list