readfile.cc #1

  • //
  • guest/
  • dannyz_snps/
  • p4/
  • 2016-1/
  • sys/
  • readfile.cc
  • View
  • Commits
  • Open Download .zip Download (5 KB)
/*
 * Copyright 1995, 1996 Perforce Software.  All rights reserved.
 *
 * This file is part of the Library RCS.  See rcstest.c.
 */

/*
 * readfile.cc - RCS file input routines:
 *
 * History:
 *	2-18-97 (seiwald) - translated to C++.
 */

# define NEED_FILE
# define NEED_FCNTL
# define NEED_TYPES
# define NEED_MMAP

# include <stdhdrs.h>
# include <strbuf.h>
# include <error.h>
# include <debug.h>
# include <tunable.h>
# include <filesys.h>

# include "readfile.h"

/*
 * ReadFile standard implementation (using read/write)
 */

ReadFile::ReadFile()
{
	fp = 0;
	mapped = 0;
	maddr = (unsigned char *)-1;
	mlen = 0;
	mptr = mend = 0;
	size = 0;
	offset = 0;
}

ReadFile::~ReadFile()
{
	Close();
}

void
ReadFile::Open( FileSys *f, Error *e )
{
	/* We open.  ReadFile::Close() will close. */

	this->fp = f;

	f->Open( FOM_READ, e );

	if( e->Test() )
	    return;

	// find size

	size = f->GetSize();

# ifdef HAVE_MMAP

	/* Try to mmap. */
	/* On Solaris (at least), you can't mmap a zero length file. */

	int fd = fp->GetFd();

	if( fd > 0 
	    && size > 0
	    && size <= p4tunable.Get( P4TUNE_FILESYS_MAXMAP ) )
	{
	    mlen = offset = size;

	    maddr = (unsigned char *)mmap( 
		    (caddr_t)0, 
		    size,
		    PROT_READ,
		    MAP_PRIVATE,
		    fd,
		    (off_t)0 );

	    mapped = maddr != (unsigned char *)-1;
	}

# endif

	/* Without mmap, we seek/read as needed */

	if( !mapped )
	{
	    offset = 0;	
	    mlen = FileSys::BufferSize();
	    maddr = new unsigned char[ mlen ];
	}

	/* maddr ... mptr ... mend */

	mptr = maddr;
	mend = mptr + offset;
}

void
ReadFile::Close()
{
	if( !mapped && maddr != (unsigned char *)-1 )
	    delete []maddr;

# ifdef HAVE_MMAP
	if( mapped && maddr != (unsigned char *)-1 )
	    munmap( (caddr_t)maddr, mlen );
# endif

	if( fp )
	    fp->Close( e );

	maddr = (unsigned char *)-1;
	mapped = 0;
	fp = 0;
}

int
ReadFile::Read()
{
	// either mmaped, or all read

	if( offset >= size )
	    return 0;

	int n = fp->Read( (char*)maddr, mlen, e );

	if( e->Test() )
	{
	    // say what? file got short?
	    size = offset;
	    n = 0;
	}

	mptr = maddr;
	mend = mptr + n;
	offset += n;

	/* return if more */

	return n;
}

void	
ReadFile::Seek( offL_t o )
{
	offL_t l = offset - o;

	// Either mmapped or in buffer
	// Else actually seek underlying file.

	if( l >= 0 &&  l <= mend - maddr )
	{
	    mptr = mend - l;
	}
	else
	{
	    Error e;

	    fp->Seek( o, &e );
	    mend = mptr = maddr;
	    offset = o;
	}
}

offL_t
ReadFile::Memcmp( ReadFile *other, offL_t length ) 
{
	int l1, l2;

	while( length && ( l1 = InMem() ) && ( l2 = other->InMem() ) )
	{
	    if( l1 > length )
		l1 = length;
	    if( l1 > l2 )
		l1 = l2;

	    if( int x = memcmp( mptr, other->mptr, l1 ) )
		return x;

	    mptr += l1;
	    other->mptr += l1;
	    length -= l1;
	}

	return 0;
}

offL_t
ReadFile::Memcpy( char *buf, offL_t length )
{
	int l;
	offL_t olen = length;

	while( length && ( l = InMem() ) )
	{
	    if( l > length )
		l = length;
		
	    (void)memcpy( buf, mptr, l );

	    buf += l;
	    mptr += l;
	    length -= l;
	}

	return olen - length;
}

offL_t
ReadFile::Memccpy( char *buf, int c, offL_t length )
{
	int l;
	offL_t olen = length;

	while( length && ( l = InMem() ) )
	{
	    if( l > length )
		l = length;
		
	    char *b;

	    if( b = (char *)memccpy( buf, mptr, c, l ) )
		l = b - buf;

	    buf += l;
	    mptr += l;
	    length -= l;

	    if( b )
		break;
	}

	return olen - length;
}

offL_t
ReadFile::Memchr( int c, offL_t length )
{
	// Memchr( c, -1 ) means to Eof()

	if( length == -1 )
	    length = Size() - Tell();

	int l;
	offL_t olen = length;

	while( length && ( l = InMem() ) )
	{
	    if( l > length )
		l = length;
		
	    unsigned char *p;

	    if( p = (unsigned char *)memchr( mptr, c, l ) )
		l = p - mptr;

	    mptr += l;
	    length -= l;

	    if( p )
		break;
	}

	return olen - length;
}

/*
 * ReadFile::Textcpy() - Memcpy w/ line ending translation
 *
 * Textcpy() is written entirely in calls to Memcpy() and Memccpy().
 */

offL_t
ReadFile::Textcpy( char *dst, offL_t dstlen, offL_t srclen, LineType type )
{
	switch( type )
	{
	default:
	case LineTypeRaw:
	    {
		// Just Memcpy the minimum.

		return Memcpy( dst, dstlen < srclen ? dstlen : srclen );
	    }

	case LineTypeCr:
	    {
		// Memcpy the minimum, translating \r to \n

		char *odst = dst;

		if( dstlen > srclen ) dstlen = srclen;

		while( dstlen )
		{
		    offL_t l = Memccpy( dst, '\r', dstlen );
		    if( !l ) break;
		    dst += l, dstlen -= l;
		    if( dst[-1] == '\r' ) dst[-1] = '\n';
		}

		return dst - odst;
	    }

	case LineTypeCrLf:
	case LineTypeLfcrlf:
	    {
		// Memcpy, stopping at each \r and, if it is followed
		// by a \n, translating the \r to \n and dropping the
		// \n from the source.  This can cause dstlen and srclen
		// to move out of step.  If we hit a \r at the exact end
		// of srclen, and a \n follows, srclen reaches -1.
		// LFCRLF reads CRLF.

		char *odst = dst;

		while( dstlen && srclen > 0 )
		{
		    offL_t l;
		    l = Memccpy( dst, '\r', dstlen < srclen ? dstlen : srclen);
		    if( !l ) break;
		    dst += l, dstlen -= l, srclen -= l;

		    if( dst[-1] == '\r' && !Eof() && Char() == '\n' )
			Next(), dst[-1] = '\n', --srclen;
		}

		return dst - odst;
	    }
	}
}
# Change User Description Committed
#1 21443 dannyz_snps "Forking branch 2016-1 of perforce_software-p4 to dannyz_snps-p4."
//guest/perforce_software/p4/2016-1/sys/readfile.cc
#1 19472 Liz Lam Initial add of the 2016.1 p4/p4api source code.