#!/bin/bash
#
# SPDX-License-Identifier: GPL-3.0-or-later

LIBDIR=${LIBDIR:-'/usr/share/artools/lib'}

# shellcheck source=src/lib/base/message.sh
source "${LIBDIR}"/base/message.sh

set -e

IGNORE_INTERNAL=0

if [[ $1 = "--ignore-internal" ]]; then
    IGNORE_INTERNAL=1
    shift
fi

script_mode=${BASH_SOURCE[0]##*/find-lib}

case $script_mode in
    deps|provides) true;;
    *) die "Unknown mode %s" "$script_mode" ;;
esac

if [[ -z $1 ]]; then
    printf "%s [options] <package file|extracted package dir>\n" "${0##*/}"
    printf "Options:\n"
    printf "    --ignore-internal      ignore internal libraries\n"
    exit 1
fi

if [[ -d $1 ]]; then
    pushd "$1" >/dev/null
else
    setup_workdir

    case ${script_mode} in
        deps) bsdtar -C "$WORKDIR" -xf "$1";;
        provides) bsdtar -C "$WORKDIR" -xf "$1" --include="*.so*";;
    esac

    pushd "$WORKDIR" >/dev/null
fi

shopt -s extglob

process_sofile() {
    # extract the library name: libfoo.so
    shopt -s extglob nullglob
    soname="${sofile%.so?(+(.+([0-9])))}".so
    shopt -u extglob nullglob
    # extract the major version: 1
    soversion="${sofile##*\.so\.}"
    if [[ "$soversion" = "$sofile" ]] && ((IGNORE_INTERNAL)); then
        return
    fi
    if ! in_array "${soname}=${soversion}-${soarch}" "${soobjects[@]}"; then
        # libfoo.so=1-64
        printf "%s\n" "${soname}=${soversion}-${soarch}"
        soobjects+=("${soname}=${soversion}-${soarch}")
    fi
}

shopt -u extglob

case $script_mode in
    deps) find_args=(-perm -u+x);;
    provides) find_args=(-name '*.so*');;
esac

find . -type f "${find_args[@]}" | while read -r filename; do
    if [[ $script_mode = "provides" ]]; then
        # ignore if we don't have a shared object
        if ! LC_ALL=C readelf -h "$filename" 2>/dev/null | grep -q '.*Type:.*DYN (Shared object file).*'; then
            continue
        fi
    fi

    # get architecture of the file; if soarch is empty it's not an ELF binary
    soarch=$(LC_ALL=C readelf -h "$filename" 2>/dev/null | sed -n 's/.*Class.*ELF\(32\|64\)/\1/p')
    [[ -n $soarch ]] || continue

    if [[ $script_mode = "provides" ]]; then
        # get the string binaries link to: libfoo.so.1.2 -> libfoo.so.1
        sofile=$(LC_ALL=C readelf -d "$filename" 2>/dev/null | sed -n 's/.*Library soname: \[\(.*\)\].*/\1/p')
        [[ -z $sofile ]] && sofile="${filename##*/}"
        process_sofile
    elif [[ $script_mode = "deps" ]]; then
        # process all libraries needed by the binary
        for sofile in $(LC_ALL=C readelf -d "$filename" 2>/dev/null | sed -nr 's/.*Shared library: \[(.*)\].*/\1/p'); do
            process_sofile
        done
    fi
done

popd >/dev/null
