#!/bin/sh -efu
#
# Copyright (C) 1999-2001  Dave Olszewski
# Copyright (C) 2006  Sir Raorn <raorn@altlinux.ru>
# Copyright (C) 2006  Dmitry V. Levin <ldv@altlinux.org>
# 
# Search through all system shared libraries for a specific symbol.
#
# 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
#

PROG=findsym

info()
{
	printf %s\\n "$PROG: $*" >&2
}

fatal()
{
	printf %s\\n "$PROG: $*" >&2
	exit 1
}

show_usage()
{
	[ -z "$*" ] || info "$*"
	echo "Try \`$PROG --help' for more information." >&2
	exit 1
}

print_version()
{
	cat <<EOF
$PROG version 1.2
Written by Dave Olszewski.
Rewritten by Sir Raorn and Dmitry V. Levin.

Copyright (C) 1999-2001  Dave Olszewski
Copyright (C) 2006  Sir Raorn <raorn@altlinux.ru>
Copyright (C) 2006  Dmitry V. Levin <ldv@altlinux.org>
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
EOF
	exit
}

show_help()
{
	cat <<EOF
$PROG - search through all system shared libraries for a specific symbol.

This program will attempt to search through all system shared libraries
for a specific symbol.  This is useful when trying to compile something
and the compiler complains about an undefined reference similar to this:

/tmp/ccabcdef.o(.text+0x7): undefined reference to \`foo'

Running \`findsym' would try to locate the symbol foo and indicate
what library you should be linking with.

Usage: $PROG [options] <symbol>...

Options:
  -C, --demangle[=style]    demangle symbol names;
  -V, --version             print program version and exit;
  -h, --help                show this text and exit.
    
Report bugs to http://bugs.altlinux.ru/

EOF
	exit
}

TEMP=`getopt -n $PROG -o C,h,V -l demangle::,help,version -- "$@"` ||
	show_usage
eval set -- "$TEMP"

demangle=
while :; do
	case "$1" in
		--) shift; break
			;;
		-C)
			demangle='-C'
			;;
		--demangle)
			shift; demangle="--demangle=$1"
			;;
		-h|--help) show_help
			;;
		-V|--version) print_version
			;;
		*) fatal "Unrecognized option: $1"
			;;
	esac
	shift
done

# At least one argument, please.
[ "$#" -ge 1 ] ||
	show_usage 'Not enough arguments.'

IFS='
'
/sbin/ldconfig -p |
	sed -ne 's/^.\+=>[[:space:]]\+\([^[:space:]]\+\)[[:space:]]*$/\1/p' |
	sort -u |
	xargs -r nm -gD ${demangle} -- 2>/dev/null |
		LC_ALL=C sed -e 's/^\([0-9a-f]\+\)\?[[:space:]]\+\([A-Za-z]\)[[:space:]]\+\([^[:space:]]\)/\1\t\2\t\3/' |
		LC_ALL=C awk "-vr=$IFS" "-vs=$*" '
BEGIN {
	FS="\t"
	OFS=" "
	f=""
	split(s,a,r)
}
(NF==0) {f=""}
(NF==1) {f=$1}
((NF==3) && (f!="") && ($2~/^[A-Za-z]$/) && ($1~/^[0-9a-f]+$/)) {
	for(e in a)
		if($3==a[e]) {
			$1=$1
			printf("%s %s\n",f,$0)
		}
}
'
