#!/bin/bash

##########################################################
# Copyright (c) 2001-2025 Alexey Kuryakin daqgroup@mail.ru
##########################################################

##########################################################
# Utility to search the path of command or shared library.
# Uses {which,whereis,ldconfig} commands for files search.
##########################################################


declare -i opt_exec=0; # option --exec - execute found command
declare -i opt_verb=0; # option --verb - verbose print on bugs

#############################################################################################################################
# https://stackoverflow.com/questions/1763891/is-it-possible-to-make-stdout-and-stderr-output-be-of-different-colors-in-xterm
#############################################################################################################################
function colorize_norm()( set -o pipefail; ( "$@" 2>&1>&3 | sed $'s,.*,\e[31m&\e[m,'   >&2 ) 3>&1 | sed $'s,.*,\e[32m&\e[m,'   );
function colorize_bold()( set -o pipefail; ( "$@" 2>&1>&3 | sed $'s,.*,\e[1;31m&\e[m,' >&2 ) 3>&1 | sed $'s,.*,\e[1;32m&\e[m,' );
function colorize_head()( set -o pipefail; ( "$@" 2>&1>&3 | sed $'s,.*,\e[1;35m&\e[m,' >&2 ) 3>&1 | sed $'s,.*,\e[1;37m&\e[m,' );

function print_stderr(){
 1>&2 echo -ne "$1";
};

function color_print_stderr(){
 local message="$1"; local colorize="";
 if [[ -t 1 ]]; then colorize="colorize_bold"; fi;
 $colorize print_stderr "$message";
};

function fatal(){
 color_print_stderr "\n$2\n\n";
 exit $1;
};

function verb_print_stderr(){
 if [[ $opt_verb -gt 0 ]]; then
  color_print_stderr "$1";
 fi;
};

function error_noarg(){
 local scriptname="$(basename ${BASH_SOURCE[0]})";
 fatal 1 " Error: missed argument. Use $scriptname -h for help.";
};

function show_vers(){
 local scriptname="$(basename ${BASH_SOURCE[0]})";
 echo "$scriptname version 1.0";
};

function show_help(){
 show_vers;
 local scriptname="$(basename ${BASH_SOURCE[0]})";
 echo "Copyright (c) 2001-2025 Alexey Kuryakin daqgroup@mail.ru";
 echo "Search specified command or library using (which,whereis,ldconfig).";
 echo "Execute found command when --exec option specified.";
 echo "Usage: ${scriptname} [-options] [name [args]]";
 echo "Options:";
 echo " -h,--help  - show help";
 echo " --version  - show version";
 echo " -v,--verb  - verbose print on bugs"
 echo " -e,--exec  - execute found command";
 echo "Arguments:";
 echo " name       - command or library name to search";
 echo " args       - command line arguments";
 echo "Notes:";
 echo " 1) Libraries has names like lib*.so or lib*so.1.";
 echo " 2) Command search uses which call, then whereis.";
 echo " 3) Library search uses ldconfig call.";
 echo "Examples:";
 echo " $scriptname --help       # show help";
 echo " $scriptname --version    # show version";
 echo " $scriptname hddtemp      # find command";
 echo " $scriptname libdim.so    # find library";
 echo " $scriptname -e ifconfig  # execute command";
};

function whereis_bin(){
 local arg="$1";
 if [[ -n $arg ]]; then
  whereis -b $arg | awk '{print $2}';
  return $?; 
 fi;
 return 1;
};

function ldconfig_cache(){
 local ldconfig="$(whereis_bin ldconfig)";
 if [[ -x $ldconfig ]]; then
  $ldconfig -p | grep '=>' |  sed -e 's/.*=>\s*//';
  return $?;
 fi;
 return 1;
};

function which_lib(){
 local arg="$1";
 if [[ -n $arg ]]; then
  local lib="$(ldconfig_cache | grep "/$arg$" | head -n 1)";
  if [[ -x $lib ]]; then
   echo "$lib";
   return 0;
  fi;
 else
  error_noarg;
 fi;
 verb_print_stderr "Error: could not find library $1.\n";
 return 1;
};

function which_cmd(){
 local arg="$1";
 if [[ -n $arg ]]; then
  local cmd="$(which $arg 2>/dev/null)";
  if [[ -z $cmd ]]; then
   cmd="$(whereis_bin "$arg")";
  fi;
  if [[ -x $cmd ]]; then
   if [[ $opt_exec -eq 1 ]]; then
    shift;
    exec $cmd "$@";
    return $?;
   else
    echo "$cmd";
    return 0;
   fi;
  fi;
 else
  error_noarg;
 fi;
 verb_print_stderr "Error: could not find command $1.\n";
 return 1;
};

function main(){
 if [[ -z $1 ]]; then
  error_noarg;
  return 1;
 fi;
 while [[ -n $1 ]]; do
  case $1 in
   --version)       show_vers; return 0; ;;
   -h|-help|--help) show_help; return 0; ;;
   -e|-exec|--exec) let opt_exec=1; ;;
   -v|-verb|--verb) let opt_verb=1; ;;
   *.so|*.so.\d)    which_lib "$@"; return $?; ;;
   *)               which_cmd "$@"; return $?; ;;
  esac;
  shift;
 done;
};

main "$@";

##############
## END OF FILE
##############
