#!/bin/sh
#
# chkconfig: 345 96 11
# description: Patch libXaw to be libXaw3D / libneXtaw / whatever
#

Die () { # [message [errno]]
  # print $1 and exit $2
  echo "ERROR: ${1:-$?}" >&2
  exit ${2:-1}
}

Sys="`uname -a`"
PATH=/usr/bin:/usr/sbin:/bin:/sbin:/usr/local/bin

which_package () { # file_name
  # print the name of the package owes the $1
  case "$Sys" in
    FreeBSD*) pkg_info -W "$1"  | sed 's/.* \(.*\)/\1/';;
    Linux*alt*) rpm -qf "$1" ;;
    *) Die "Sorry, still no which_package support for $Sys" ;;
  esac
}

true_md5 () { # file_name
  # Find $1 checksum recorded in the package (if it's there)
  case "$Sys" in
    FreeBSD*)
      pkg=$PKGPATH/`which_package "$1"`/+CONTENTS
      test -r "$pkg" || { echo ""; return; }
      awk -v F="$1" 'BEGIN {RF=F}
/@cwd/{RF=F; sub($2"/*","",RF) }
$0==RF{getline; sub("@comment MD5:",""); print }
' "$pkg" ;;
    Linux*alt*)
      pkg=`which_package "$1"`;
      rpm -q --dump "$pkg" | grep "$1" | cut -d\  -f4 ;;
    *) Die "Sorry, still no true_md5 support for $Sys" ;;
  esac
}

real_md5 () { # file_name
  # Calculate $1 checksum compatible to package format
  case "$Sys" in
    FreeBSD*) md5 -q "$1" ;;
    Linux*alt*) md5sum "$1" | cut -d\  -f 1 ;;
    *) Die "Sorry, still no real_md5 support for $Sys" ;;
  esac
}

bupname () { # filename
  # Calculate file backup name of $1
  P=`which_package "$1"`
  echo `dirname "$1"`/.`basename "$1"`-${P#*-}
}

bupfile () { # filename [repeat]
  # Backup $1 or check current backup is valid
  B=`bupname "$1"`
  echo "$B"
  CF=`real_md5 "$1"`
  CT=`true_md5 "$1"`
  if [ -f "$B" ]	# Backup is here
  then
    CB=`real_md5 "$B"`
    if [ "$CB" = "$CT" ]
    then
      test "$CB" = "$CF"
    else
      echo "WARNING: Removing false backup for $1" >&2
      rm "$B"
      test -z "$2" || Die "Can't remove false backup for $1"
      bupfile "$1" REPEAT > /dev/null
    fi
  else			# No backup 
    test "$CF" = "$CT" || Die "No backup for $1, file is changed!"
    echo "WARNING: No backup for "$1", backing up" >&2
    cp -p "$1" "$B"
  fi
}

patchfile () { # name src dst
  if B=`bupfile "$1"`
  then
    test ${#2} -ge ${#3} || Die "Cannot patch $2 instead of $3: too short"
    bbe -b "/\000$2/:/\000/" -e "r 1 $3\000" -o "$1" "$B" || Die
    echo "Patching $1: $2 -> $3" >&2
  else
    echo "WARNING: file $1 is already patched" >&2
  fi
}

restorefile () { # filename [filename ...]
  for F
  do
    if B=`bupfile "$F"`
    then
      echo "WARNING: $F is not changed" >&2
    else
      cp -p "$B" "$F"
    fi
  done
}

whatfile () { # symlink lib1 [lib2 ...]
  L=$(realpath $1)
  C=`real_md5 "$L"`
  #R=`real_md5 "$L"`
  shift
  for F; do
    test `true_md5 "$F"` = "$C" && { echo "$F original"; return 0; }
    test `real_md5 "$F"` = "$C" && { echo "$F patched"; return 0; }
  done
  echo "NONE"; return 1
}

pkglist () { # package
  # list packaged files
  case "$Sys" in
    FreeBSD*) pkg_info -Lx "$1" 2>/dev/null ;;
    Linux*alt*) rpm -ql "$1" 2>/dev/null ;;
    *) Die "Sorry, still no pkglist support for $Sys" ;;
  esac
  return 0
}

Usage () {
  echo "$0 -r[estore]|-b[ackup]|-c[heck]|-p[atch]|-l[ist]|package_name"
  exit ${1:-0}
}

DO=what
case "$Sys" in
  Linux*alt*) ALLNEW="libneXtaw libXaw3d"
	OPKG="libXaw"
  ;;
  FreeBSD*) ALLNEW="neXtaw Xaw3d"
	OPKG="xorg-libraries"
  ;;
esac
ALLNEW=$(for N in $ALLNEW; do test -z "`pkglist $N`" || echo "$N"; done | tr '\n' ' ')
NPKG=`echo $ALLNEW | cut -d\  -f1`

while test "$#" -gt 0
do
  case "$1" in
    -r*) DO=restore ;;
    -b*) DO=backup ;;
    -e*) DO=erase ;;
    *start|-p*) DO=patch ;;
    stop) ;;
    -O*) OFIL="$2"; shift ;;
    -N*) NPKG="$2"; shift ;;
    -[cw]*) DO=what ;;
    -[h?]*) Usage 0 ;;
    *) NPKG="$1"; DO=patch ;; 
  esac
  shift
done
OLDL=`pkglist "$OPKG" | grep "$OPKG.*[.]so" | sort | tail -1`
NEWL=`pkglist "$NPKG" | grep "$NPKG.*[.]so" | sort | tail -1`
#echo "$OLDL" "$NEWL" && exit 0
OLDB=`bupfile "$OLDL"`
NEWB=`bupfile "$NEWL"`
OLDN=$(strings "$OLDB" | fgrep `basename ${OLDL%%.*}.so| sed 's/aw[0-9]\./aw./'`)
OLDR=`echo "$OLDN" | tr w W`
OLDNL=`dirname "$OLDL"`/"$OLDN"
NEWNL=`dirname "$NEWL"`/"$OLDN"
NEWN=$(strings "$NEWB" | fgrep `basename ${NEWL%%.*}.so`)
case $DO in
  backup)	;;	# done already
  restore)	restorefile "$OLDL" "$NEWL" 
		rm -f "$OLDNL" "$NEWNL"
  		ldconfig
  		;;
  erase)	Die "Still not implemented" ;;
  patch)	patchfile "$NEWL" "$NEWN" "$OLDN"
		patchfile "$OLDL" "$OLDN" "$OLDR"
		rm -f "$OLDNL" "$NEWNL"
		ldconfig
		test -f "$OLDNL" || ln -s "$NEWNL" "$OLDNL"
		;;
  *)		
		echo "New-style Xaw packages: $ALLNEW"
  		echo "Current $OLDN is `whatfile $OLDNL $OLDL $NEWL`" ;;
esac
