/
mud++0.33/etc/
mud++0.33/etc/guilds/
mud++0.33/help/propert/
mud++0.33/mudC/
mud++0.33/player/
mud++0.33/src/
mud++0.33/src/bcppbuilder/
mud++0.33/src/unix/
mud++0.33/src/vm/
/*
....[@@@..[@@@..............[@.................. 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@hom.net 
MUD++ development mailing list    mudpp-list@mailhost.net
------------------------------------------------------------------------------
ionew.cpp
*/

#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include "io.h"
#include "osdepend.h"

#ifdef HAVE_MMAP
#include <sys/mman.h>
#endif

#ifdef ultrix
// All ULTRIX I know have no prototypes for mmap(), munmap()
// Even so, mmap doesn't work on ULTRIX in my experience.
extern "C"
{
	caddr_t mmap( caddr_t, size_t, int, int, int, off_t );
	int munmap( caddr_t, size_t );
}
#endif

#define CACHE_SIZE 1

#define STR_OPEN 1
#define STR_EOF  2
#define STR_NOTMAPPED 4  // This means mmap() failed and class had to allocate.

#ifndef MAP_FILE
#define MAP_FILE 0  // non BSD systems.
#endif

#ifndef STDOUT_FILENO
#define STDIN_FILENO 0
#define STDOUT_FILENO 1
#endif

OutputFile Cout(STDOUT_FILENO);

int StaticInput::getnum()
		{
	const char * start;	
	skipwhite();

	if ( eof() )
	{
		error("Input::getnum() - EOF hit before data");
	return 0;
	}

	start = ptr;
	if ( !isdigit( *ptr) )
	{
		if ( (*ptr == '-') || (*ptr =='+') )
			ptr++;
		else
		{
			error("Input::getnum() - non-numeric character");
			return 0;
	}
}

	start = ptr;
	while( isdigit( getch() )	)
		;

	if( !eof() )
		putback();
	
	return atoi( start );
}

float StaticInput::getfloat()
{
	const char * start;	
	skipwhite();

	if( eof() )
	{
		error("Input::getfloat() - EOF hit before data");
		return 0;
	}
	
	if( !isdigit(*ptr) && *ptr != '-' && *ptr != '+' )
	{
		error("Input::getfloat() - non-numeric character");
		return 0;
	}

	start = ptr;
	while( isdigit( getch() ) || *(ptr-1) != '.')
		;

	if( !eof() )
		putback();

	return atof( start );
}

unsigned long StaticInput::getlong()
{
	const char * start;	
	skipwhite();

	if ( eof() )
	{
		error("Input::getnum() - EOF hit before data");
		return 0;
	}

	if ( !isdigit( *ptr) && *ptr != '-' && *ptr != '+' )
		{
		error("Input::getlong() - non-numeric character");
		return 0;
	}

	while( isdigit( getch() )	)
		;

	if( !eof() )
		putback();

	return atol( start );
}


char * StaticInput::getword(char * trg)
{
	char * start = trg;
	skipwhite();
	
	if ( eof() )
	{
		error("Input::getword - EOF hit before data");
		return 0;
	}
	if ( (*ptr == '{') || (*ptr == '}') || (*ptr =='#') || (*ptr
		==';'))
		{
		*trg++ = *ptr++;
		*trg = '\0';
		return start;
	}
	
	while ( !eof() && !isspace(*ptr) && *ptr != '{' && *ptr != '}' &&
			*ptr != '#' && *ptr !=';' )
	{
		*trg++ = *ptr++;
}

	*trg = '\0';
	return start;
}

char * StaticInput::getstring(char* trg)
{
	char * start = trg;
	skipwhite();
 
	if( eof() )
	{
		error("Input::getstring - EOF hit before data");
		return 0;
	}

	while ( !eof() && *ptr != TERM_CHAR )
	{
		if ( *ptr !=  '\r' )
		{
			*trg = *ptr;
			if ( *trg == '\n' )
				*(++trg) = '\r';
			trg++;
		}
		ptr++;
	}
	
	if ( !eof() )
		ptr++;

	*trg = '\0';
	return start;
}

char * StaticInput::getCstring(char* trg)
	{
	int count;
	count = strlen( ptr )+1;
	memcpy( trg, ptr, count );
	ptr += count;
	return trg;
	}

char * StaticInput::getline(char* trg)
	{
	char * start = trg;
	skipwhite();
	if ( eof() )
		{
		error("Input::getline - EOF hit before data");
		return 0;
}

	while( !eof() && *ptr != '\n' )
		*trg++ = *ptr++;

	*trg = '\0';
	return start;
	}

char * StaticInput::getsmartline(char * trg)
	{
	char * start = trg;
	skipwhite();
	if ( eof() )
		{
		error("Input::getline - EOF hit before data");
		return 0;
}

again:
	while( !eof() && *ptr != '\n' )
		*trg++ = *ptr++;

	if ( !eof() )
{
		if ( (start != trg) && *(trg-1) == '\\' )
	{
		ptr++;
			if ( *ptr == '\r' )
				ptr++;
			trg--;
			// YESSSS!!!!
			goto again;
	}
	}

	*trg = '\0';
	return trg;

}

void StaticInput::getbitfield( unsigned long * field )
	{
	int fields = getnum();
	for( int i = 0; i < fields; i++ )
		field[i] = getnum();
	}

void * StaticInput::read(void* trg, int siz)
	{
	void * start = trg;
	if ( (highwater - ptr) < siz )
		{
		error("Input::read - requested more data than available");
		return 0;
	}
	memcpy( trg, ptr, siz);
	ptr += siz;
	return start;
}


void StaticInput::error(const char * str)
{
	Cout << getName() << ':' << getLineNo() << ": " << str << endl;
	mudpp_exit(1);
}

void StaticInput::errorf( const char * fmt, ... )
{
	char buf[BUF];
	va_list args;
	va_start( args, fmt );
	vsprintf( buf, fmt, args );
	error(buf);
	va_end(args);
}


void InputFile::open()
{
	int fd;

	if( ( fd = ::open( filename, 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( ( tcache = (char *)mmap( 0, stats.st_size + 1, PROT_READ,
								MAP_FILE | MAP_PRIVATE,
								fd, 0 ) ) == (caddr_t) -1)
#endif /* HAVE_MMAP */
{
		// 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;
#if !defined(WIN32) && !defined(__CYGWIN32__)
		tcache = new char[ stats.st_size + 1 ];
		while( tot < stats.st_size )
		{
			if( ( num = ::read( fd, (tcache + tot), stats.st_size - tot ) ) == -1 )
			{
				perror( "MPPIStream::open:read" );
				mudpp_exit(0);
			} /* if */
			else if( ( tot += num ) == stats.st_size )
				break;

			continue;
		} /* while */
		*( tcache + stats.st_size ) = 0;
#else 
/*
 * WIN32 returns 0 at end of file, and truncates CRLF to LF, returning
 * ONLY the number of LFs which means that the normal looping read
 * will likely never fill properly.
 * The above looping reader is not necessary for WIN32 anyway since
 * it can handle large files with one read call (I hope :).
 * The routine for WIN32 is a little bit longer in that it makes an effort to
 * use the minimal amount of memory for the cache[] given the CRLF 
 * translation.
 */
		char *temp;
		temp = new char[stats.st_size + 1];
		num = ::read( fd, temp, stats.st_size );
		if (num == -1)
		{
			perror( "MPPIStream::open:read");
			mudpp_exit(0);
}
		tcache = new char[num+1];
		memcpy(tcache, temp, num);
		*(  tcache + num ) = 0;
		delete [] temp;
#endif /* WIN32 */
		flags |= STR_NOTMAPPED;
	} /* if ...mmap */

	::close( fd ); // We dont need it, its all in RAM now.
	cache = tcache;
	flags |= STR_OPEN; 
	ptr = cache;
	highwater = cache + stats.st_size;
	return;
}

void InputFile::close()
{
	if( !cache )
		return;

	if( flags & STR_NOTMAPPED )
		delete [] tcache;
#if(HAVE_MMAP)
	else if( ( munmap( tcache, stats.st_size ) ) < 0 )
	{
		Cout << "Unmapped file " << getName() << " of size " << size() << " or "<< stats.st_size<<endl;
		perror( "MPPIStream::close:munmap" );
		mudpp_exit(0);
	}
#endif /* HAVE_MMAP */

	cache = NULL;
	ptr = NULL;
	tcache = NULL;
}


void Output::write( const void * src, size_t len )
{
	if ( !len )
		return;

	if( ( ptr + len ) < highwater )
		{
		memcpy( ptr, src, len );
		ptr += len;
}
	else
{
		flush();
		if ( (ptr + len) < highwater )
	{
			memcpy(ptr,src,len);
			ptr += len;
		}
		else
		{
			largewrite(src,len);
		}
	}
	return;
}

void Output::putbitfield( const unsigned long * field, int num )
{
	*this << num;

	for( int i = 0; i < num; i++ )
			{
		*this << ' ';
		*this << field[i]; 
			}
		}


Output & Output::operator << ( const char * x )
	{
	if( ! x )
		Error::dump("Null pointer passed to Output::operator << char *");
	int len = strlen( x );
	write(x,len);
	return *this;
}


Output & Output::operator << ( int x )
	{
	const char *p = itoa( x );
	int len = strlen( p );
	write(p,len);
	return *this;
}


Output & Output::operator << ( long x )
{
	const char *p = ltoa( x );
	int len = strlen( p );
	write(p,len);
	return *this;
}


Output & Output::operator << ( unsigned long x )
{
	const char *p = ultoa( x );
	int len = strlen( p );
	write(p,len);
	return *this;
}

 
Output & Output::operator << ( short int x)
	{
	const char *p = itoa( (int) x );
	int len = strlen( p );
	write(p,len);
	return *this;
	}


Output & Output::operator << ( unsigned short int x )
	{
	const char *p = itoa( (int) x );
	int len = strlen( p );
	write(p,len);
	return *this;
	} 


Output & Output::operator << ( char x )
		{
	if( ptr >= highwater )
		flush();

	*ptr = x;
	ptr++;
	return *this;
}


void OutputBuffer::flush()
{ 
	if ( ptr == buf )
		return;
	int len = ptr - buf;
	if ( len >= (size - usedsize) )
	{
		memcpy( data+usedsize, buf, len);
		usedsize += len;
	}
	else
	{
		size <<= 1;
		size += len;
		char * ndata = new char[size];
		memcpy( ndata, data, usedsize );
		memcpy( ndata+ usedsize, buf, len );
		usedsize += len;
		delete [] data;
		data = ndata;
	}

	ptr = buf;
}

void OutputBuffer::largewrite( const void * x, size_t len )
{ 
	if ( ptr != buf )
		flush();

	if ( len >= (unsigned int) (size - usedsize) )
	{
		memcpy( data+usedsize, x, len);
		usedsize += len;
	}
	else
	{
		size <<= 1;
		size += len;
		char * ndata = new char[size];
		memcpy( ndata, data, usedsize );
		memcpy( ndata+ usedsize, x, len );
		usedsize += len;
		delete [] data;
		data = ndata;
	}
}

const char * OutputBuffer::getDataAsString()
{
	*this << '\0';
	flush();
	usedsize--;	// \0 is needed only for a moment
	return data;
}

void OutputFile::open(int mode)
{ 
	if ( mode == OUTFILE_WRITE )
		fd = ::open( filename, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_FILE_MODE );
	else
		fd = ::open( filename, O_WRONLY | O_CREAT | O_APPEND, DEFAULT_FILE_MODE );

	if ( fd == -1 )
	{
		active = false;
		perror("Cannot open file for writing");
		mudpp_exit(1);
	}
	active = true;
}

void OutputFile::close()
{
	if ( fd == -1 )
		return;
	if ( !systemfd )
		::close(fd);
	active = false;
	}


void OutputFile::flush()
{
	if ( ptr == buf )
		return;
	::write( fd, buf, ptr - buf );
	ptr = buf;
}

void OutputFile::largewrite( const void *x, size_t len )
{
	if ( ptr != buf )
		::write(fd, buf, ptr - buf );
	::write(fd, x, len );
	ptr = buf;
}