// -*-C++-*- 

/*  src/platform/ANSICPlatform.cpp  */

/*
 * Author: Philogelos A. <Philogelos@yahoo.com>
 * Maintainer: Philogelos A.
 * Keywords: C++, library, containers
 *
 * Copyright (C) 1998 Philogelos A.
 *
 * This file is part of Quercus Robusta.
 *
 * Quercus Robusta is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Library General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this software; see the file COPYING.LIB.  If not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 *
 */



/* $Id$ */
#if !defined(_INLINE)
static char cvsid[] = "@(#)$Id$";
static char debugFileId[] = __FILE__;
#endif

#include <sys/types.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <stdarg.h>

#if defined( USE_BOEHM_GC )
#include <gc.h>
#endif

#if defined( __GNUC__ )
extern "C" 
int vsnprintf( char *str, size_t n, const char *format, va_list ap );
#endif

extern int errno;

#include "platform/ANSICPlatform.hpp"
#include "exceptions/OutOfMemory.hpp"
#include "String.hpp"
#include "Debug.hpp"

#include "exceptions/InvalidArgument.hpp"

#if defined( USE_BOEHM_GC ) && ( defined( MEMORY_LEAK_TEST ) || defined( USE_ALLOC_CHAIN ) )
#warning "There is no much sense in using GC along with MEMORY_LEAK_TEST or USE_ALLOC_CHAIN"
#endif

extern "C"
{
  int sprintf( char *s, const char * format, /* args */ ...) 
	PRINTF_ALIKE( 2, 3 );
  int fprintf( FILE *strm, const char *format, /* args */ ... ) 
	PRINTF_ALIKE( 2, 3 );

  char  *strcpy( char *dst, const char *src );
  int    strcmp( const char *s1, const char *s2 );
  size_t strlen( const char *s );
  char  *strcat( char *dst, const char *src );
  char  *strchr( const char *s, int c );
  long   strtol( const char *str, char **endptr, int base );

  void *memcpy( void *s1, const void *s2, size_t n );
  void *memset( void *s, int c, size_t n );


#if defined( USE_BOEHM_GC )

  void *GC_malloc( size_t size_in_bytes );
  void GC_free( void *object_addr );

#endif
}


ANSICPlatform::ANSICPlatform()
{
  callsNum = 0;
}

ANSICPlatform::~ANSICPlatform()
{}

void ANSICPlatform::sprintf( char *s, const char * format, /* args */ ... ) 
{
  preC_( format != NULL );
  preC_( s != NULL );

  va_list args;

  va_start( args, format );
  this -> vsprintf( s, format, args );
  va_end(args);
  ++callsNum;
}

void ANSICPlatform::vsprintf( char *s, const char *format, va_list raw )
{
  preC_( format != NULL );
  preC_( s != NULL );

  ::vsprintf( s, format, raw );
  ++callsNum;
}

Index ANSICPlatform::printfLength( const char * format, /* args */ ... )
{
  preC_( format != NULL );

  va_list args;
  Index result;
  
  va_start( args, format );

  result = this -> vprintfLength( format, args );
  va_end(args);
  ++callsNum;
  return result;
}

Index ANSICPlatform::vprintfLength( const char * format, va_list raw )
{
  preC_( format != NULL );
  
  int result;
#if defined( SNPRINTF_RETURNS_ERROR )
  static char *dummyBuf = NIL;
  static long int size = 2;
#else
  char dummyBuf[ 2 ];
#endif

#if defined( SNPRINTF_RETURNS_ERROR )
  if( dummyBuf == NULL )
	{
	  dummyBuf = new char[ size ];
	}
  while( true )
	{
	  result = ::VSNPRINTF( dummyBuf, size, format, raw );
	  if( result == -1 )
		{
		  delete []dummyBuf;
		  size *= 2;
		  dummyBuf = new char[ size ];
		}
	  else
		{
		  break;
		}
	}
#else
  result = ::VSNPRINTF( dummyBuf, 2, format, raw );
#endif
  postC_( result >= 0 );
  return result;
}

void ANSICPlatform::rawErrorPrintf( const char * format, /* args */ ... ) 
{
  preC_( format != NULL );

  va_list raw;

  va_start( raw, format );
  this -> rawErrorVPrintf( format, raw );
  va_end( raw );
  ++callsNum;
}

void ANSICPlatform::rawErrorVPrintf( const char * format, va_list raw ) 
{
  preC_( format != NULL );

  vfprintf( stderr, format, raw );
  ++callsNum;
}

char  *ANSICPlatform::strcpy( char *dst, const char *src )
{
  preC_( dst != NULL );
  preC_( src != NULL );

  ++callsNum;
  return ::strcpy( dst, src );
}

int    ANSICPlatform::strcmp( const char *s1, const char *s2 )
{
  preC_( s1 != NULL );
  preC_( s2 != NULL );

  ++callsNum;
  return ::strcmp( s1, s2 );
}

Index ANSICPlatform::strlen( const char *s )
{
  preC_( s != NULL );

  ++callsNum;
  return ::strlen( s );
}

char  *ANSICPlatform::strcat( char *dst, const char *src )
{
  preC_( dst != NULL );
  preC_( src != NULL );

  ++callsNum;
  return ::strcat( dst, src );
}

char  *ANSICPlatform::strchr( const char *s, int c )
{
  preC_( s != NULL );

  ++callsNum;
  return ::strchr( s, c );
}

long ANSICPlatform::strtol( const char *str, char **endptr, int base ) THROWS( InvalidArgument * )
{
  preC_( str != NULL );

  long result;

  ++callsNum;
  result = ::strtol( str, endptr, base );
  if( errno == ERANGE )
	{
	  throw new 
		InvalidArgument( "strtol: value is outside the range of representable values", 
						 ( Top * ) nil );
	}
  if( ( errno == EINVAL ) && ( result == 0 ) )
	{
	  throw new 
		InvalidArgument( "strtol: no conversion could be performed", 
						 ( Top * ) nil );
	}
  if( ( endptr != ( char ** ) NULL ) && ( ( ** endptr ) != ( char ) 0 ) )
	{
	  throw new 
		InvalidArgument( "strtol: garbage detected", 
						 ( Top * ) nil );
	}
  return result;
}

int ANSICPlatform::memcmp( void *s1, const void *s2, Index n )
{
  preC_( s1 != NULL );
  preC_( s2 != NULL );

  ++callsNum;
  return ::memcmp( s1, s2, n );
}

void *ANSICPlatform::memchr( const void *s, int c, Index n )
{
  preC_( s != NULL );
  preC_( n >= 0 );

  ++callsNum;
  return ::memchr( s, c, n );
}

void *ANSICPlatform::memcpy( void *s1, const void *s2, Index n )
{
  preC_( s1 != NULL );
  preC_( s2 != NULL );

  ++callsNum;
  return ::memcpy( s1, s2, n );
}

void *ANSICPlatform::memset( void *s, int c, Index n )
{
  preC_( s != NULL );

  ++callsNum;
  return ::memset( s, c, n );
}

void *ANSICPlatform::allocateMemory( Index aSize )
{
  char *arena;

#if defined( USE_BOEHM_GC )
  arena = ( char * ) GC_malloc( aSize );
#else
  arena = ( char * ) malloc( aSize );
#endif
  if( arena == NULL )
	{
	  throw getOutOfMemory();
	}
  this -> memset( arena, 0, aSize );
  return arena;
}

void  ANSICPlatform::deallocateMemory( void *aPointer )
{
  if( aPointer != NIL )
	{
#if defined( USE_BOEHM_GC )
	  GC_free( aPointer );
#else
	  ::free( aPointer );
#endif
	}
}

void *ANSICPlatform::allocateMemoryBootstrapANSI( Index aSize )
{
  char *arena;

#if defined( USE_BOEHM_GC )
  arena = ( char * ) GC_malloc( aSize );
#else
  arena = ( char * ) malloc( aSize );
#endif
  ::memset( arena, 0, aSize );
  return arena;
}

void  ANSICPlatform::deallocateMemoryBootstrapANSI( void *aPointer )
{
  if( aPointer != NIL )
	{
#if defined( USE_BOEHM_GC )
	  GC_free( aPointer );
#else
	  ::free( aPointer );
#endif
	}
}

boolean ANSICPlatform::equals( const Top *anOther ) const
{
  return( DCAST( anOther, ANSICPlatform ) == this );
}

Top *ANSICPlatform::clone() const
{
  return ( Top * ) this;
}

OutOfMemory *ANSICPlatform::getOutOfMemory()
{
  return outOfMemoryException;
}

OutOfMemory *ANSICPlatform::outOfMemoryException = new OutOfMemory( "malloc in ANSICPlatform::allocateMemory failed", null );

#if defined(_INLINE)
#include "../src/Debug.ipp"
#include "../src/String.ipp"
#endif


/* $Log$ */
