#!/bin/sh

############################################################
# Copyright (c) 2009-2010 by Aleksey Cheusov
#
# See COPYRIGHT file in the distribution.
############################################################

set -e

LC_ALL=C
export LC_ALL

if test -d /usr/xpg4/bin; then
    # We cannot work with Solaris' default usercrap
    PATH=/usr/xpg4/bin:$PATH
    export PATH
fi

##################################################
# options
usage (){
    cat <<EOF
mkc_check_decl detects presense of define, variable, function or type
in system header files by compiling a test program.

Usage:
 mkc_check_decl <define|variable|func[0-9]|type|member> <what> [includes...]

Examples:
   mkc_check_decl define __GNUC__
   mkc_check_decl define RTLD_LAZY dlfcn.h
   mkc_check_decl variable sys_errlist errno.h
   mkc_check_decl variable __malloc_hook malloc.h
   mkc_check_decl func3 poll poll.h
   mkc_check_decl func2 fgetln stdio.h
   mkc_check_decl type mbstate_t wchar.h
   mkc_check_decl type long-long
   mkc_check_decl member tm.tm_isdst time.h
   mkc_check_decl member ifreq.ifr_addr.sa_len net/if.h
EOF
}

if test $# -eq 0; then
    usage
    exit 1
fi
if test "_$1" = '_-h' -o "_$1" = '_--help'; then
    usage
    exit 0
fi

##################################################
# initializing

decltype=`echo $1 | sed -e 's/[0-9]//g'`
argscnt=`echo $1 | sed 's/[^0-9]//g'`
shift

declwhat=`echo $1 | sed 's/-/ /'`
shift

if test "$decltype" = type; then
    pathpart=`echo ${decltype}_${declwhat}_$* | tr '/. ' '__~'`
else
    pathpart=`echo $decltype$argscnt $declwhat $* | tr '/. ' '___'`
fi

. mkc_check_common.sh

##################################################
# functions

get_includes (){
    for i in $MKC_COMMON_HEADERS "$@"; do
	echo "#include <$i>"
    done
}

##############################
compile (){
    if $CC -c -o "$tmpo" $CPPFLAGS $CFLAGS "$tmpc" 2>"$tmperr"
    then
	return 0
    else
	return 1
    fi
}

##############################
is_define (){
    get_includes "$@" > "$tmpc"

    cat >> "$tmpc" <<EOF
#if defined($declwhat)
int main ()
{
   return 0;
}
#else
.error "$declwhat is not a define"
#endif
EOF

    #
    compile
}

##############################
is_variable (){
    get_includes "$@" > "$tmpc"

    cat >> "$tmpc" <<EOF
int main ()
{
   return sizeof (($declwhat)) && (&$declwhat != 0);
}
EOF
    #
    compile
}

##############################
has_size (){
    get_includes "$@" > "$tmpc"

    cat >> "$tmpc" <<EOF
int main ()
{
   return sizeof ($declwhat);
}
EOF

    #
    compile
}

is_type (){
    has_size "$@" || return 1
    is_variable "$@" && return 1
    return 0
}

##############################
is_func (){
    get_includes "$@" > "$tmpc"

    cat >> "$tmpc" <<EOF
void func (void)
{
   if (${declwhat}) return;
   ${declwhat} (
EOF

    awk -v N="$argscnt" '
BEGIN {
   for (i=0; i < N; ++i){
      if (i)
         printf ","
      printf "0"
   }
}
' >> "$tmpc"

    printf ');\n}\n' >> "$tmpc"

    #
    compile
}

##############################
is_member (){
    get_includes "$@" > "$tmpc"

    type_t=`echo $declwhat | sed 's/[.].*$//'`
    member=`echo $declwhat | sed 's/^[^.]*[.]//'`

    cat >> "$tmpc" <<EOF
int main ()
{
   $type_t var;
   return sizeof (var.$member);
}
EOF

    #
    compile
}

##################################################
# test

for i in "$@"; do
    incs_msg="$incs_msg $i"
done

if test -n "$incs_msg"; then
    incs_msg=" ($incs_msg )"
fi

check_itself (){
    if is_${decltype} "$@"
    then
	echo 1
    else
	echo 0
    fi
}

check_and_cache "checking for $decltype ${declwhat}${incs_msg}" "$cache" "$@"

##################################################
# clean-ups

cleanup

##################################################
# finishing

if test "$ret" -eq 1; then
    printme 'yes\n' 1>&2
else
    printme 'no\n' 1>&2
fi

echo $ret
