#! /bin/sh

set -e

be32()
{
  set -- $($OD -An -j "$1" -N 4 -t u1 "$2") || return 1
  echo $((($1 << 24) | ($2 << 16) | ($3 << 8) | $4 ))
}

rpmhdrsize()
{
  off=$1
  file=$2

  nindex=$(be32 $((off + 8)) "$file") || return 1
  hsize=$(be32 $((off + 12)) "$file") || return 1

  echo $((16 + nindex * 16 + hsize))
}

rpmcpioofs()
{
  file=$1

  # check RPM magic
  set -- $($OD -An -N 4 -t x1 "$file") || return 1
  if [  "$1 $2 $3 $4" != "ed ab ee db" ] ; then
    echo "$file: not an RPM file"
    return 1
  fi

  off=96

  # signature header
  sz=$(rpmhdrsize "$off" "$file") || return 1
  off=$((off + ((sz + 7) & ~7)))

  # main header
  sz=$(rpmhdrsize "$off" "$file") || return 1
  off=$((off + sz))

  echo "$off"
}

rpm2cpio()
{
  file=$1
  off=$(rpmcpioofs "$file") || return 1

  set -- $($OD -An -j "$off" -N 6 -t x1 "$file") || return 1

  case "$1 $2 $3 $4 $5 $6" in
    '1f 8b '*) extr="$GZIP -dc" ;;
    '42 5a 68 '*) extr="$BZIP2 -dc" ;;
    'fd 37 7a 58 5a 00') extr="$XZ -dc" ;;
    '28 b5 2f fd '*) extr="$ZSTD -dc" ;;
    '30 37 30 37 30 31' | *) extr="$CAT" ;; # uncompressed or unknown method
  esac

  $DD if="$file" bs=1 skip="$off" 2> /dev/null | $extr
}

printlist()
{
  for e in "$@"; do
    echo "    $e"
  done
}

myname=$(basename $0)
mydir=$(dirname $0)

opt_a=false
opt_d=false
opt_e=false

for p in "$@"; do
  # destdir should be the last
  if [ -n "$destdir" ]; then
    packages=""
    break
  fi

  case "$p" in
    -a)
      opt_a=true
      ;;
    -d)
      opt_d=true
      ;;
    -e)
      opt_e=true
      ;;
    *)
      if $opt_a; then
        rpmarch="$p"
        opt_a=false
      elif $opt_d; then
        destdir="$p"
        opt_d=false
      else
        packages="$packages${packages:+ }$p"
      fi
      ;;
  esac
done

if [ -z "$packages" ] || $opt_a || $opt_d ; then
  echo "Usage: $myname package[.oc00[.arch[.rpm]]] ... [-e] [-a arch] [-d destdir]"
  echo
  echo "This will install package[.oc00[.arch[.rpm]]] to destdir without"\
       "checking dependencies."
  echo "If -e is given, experimental repo will be searched, too."
  echo "arch should be one of noarch, i386, i686 and pentium4."
  echo "If -a arch is omitted, arch will be penitum4." \
       "i386, i686 and pentium4 available."
  echo "If -d destdir is omitted, destdir will be i686-pc-os2-emx of" \
       "the parent dir of"
  echo "the dir where $myname is. That is, dir/../i686-pc-os2-emx."
  exit 1
fi

# assume we're in /opt/os2emx/bin directory
prefix="$mydir/.."
target=i686-pc-os2-emx
targetprefix="${destdir:-$prefix/$target}"

: ${CURL:=curl -sSfL}
: ${SED:=sed}
: ${SORT:=sort}
: ${GREP:=grep}
: ${UNZIP:=unzip}
: ${MKDIR_P:=mkdir -p}
: ${OD:=od}
: ${DD:=dd}
: ${GZIP:=gzip}
: ${BZIP2:=bzip2}
: ${XZ:=xz}
: ${ZSTD:=zstd}
: ${CAT:=cat}
: ${CPIO:=cpio -v}
: ${CP:=cp -v}
: ${RM:=rm -f}

rpmarch=${rpmarch:-pentium4}
rpmnoarch=noarch
rpmarchurl="https://rpm.netlabs.org/release/00/pentium4/$rpmarch"
rpmnoarchurl="https://rpm.netlabs.org/release/00/pentium4/$rpmnoarch"
rpmexparchurl="https://rpm.netlabs.org/experimental/00/i386/$rpmarch"
rpmexpnoarchurl="https://rpm.netlabs.org/experimental/00/i386/$rpmnoarch"
rpmdir="$myname.rpm.dir"
rpmlst="$rpmdir/$myname.rpm.lst"

$MKDIR_P "$rpmdir"

echo "Downloading the RPM file list..."
$CURL "$rpmarchurl/" "$rpmnoarchurl/" \
  | $SED -n -e "s/^.*href=\"\(.*\.rpm\)\".*$/\1@@@rel@@@/" \
            -e "/^pthread.*-20[0-9]*-[0-9][0-9]*[-_.].*$/!p" > "$rpmlst.tmp"

if $opt_e; then
  $CURL "$rpmexparchurl/" "$rpmexpnoarchurl/" \
    | $SED -n -e "s/^.*href=\"\(.*\.rpm\)\".*$/\1@@@exp@@@/p" >> "$rpmlst.tmp"
fi

$SORT -V < "$rpmlst.tmp" > "$rpmlst"
$RM "$rpmlst.tmp"

addpackage()
{
  r="${1%@@@rel@@@}"
  r="${r%@@@exp@@@}"
  rpms="$rpms $r"

  case "$1" in
    *"$rpmarch.rpm@@@rel@@@")
      r="$rpmarchurl/$r"
      ;;
    *"$rpmnoarch.rpm@@@rel@@@")
      r="$rpmnoarchurl/$r"
      ;;
    *"$rpmarch.rpm@@@exp@@@")
      r="$rpmexparchurl/$r"
      ;;
    *"$rpmnoarch.rpm@@@exp@@@")
      r="$rpmexpnoarchurl/$r"
      ;;
  esac

  curlopts="$curlopts${curlopts:+ }-O -J $r"
  return 0
}

echo "Checking the package(s)..."
printlist $packages
for package in $packages; do
  case "$package" in
    *://*)
      # add URLs
      addpackage "$package"
      continue
      ;;
    *'*'* | *'?'*)
      pname=""
      r=""
      while read -r l; do
        case "$l" in
          $package)
            pn=$(echo "$l" | $SED 's/[-_.][0-9][0-9]*[-_.].*//')
            if [ "$pname" != "$pn" ]; then
              [ -z "$pname" ] || addpackage "$r"
              pname="$pn"
            fi
            r="$l"
            ;;
        esac
      done < "$rpmlst"
      [ -n "$pname" ] || { echo "Package '$package' not found!"; exit 1; }

      addpackage "$r"
      continue
      ;;
    *)
      if [ -f "$package" ]; then
        # add local files
        p="$package"
        if [ -n "${p##/*}" ]; then
          # relative path
          p="$(pwd)/$p"
        fi
        p="file://$p"
        addpackage "$p"
        continue
      fi
      ;;
  esac

  # normalize package
  r="${package%.oc00*}"
  r="$r.oc00"

  # find the exact match first
  r=$($GREP "^$r\.\($rpmarch\|$rpmnoarch\)\.rpm@@@\(rel\|exp\)@@@$" $rpmlst) || :

  if [ -z "$r" ]; then
    # find the latest version with $package package name
    r=$($GREP "^${package}[-_.][0-9]" $rpmlst | tail -n1) || :

    [ -n "$r" ] || { echo "Package '$package' not found!"; exit 1; }
  fi

  addpackage "$r"
done

echo "Downloading the RPM(s)..."
printlist $rpms
rpms="$($CURL --clobber -w "%{filename_effective}\n" --output-dir "$rpmdir" $curlopts \
        | $SED "s,$rpmdir/,,g")"

echo "Extracting the RPM(s)..."
printlist $rpms
saveddir="$PWD"
cd "$rpmdir"
for r in $rpms; do
  rpm2cpio "$r" | $CPIO -idm
done
cd "$saveddir"

echo "Installing the extracted file(s) to $targetprefix..."
$MKDIR_P "$targetprefix"
for d in "$rpmdir/@unixroot/usr"/* ; do
  $CP -fa "$d" "$targetprefix" || break
done

echo "Postprocessing for the RPM(s)..."
postrpm "$targetprefix"

echo "Cleaning up..."
$RM -r "$rpmdir"
