/*
....[@@@..[@@@..............[@.................. MUD++ is a written from
....[@..[@..[@..[@..[@..[@@@@@....[@......[@.... scratch multi-user swords and
....[@..[@..[@..[@..[@..[@..[@..[@@@@@..[@@@@@.. sorcery game written in C++.
....[@......[@..[@..[@..[@..[@....[@......[@.... This server is an ongoing
....[@......[@..[@@@@@..[@@@@@.................. development project. All
................................................ contributions are welcome.
....Copyright(C).1995.Melvin.Smith.............. Enjoy.
------------------------------------------------------------------------------
Melvin Smith (aka Fusion) msmith@falcon.mercer.peachnet.edu
MUD++ development mailing list mudpp-list@spice.com
------------------------------------------------------------------------------
io.cc
*/
// This is a quick hack to get around being dependant on iostream
// Not robust, etc.
// Basic one hour job.
// -Melvin
#include "io.h"
// These are currently in string.cc
const char * itoa( int );
const char * ltoa( unsigned long );
IStream::IStream( const char *fname )
: line(1), ptr(0), cache(0)
{
if( ( fd = ::open( fname, O_RDONLY ) ) < 0 )
{
return;
}
// Get stats on the file (size is what we need)
if( fstat( fd, &stats ) < 0 )
{
return;
}
// Tell kernel to map this device to memory. If your mmap()
// is failing then change the define below and it will skip to
// allocator.
#if(HAVE_MMAP)
if( ( cache = (char *)mmap( 0, stats.st_size + 1, PROT_READ,
MAP_FILE | MAP_PRIVATE,
fd, 0 ) ) == (caddr_t) -1)
#endif
{
// If mmap fails or is not available then we use our own allocation
// We lose performance like this but the class internals
// will still use the whole buffer just like if we mmap()
int tot = 0;
int num;
cache = new char[ stats.st_size + 1 ];
while( tot < stats.st_size )
{
if( ( num = read( fd, (cache + tot), stats.st_size - tot ) ) == -1 )
{
perror( "read" );
exit(0);
}
else if( ( tot += num ) == stats.st_size )
{
break;
}
continue;
}
*( cache + stats.st_size ) = 0;
flags |= STR_NOTMAPPED;
}
::close( fd ); // We dont need it, its all in RAM now.
flags |= STR_OPEN;
ptr = cache;
}
IStream::~IStream()
{
if( cache )
{
// See if the device was ever mapped or did we fall to
// backup with new char[] and read()
if( flags & STR_NOTMAPPED )
{
delete [] cache;
}
else if( ( munmap( cache, stats.st_size ) ) < 0 )
{
perror( "munmap" );
exit(0);
}
}
}
OStream Cout;
OStream::OStream( const char * fname )
: Stream(), ptr( cache ), highwater( cache + CACHE_SIZE )
{
fd = ::open( fname, O_WRONLY | O_CREAT | O_TRUNC, 0777 );
if( fd < 0 )
{
// Add error handling later.
exit(0);
}
flags |= STR_OPEN;
}
OStream::~OStream()
{
flush();
if( fd > 2 )
::close( fd );
}
OStream & OStream::operator << ( const char * x )
{
if( ! x )
return *this;
int len = strlen( x );
if( ( ptr + len ) < highwater )
{
memcpy( ptr, x, len );
ptr += len;
}
else
{
write( fd, cache, (int)( ptr - cache ) );
ptr = cache;
write( fd, x, strlen( x ) );
}
return *this;
}
OStream & OStream::operator << ( char * x )
{
return ( *this << (const char *)x );
}
OStream & OStream::operator << ( int x )
{
const char *p = itoa( x );
int len = strlen( p );
if( ( ptr + len ) < highwater )
{
memcpy( ptr, p, len );
ptr += len;
}
else
{
write( fd, cache, (int)( ptr - cache ) );
ptr = cache;
write( fd, p, len );
}
return *this;
}
OStream & OStream::operator << ( long x )
{
const char *p = ltoa( x );
int len = strlen( p );
if( ( ptr + len ) < highwater )
{
memcpy( ptr, p, len );
ptr += len;
}
else
{
write( fd, cache, (int)( ptr - cache ) );
ptr = cache;
write( fd, p, len );
}
return *this;
}
OStream & OStream::operator << ( unsigned long x )
{
const char *p = ltoa( x );
int len = strlen( p );
if( ( ptr + len ) < highwater )
{
memcpy( ptr, p, len );
ptr += len;
}
else
{
write( fd, cache, (int)( ptr - cache ) );
ptr = cache;
write( fd, p, len );
}
return *this;
}
OStream & OStream::operator << ( char x )
{
if( ptr < highwater )
{
*ptr = x;
ptr++;
}
else
{
// Using iovec may be nice here.
write( fd, cache, CACHE_SIZE );
write( fd, &x, 1 );
ptr = cache;
}
return *this;
}
void OStream::flush()
{
if( ptr > cache )
{
write( fd, cache, (int)( ptr - cache ) );
ptr = cache;
}
}
int OStream::open()
{
return -1;
}
int OStream::open( const char * )
{
return -1;
}
void OStream::close()
{
if( fd >= 0 )
::close( fd );
fd = -1;
}
// IStream class implementation, memory mapped
void IStream::close()
{
if( !cache )
return;
if( ( munmap( cache, stats.st_size ) ) < 0 )
{
perror( "munmap" );
exit(0);
}
cache = ptr = 0;
}
void IStream::putback()
{
if( cache )
if( ptr > cache )
{
ptr--;
if( *ptr == '\n' )
line--;
}
}
char IStream::get( char & ch )
{
if( cache )
{
if( ( ch = *ptr ) )
{
if( *ptr == '\n' )
line++;
return *ptr++;
}
return *ptr; // EOF = 0
}
ch = '\0';
return '\0';
}
char * IStream::getline( char * buf )
{
char *save = buf;
if( cache )
{
while( *ptr )
{
*buf = *ptr;
if( *ptr++ == '\n' )
{
line++;
*buf = '\0';
return save;
}
buf++;
}
*buf = '\0';
return save;
}
*buf = '\0';
return buf;
}