/*  MSS -- Memory Supervision System version 1.3
 *  Copyright (C) 1998  Juan Jesus Alcolea Picazo and Peter Palotas
 *  Copyright (C) 2002, 2005  Laurynas Biveinis
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program 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 General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *  You can contact the authors of this library at the following e-mail
 *  addreses. For more information, look in the documentation that came
 *  with this library.
 *
 *  Juan Jesus Alcolea Picazo, a920101@zipi.fi.upm.es
 *  Peter Palotas, blizzar@hem1.passagen.se
 *  Laurynas Biveinis, lauras@softhome.net
 *
 */

#if !defined __mss_h__ || defined __MSS_H_REINCLUDE

/* The section below should be included only once, even if we are
 * reincluding after <no_mss.h> --LB
 */
#if !defined __mss_h__
#define __mss_h__

/* If there is no way to get current function name, use this */
#define MSS_UNKNOWN_FUNC "unknown function"

/* Predefined variable to get current function name */
#define __PRETTY_FUNCTION__ __PRETTY_FUNCTION__

/* C++ support configuration */
#define MSS_EXCEPTION_SUPPORT
#define MSS_HAVE_HEADER_NEW
#define MSS_BAD_ALLOC std::bad_alloc
#define MSS_NOTHROW_T std::nothrow_t

#define	MSS_DISABLE_THREADING_FUNC
#define MSS_ENABLE_THREADING_FUNC

/**************************************************************************/
/*              DO NOT CHANGE ANYTHING BELOW THIS LINE                    */
/**************************************************************************/

#include <stdlib.h>
#include <string.h>

#define MSS_VERSION "1.3"

#ifdef __cplusplus
extern "C" {
#endif /* !__cplusplus */

/****************/
/*    USER.C    */
/****************/
void mss_enter_scope(const char *filename, const char *function, unsigned long line);
void mss_leave_scope(const char *filename, const char *function, unsigned long line);

void mss_unregister_constant_block(void *ptr, const char *filename, const char *function, unsigned long line);
void mss_register_constant_block(void *ptr, const char *filename, const char *function, unsigned long line);

unsigned int mss_currently_used_mem(void);
unsigned int mss_maximum_used_nem(void);
unsigned int mss_number_of_allocated_blocks(void);

void mss_set_block_label(void *ptr, const char *message, const char *filename, const char *function, unsigned long line);
void mss_dump_block(void *ptr, const char *file, const char *filename, const char *function, unsigned long line);

/****************/
/*   ALLOC.C    */
/****************/
enum { MSS_BY_NEW = 0, 
       MSS_BY_NEW_ARRAY,
       MSS_BY_DELETE,
       MSS_BY_DELETE_ARRAY,
       MSS_BY_MALLOC,
       MSS_BY_REALLOC,
       MSS_BY_CALLOC,
       MSS_BY_FREE,
       MSS_BY_XMALLOC,
       MSS_BY_XREALLOC,
       MSS_BY_XFREE,
       MSS_BY_CFREE,
       MSS_BY_STRDUP,
       MSS_LAST_METHOD = MSS_BY_STRDUP,
       MSS_NO_METHOD = MSS_LAST_METHOD + 1
     };



void *mss_malloc(size_t s, int called_by, const char *filename, const char *function, unsigned long line);
char *mss_strdup(const char *source, const char *filename, const char *function, unsigned long line);
void *mss_realloc(void *ptr, size_t size, int called_by, const char *filename, const char *function, unsigned long line);
void mss_free(void *ptr, int called_by, const char *filename, const char *function, unsigned long line);

/****************/
/*   CHECK.C    */
/****************/
void mss_check_pointer_validity(void *ptr, const char *filename, const char *function, unsigned long line);
void mss_check_all_blocks(const char *filename, const char *function, unsigned long line);
void mss_check_block(void *ptr, const char *filename, const char *function, unsigned long line);


/****************/
/*  CPPSPEC.CC  */
/****************/
#ifdef __cplusplus
} /* End of extern "C" */

#ifdef MSS_HAVE_HEADER_NEW
#    include <new>
#endif

#ifdef MSS_EXCEPTION_SUPPORT
#    define MSS_DELETE_EXCEPTIONS throw()
#    ifdef MSS_BAD_ALLOC
#        define MSS_NEW_EXCEPTIONS throw(MSS_BAD_ALLOC)
#    else
#        define MSS_NEW_EXCEPTIONS throw()
#    endif
#else
#    define MSS_DELETE_EXCEPTIONS
#endif

extern unsigned int MSS_DEL_LINE;
extern const char *MSS_DEL_FILENAME;
extern const char *MSS_DEL_FUNCTION;

/* Overloaded and redefined operators */
void *operator new(size_t s) MSS_NEW_EXCEPTIONS;
void *operator new(size_t s, const char *filename, const char *function, unsigned long line) MSS_NEW_EXCEPTIONS;
void operator delete(void *p) MSS_DELETE_EXCEPTIONS;

void *operator new[](size_t s) MSS_NEW_EXCEPTIONS;
void *operator new[](size_t s, const char *filename, const char *function, unsigned long line) MSS_NEW_EXCEPTIONS;
void operator delete[](void *p) MSS_DELETE_EXCEPTIONS;

#ifdef MSS_NOTHROW_T
void *operator new(size_t s, const MSS_NOTHROW_T & nothrow) MSS_NEW_EXCEPTIONS;
void *operator new[](size_t s, const MSS_NOTHROW_T & nothrow) MSS_NEW_EXCEPTIONS;
#endif

extern "C" {
#endif /* !__cplusplus */


/****************/
/*    LOG.C     */
/****************/
typedef int (*MssCallBackFunc)  (char *		outbuf,
				 void *		blkptr,
		              	 unsigned int 	blklen,
	 			 const char * 	blklab,
				 const char * 	blksrc,
				 const char * 	blkfnc,
				 unsigned int blklin);

void mss_log_block_list_filtered(const char * filename, const char * function, unsigned int line, MssCallBackFunc callback_func);
void mss_log_msg(const char *msg, const char *filename, const char *function, unsigned long line);
void mss_log_disable(const char *filename, const char *function, unsigned long line);
void mss_log_enable(const char *filename, const char *function, unsigned long line);
void mss_log_info(const char *filename, const char *function, unsigned long line);
void mss_log_internal_info(const char *filename, const char *function, unsigned long line);
void mss_log_list_blocks(const char *filename, const char *function, unsigned long line);
void mss_log_list_blocks_internal();


/****************/
/*    INIT.C    */
/****************/
void mss_startup(void);

#ifdef __cplusplus
}
#endif /* !__cplusplus */

#endif /* !defined __mss_h__ */

/****************/
/* User  Macros */
/****************/
/* Don't define these if in MSS source */
#ifndef __mss_internal__

/* Check if we are being included after <no_mss.h> and previously <mss.h>.
 * In this case redefine all logging macros. -- LB
 */
#ifdef __MSS_H_REINCLUDE
#undef __MSS_H_REINCLUDE
#define MSS
#endif 

/* If MSS is not defined, we do not use MSS either ;) */
#ifdef MSS
#ifdef __cplusplus
#define new new(__FILE__, __PRETTY_FUNCTION__, __LINE__)
#define delete MSS_DEL_FILENAME = __FILE__, MSS_DEL_LINE = __LINE__, MSS_DEL_FUNCTION = __PRETTY_FUNCTION__, delete
#endif /* !__cplusplus */

#define malloc(s) mss_malloc(s, MSS_BY_MALLOC, __FILE__, __PRETTY_FUNCTION__, __LINE__)
#define xmalloc(s) mss_malloc(s, MSS_BY_XMALLOC, __FILE__, __PRETTY_FUNCTION__, __LINE__)
#define free(p) mss_free(p, MSS_BY_FREE, __FILE__, __PRETTY_FUNCTION__, __LINE__)
#define realloc(p, s) mss_realloc(p, s, MSS_BY_REALLOC, __FILE__, __PRETTY_FUNCTION__, __LINE__)
#define xrealloc(p, s) mss_realloc(p, s, MSS_BY_XREALLOC, __FILE__, __PRETTY_FUNCTION__, __LINE__)
#define calloc(num, size) mss_malloc((num) * (size), MSS_BY_CALLOC, __FILE__, __PRETTY_FUNCTION__, __LINE__)
#define xfree(p) mss_free(p, MSS_BY_XFREE, __FILE__, __PRETTY_FUNCTION__, __LINE__)
#define cfree(p) mss_free(p, MSS_BY_CFREE, __FILE__, __PRETTY_FUNCTION__, __LINE__)
#ifdef strdup
#undef strdup
#endif
#define strdup(s) mss_strdup(s, __FILE__, __PRETTY_FUNCTION__, __LINE__)

#define MSS_ENTER_SCOPE mss_enter_scope(__FILE__, __PRETTY_FUNCTION__, __LINE__)
#define MSS_LEAVE_SCOPE mss_leave_scope(__FILE__, __PRETTY_FUNCTION__, __LINE__)

#define MSS_LOG_INFO mss_log_info(__FILE__, __PRETTY_FUNCTION__, __LINE__)
#define MSS_LOG_INTERNAL_INFO mss_log_internal_info(__FILE__, __PRETTY_FUNCTION__, __LINE__)
#define MSS_LOG_BLOCK_LIST mss_log_list_blocks(__FILE__, __PRETTY_FUNCTION__, __LINE__)
#define MSS_LOG_BLOCK_LIST_FILTERED(callback_func) mss_log_block_list_filtered(__FILE__, __PRETTY_FUNCTION__, __LINE__, callback_func)
#define MSS_LOG_MSG(m) mss_log_msg(m, __FILE__, __PRETTY_FUNCTION__, __LINE__)

#define MSS_CHECK_ALL_BLOCKS mss_check_all_blocks(__FILE__, __PRETTY_FUNCTION__, __LINE__)
#define MSS_CHECK_POINTER_VALIDITY(ptr) mss_check_pointer_validity(ptr, __FILE__, __PRETTY_FUNCTION__, __LINE__)
#define MSS_CHECK_BLOCK_AT(ptr) mss_check_block(ptr, __FILE__, __PRETTY_FUNCTION__, __LINE__)

#define MSS_DISABLE_LOG_OUTPUT mss_log_disable(__FILE__, __PRETTY_FUNCTION__, __LINE__)
#define MSS_ENABLE_LOG_OUTPUT mss_log_enable(__FILE__, __PRETTY_FUNCTION__, __LINE__)

#define MSS_REGISTER_CONSTANT_BLOCK(ptr) mss_register_constant_block(ptr, __FILE__, __PRETTY_FUNCTION__, __LINE__)
#define MSS_UNREGISTER_CONSTANT_BLOCK(ptr) mss_unregister_constant_block(ptr, __FILE__, __PRETTY_FUNCTION__, __LINE__)

#define MSS_CURRENTLY_USED_MEM mss_currently_used_mem()
#define MSS_MAXIMUM_USED_MEM mss_maximum_used_nem()
#define MSS_NUMBER_OF_ALLOCATED_BLOCKS mss_number_of_allocated_blocks()

#define MSS_STARTUP mss_startup()

#define MSS_SET_BLOCK_LABEL(ptr, str) mss_set_block_label(ptr, str, __FILE__, __PRETTY_FUNCTION__, __LINE__)
#define MSS_DUMP_BLOCK(ptr, filename) mss_dump_block(ptr, filename, __FILE__, __PRETTY_FUNCTION__, __LINE__)

#else /* #ifndef MSS */
/* We define these macros to nothing if MSS is undefined */
#define MSS_ENTER_SCOPE	;
#define MSS_LEAVE_SCOPE	;

#define MSS_LOG_INFO ;
#define MSS_LOG_INTERNAL_INFO ;
#define MSS_LOG_BLOCK_LIST ;
#define MSS_LOG_BLOCK_LIST_FILTERED(callback_func) ;
#define MSS_LOG_MSG(m) ;

#define MSS_CHECK_ALL_BLOCKS ;
#define MSS_CHECK_POINTER_VALIDITY(ptr) ;
#define MSS_CHECK_BLOCK_AT(ptr) ;

#define MSS_DISABLE_LOG_OUTPUT ;
#define MSS_ENABLE_LOG_OUTPUT ;

#define MSS_REGISTER_CONSTANT_BLOCK(ptr) ;
#define MSS_UNREGISTER_CONSTANT_BLOCK(ptr) ;

#define MSS_CURRENTLY_USED_MEM 0
#define MSS_MAXIMUM_USED_MEM 0
#define MSS_NUMBER_OF_ALLOCATED_BLOCKS ;

#define MSS_STARTUP ;

#define MSS_SET_BLOCK_LABEL(ptr, str) ;
#define MSS_DUMP_BLOCK(ptr, filename) ;


#endif /* !MSS */
#endif /* !__mss_internal__ */

#endif /* !defined __mss_h__ || !defined __MSS_H_REINCLUDE */
