dnl check whether mallinfo() is available and which fields to use to find out memory usage
dnl it's used in konq_mainwindow.cpp
dnl warning, ugly code ahead
dnl some implementations have mallinfo() in stdlib.h, others in malloc.h
dnl fields showing memory usage should be hblkhd, uordblks and usmblks,
dnl different implementations use different combinations of these (which is ok),
dnl but some of them "reuse" fields they don't use for other purposes

AC_DEFUN([KDE_MALLINFO_CHECK],
[
AC_MSG_CHECKING([for mallinfo() in $1])
AC_CACHE_VAL(kde_cv_func_mallinfo_$2,
    [
    AC_LANG_SAVE
    AC_LANG_CPLUSPLUS
    AC_TRY_COMPILE([#include $1],
	[
	struct mallinfo m;
	int dummy;
	m = mallinfo();
	dummy = m.hblkhd;
	dummy = m.uordblks;
	dummy = m.usmblks;
	dummy = dummy;
        ],
    kde_cv_func_mallinfo_$2=yes,
    kde_cv_func_mallinfo_$2=no)
    AC_LANG_RESTORE
    ])
if test "$kde_cv_func_mallinfo_$2" = "yes"; then
    kde_mallinfo_type=$2
fi
AC_MSG_RESULT($kde_cv_func_mallinfo_$2)
])


AC_DEFUN([KDE_MALLINFO_CHECK_FIELD],
[
AC_MSG_CHECKING([whether to use mallinfo field $1])
AC_CACHE_VAL(kde_cv_func_mallinfo_field_$1,
    [
    AC_LANG_SAVE
    AC_LANG_CPLUSPLUS
    AC_TRY_RUN(
	[

#include <$kde_mallinfo_type.h>
enum use_type { No, Yes, Never };
use_type use_field = No;
const int SIZE = 4 * 1024 * 1024;
const int SMALL_SIZE = 4 * 1024;

void dif( struct mallinfo& m1, struct mallinfo& m2, bool alloc )
    {
    int difval = m2.$1 - m1.$1;
    if( alloc )
	{
	if( difval >= SIZE && difval < 2 * SIZE && use_field != Never )
	    use_field = Yes;
	}
    else // !alloc
	{
	difval = -difval;
	if( difval > SMALL_SIZE && ( difval < SIZE || difval >= 2 * SIZE ) && use_field == Yes )
	    use_field = Never;
	}
    }

int main()
    {
    free( malloc( SIZE * 2 )); // avoid Doug Lea's malloc feature of having total_max in usmblks
    struct mallinfo m1 = mallinfo();
    void* mem1 = malloc( SIZE );
    struct mallinfo m2 = mallinfo();
    free( mem1 );
    struct mallinfo m3 = mallinfo();
    void* mem2[ SIZE / 32 ];
    for( int i = 0;
	 i < SIZE / 32;
	 ++i )
	mem2[ i ] = malloc( 32 );
    struct mallinfo m4 = mallinfo();
    for( int i = 0;
	 i < SIZE / 32;
	 ++i )
	free( mem2[ i ] );
    struct mallinfo m5 = mallinfo();
    void* mem3[ SIZE / 1024 ];
    for( int i = 0;
	 i < SIZE / 1024;
	 ++i )
	mem3[ i ] = malloc( 1024 );
    struct mallinfo m6 = mallinfo();
    for( int i = 0;
	 i < SIZE / 1024;
	 ++i )
	free( mem3[ i ] );
    struct mallinfo m7 = mallinfo();
    dif( m1, m2, true );
    dif( m2, m3, false );
    dif( m3, m4, true );
    dif( m4, m5, false );
    dif( m5, m6, true );
    dif( m6, m7, false );
    return use_field == Yes ? 0 : 1;
    }

        ],
	[kde_cv_func_mallinfo_field_$1=yes],
	[kde_cv_func_mallinfo_field_$1=no],
	[kde_cv_func_mallinfo_field_$1=no])
    AC_LANG_RESTORE
    ])
AC_MSG_RESULT($kde_cv_func_mallinfo_field_$1)        
kde_mallinfo_$1=$kde_cv_func_mallinfo_field_$1
if test "$kde_mallinfo_$1" = "yes"; then
    AC_DEFINE( KDE_MALLINFO_FIELD_$1, 1, [Use mallinfo field $1])
fi
])


kde_mallinfo_type=
KDE_MALLINFO_CHECK([<stdlib.h>],stdlib)
if test -z "$kde_mallinfo_type"; then
    KDE_MALLINFO_CHECK([<malloc.h>],malloc)
fi

AC_TRY_LINK_FUNC(mallinfo,
    [],
    [ AC_CHECK_LIB(malloc,mallinfo,
	[ AC_SUBST(LIBMALLOC,"-lmalloc") ],
	[ kde_mallinfo_type="" ])
    ])
    
if test -n "$kde_mallinfo_type"; then
    KDE_MALLINFO_CHECK_FIELD(hblkhd)
    KDE_MALLINFO_CHECK_FIELD(uordblks)
    KDE_MALLINFO_CHECK_FIELD(usmblks)
    if test -z "$kde_mallinfo_hblkhd" -a \
	-z "$kde_mallinfo_uordblks" -a \
	-z "$kde_mallinfo_usmblks"; then
	kde_mallinfo_type=
    fi
fi


if test "$kde_mallinfo_type" = "stdlib"; then
    AC_DEFINE(KDE_MALLINFO_STDLIB, 1, [mallinfo() is available in <stdlib.h>])
elif test "$kde_mallinfo_type" = "malloc"; then
    AC_DEFINE(KDE_MALLINFO_MALLOC, 1, [mallinfo() is available in <malloc.h>])
fi
