/* * 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; } } }