#!/bin/ksh
##
## AIX ldd(1) clone with shared objects (*.so) in archives (*.a) support
## Copyright (C) 2017 SATOH Fumiyasu @ OSS Technology Corp, Japan
##               <http://www.OSSTech.co.jp/>
##               <https://fumiyas.github.io/>
##
## License: GNU General Public License version 3
##

set -u
umask 0077

export PATH="/bin:/usr/bin"
export OBJECT_MODE=32_64

## ======================================================================

## Print arguments as-is
printr() {
  print -r -- "$*"
}

ldd_executable() {
  typeset executable
  executable="$1"; shift

  LC_ALL=C dump -H "$executable" \
  |sed \
    -e '1,/^INDEX  *PATH /d' \
    -e 's/^\(.\{7\}\) /\1-/' \
  |{
    typeset rpaths rpath
    read -r n rpaths

    typeset req_rpaths req_lib_name req_lib req_lib_obj req_lib_found req_lib_line
    while read -r n req_rpaths req_lib_name req_lib_obj; do
      [[ $req_rpaths == - ]] && req_rpaths="${LIBPATH:+$LIBPATH:}$rpaths"
      req_lib_found=
      for rpath in $(printr "$req_rpaths" |sed 's/:/ /g'); do
	req_lib="${rpath%/}/$req_lib_name"
	[[ -f $req_lib ]] || continue

	if [[ -z $req_lib_obj ]]; then
	  req_lib_line="$req_lib"
	else
	  req_lib_line="$req_lib($req_lib_obj)"
	  file "$req_lib" |grep ' archive ' >/dev/null || continue
	  ## FIXME: Do recurive ldd
	  ar t "$req_lib" "$req_lib_obj" >/dev/null || continue
	fi

	printr "	$req_lib_line"
	req_lib_found=set
	break
      done
      [[ -n $req_lib_found ]] || printr "Cannot find $req_lib_name" 1>&2
    done
  }
}

ldd_archive() {
  typeset archive archive_obj
  archive="$1"; shift
  archive_obj="${1-}"

  (
    cd "$tmp_dir" || exit $?
    if [[ $archive == /* ]]; then
      ar x "$archive" ${archive_obj:+"$archive_obj"}
    else
      ar x "$OLDPWD/$archive" ${archive_obj:+"$archive_obj"}
    fi
  ) || return $?

  if [[ -n $archive_obj ]]; then
    ldd_executable "$archive_obj"
    rm "$archive_obj"
  else
    for archive_obj in "$tmp_dir"/*.o "$tmp_dir"/*.so*; do
      [[ -f $archive_obj ]] || continue
      ldd_executable "$archive_obj"
      rm "$archive_obj"
    done
  fi
}

## ======================================================================

[[ $- == *x* ]] && typeset -ft $(typeset +f)

obj="$1"; shift

tmp_dir="/tmp/${0##*/}.$(date +%s).$$.tmp"
mkdir -m 0700 "$tmp_dir" || exit $?
trap 'rc=$?; rm -rf "$tmp_dir"; exit $rc' EXIT INT TERM

printr "$obj needs:"
if file "$obj" |grep ' executable ' >/dev/null; then
  ldd_executable "$obj" || exit $?
else
  ldd_archive "$obj" || exit $?
fi

exit 0
