#! /bin/sh
#
# build -- Copyright (c) 2001-2003 Eberhard Mattes
#
# This file is part of epocemx.
#
# epocemx is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# epocemx is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with epocemx; see the file COPYING.  If not, write to the
# the Free Software Foundation, 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.
#

##############################################################################

# Map module names to archive/directory/patch names
bn_bu=binutils-2.11
bn_bzip2=bzip2-1.0.2
bn_diff=diffutils-2.8
bn_find=findutils-4.1
bn_gawk=gawk-3.1.0
bn_gcc=gcc-20010205
bn_grep=grep-2.4.2
bn_gzip=gzip-1.2.4a
bn_less=less-374
bn_recode=recode-3.6
bn_sed=sed-3.02
bn_su=sh-utils-2.0
bn_tar=tar-1.13
bn_tu=textutils-2.0
bn_unzip=unzip-5.50
bn_zip=zip-2.3

# Map module names to SIS filenames (gcc is special)
sis_bu=emxbinutils.sis
sis_bzip2=emxbzip2.sis
sis_diff=emxdiff.sis
sis_find=emxfind.sis
sis_gawk=emxgawk.sis
sis_gcc='emxgcc-base.sis emxgcc-c.sis emxgcc-c++.sis'
sis_grep=emxgrep.sis
sis_gzip=emxgzip.sis
sis_less=emxless.sis
sis_recode=emxrecode.sis
sis_sed=emxsed.sis
sis_su=emxshutils.sis
sis_tar=emxtar.sis
sis_tu=emxtextutils.sis
sis_unzip=emxunzip.sis
sis_zip=emxzip.sis

# EPOC modules
modules="bu bzip2 diff find gawk gcc grep gzip less recode sed su tar tu unzip"
modules="$modules zip"

# EPOC modules having build_xxx and clean_xxx functions; other EPOC modules
# are built with myall in epoc/xxx (or cleaned up with myclean)
special="bzip2 gcc unzip zip"

##############################################################################

# Functions for building the modules listed in `special'

build_bzip2()
{
  cd local/$bn_bzip2
  chmod u+x myinst
  make || exit 2
  cd ../../sis
  make $sis_bzip2
  cd ..
  make_zip $sis_bzip2
}

clean_bzip2()
{
  if [ -d local/$bn_bzip2 ]
  then
    (cd local/$bn_bzip2;make clean)
  fi
  clean_sis $sis_bzip2
}

build_gcc()
{
  cd epoc/gcc
  ./myall $allarg
  for f in xgcc cpp cpp0 tradcpp0 cc1 cc1plus
  do
    test -f gcc/$f || die "make failed: $f not built"
  done
  cd ../../sis
  make all-gcc || die "make failed"
  cd ..
  make_zip $sis_gcc
}

clean_gcc()
{
  test -d epoc/gcc || die "epoc/gcc does not exist"
  (cd epoc/gcc;./myclean)
  clean_sis $sis_gcc
}

build_unzip()
{
  cd local/$bn_unzip
  chmod u+x mymake myinst
  ./mymake || exit 2
  cd ../../sis
  make $sis_unzip
  cd ..
  make_zip $sis_unzip
}

clean_unzip()
{
  if [ -d local/$bn_unzip ]
  then
    (cd local/$bn_unzip;make -f unix/Makefile clean)
  fi
  clean_sis $sis_unzip
}

build_zip()
{
  cd local/$bn_zip
  chmod u+x mymake myinst
  ./mymake || exit 2
  cd ../../sis
  make $sis_zip
  cd ..
  make_zip $sis_zip
}

clean_zip()
{
  if [ -d local/$bn_zip ]
  then
    (cd local/$bn_zip;make -f unix/Makefile clean)
  fi
  clean_sis $sis_zip
}

##############################################################################

# Is $1 a special EPOC module?
is_special()
{
  for s in $special
  do
    test "$1" = "$s" && return 0
  done
  return 1
}

# Set bn to the value of bn_$1
set_bn()
{
  eval bn="\$bn_$1"
}

# Set sis to the value of sis_$1
set_sis()
{
  eval sis="\$sis_$1"
}

# build ZIP files from SIS files
make_zip()
{
  if [ -n "$o_z" ]
  then
    for x
    do
      test -f sis/$x || die "sis/$x: does not exist"
      zip=`echo $x|sed 's/\.sis$/.zip/'`
      (cd sis;make $zip) || die "make failed"
    done
  fi
}

# Clean up SIS and ZIP files
clean_sis()
{
  for x
  do
    zip=`echo $x|sed 's/\.sis$/.zip/'`
    rm -f sis/$x
    rm -f sis/$zip
  done
}

##############################################################################

# -status
do_status()
{
  format='%-10s %-24s %s\n'
  printf "$format" MODULE ARCHIVE STATUS
  for x in $modules
  do
    set_bn $x
    if [ -f SOURCE/$bn.tar.gz ]
    then
      suff=.tar.gz
    elif [ -f SOURCE/$bn.tar.bz2 ]
    then
      suff=.tar.bz2
    else
      suff=
    fi
    if [ -n "$suff" ]
    then
      status='SIS built'
      set_sis $x
      for s in $sis
      do
        test -f sis/$s || status='available'
      done
    else
      status='not available'
    fi
    printf "$format" $x $bn$suff "$status"
  done
  exit 0
}

# -archives
do_archives()
{
  for x in $modules
  do
    set_bn $x
    echo $bn
  done
  exit 0
}

# -modules
do_modules()
{
  shift
  mods=
  if [ $# = 1 ] && ( [ "$1" = all ] || [ "$1" = epoc ] )
  then
    mods="$modules"
  else
    for x
    do
      ok=
      for y in $modules
      do
        test "$x" = "$y" && ok=yes
      done
      test -n "$ok" || die "$x: unknown module"
      mods="$mods $x"
    done
  fi
  for x in $mods
  do
    set_bn $x
    printf '%-10s %s\n' $x $bn
  done
  exit 0
}

##############################################################################

# Yell and die
die()
{
  echo "*** $@" >&2
  exit 1
}

# How to use this program
usage()
{
  echo 'Usage:'
  echo '  build [OPTIONS] all [sdk] [-without MODULE...]'
  echo '  build [OPTIONS] epoc [-without MODULE...]'
  echo '  build [OPTIONS] MODULE...'
  echo '  build [OPTIONS] -status'
  echo
  echo 'Modules:'
  echo '  host  cross development system'
  echo '  sdk   EPOC C++ SDK'
  echo
  echo 'EPOC modules:'
  echo '  emx' $modules
  echo
  echo 'Options:'
  echo "  -c    don't build modules, clean up instead"
  echo '  -d    delete existing unpacked and patched source files'
  echo '  -i    use emxinstall to install EPOC files'
  echo "  -j    don't clean up and don't configure before building (implies -u)"
  echo "  -m    don't fail if the source code archive for an optional module is missing"
  echo "  -n    don't build modules (for use with -i)"
  echo '  -u    use existing unpacked and patched source files (implied by -j)'
  echo '  -z    make ZIP files from the SIS files'
  exit 1
}

#Process one EPOC module of the command line
add_mod()
{
  if [ -z "$o_without" ]
  then
    a_mods="$a_mods $1"
  else
    a_without="$a_without $1"
  fi
}

#Process the "host" module of the command line
add_host()
{
  if [ -z "$o_without" ]
  then
    a_host=host
  else
    a_without_host=x
  fi
}

# Fail after -without
wo()
{
  test -z "$o_without" || die "cannot use $1 after -without"
}

##############################################################################

# Parsing the command line

test $# = 1 && test "$1" = "-archives" && do_archives
test $# -gt 1 && test "$1" = "-modules" && do_modules "$@"
test -d SOURCE || die "Please configure the source path with ./cfg-src"
test $# = 1 && test "$1" = "-status" && do_status

# Parsing the command line

a_all=
a_emx=
a_host=
a_without_host=
a_sdk=
a_mods=
a_without=
o_c=
o_d=
o_i=
o_j=
o_m=
o_n=
o_u=
o_without=
o_z=
while [ $# != 0 ]
do
  case "$1" in
    -c)       wo "$1"; o_c=x;;
    -d)       wo "$1"; o_d=x;;
    -i)       wo "$1"; o_i=x;;
    -j)       wo "$1"; o_j=x; o_u=x;;
    -m)       wo "$1"; o_m=x;;
    -n)       wo "$1"; o_n=x;;
    -u)       wo "$1"; o_u=x;;
    -z)       wo "$1"; o_z=x;;
    -without) wo "$1"; o_without=x;;
    -help)    usage;;
    --help)   usage;;
    all)      wo "$1"; a_all=$1;;
    epoc)     wo "$1"; a_mods="$modules";;
    emx)      wo "$1"; a_emx=$1;;
    host)     add_host;;
    sdk)      wo "$1"; a_sdk=$1;;
    bu | bzip2 | diff | find | gawk | gcc | grep | gzip | less | recode | sed | su | tar | tu | unzip | zip)
              add_mod $1;;
    -*)       die "$1: unknown option";;
    *)        die "$1: unknown module"
  esac
  shift
done

# Checking the arguments and computing the module list
test "$o_d$o_u" = "xx" && die "cannot use both -d and -u"
test -n "$o_c" && test -n "$o_d$o_i$o_j$o_m$o_n$o_u$o_z" && die "cannot use -c with another option"
m=
if [ -n "$a_all" ]
then
  test -z "$a_mods$a_host$a_emx"  || die "cannot use 'all' with another module"
  for x in $modules
  do
    m="$m $x"
  done
  a_emx=emx
  test -z "$a_without_host" && a_host=host
else
  for x in $modules
  do
    ok=false
    for y in $a_mods
    do
      test "$x" = "$y" && ok=true
    done
    $ok && m="$m $x"
  done
  test -n "$a_without_host" && a_host=
fi

mods=
for x in $m
do
  include=true
  for y in $a_without
  do
    test "$x" = "$y" && include=false
  done
  $include && mods="$mods $x"
done

test -n "$a_host$a_sdk$a_emx$mods" || usage
echo Selected modules: $a_host $a_sdk $a_emx $mods

if [ -n "$o_i" ]
then
  test -n "$EMXINSTALL_ROOT" || die "EMXINSTALL_ROOT not set, see INSTALL"
fi

host=
test -n "$a_host" && host='bu gcc'

allarg=
test -n "$o_j" && allarg=-j

if [ -z "$o_c" ]
then
  # Checking archives and patches
  for x in $host
  do
    set_bn $x
    test -f SOURCE/$bn.tar.gz || test -f SOURCE/$bn.tar.bz2 || die "SOURCE/$bn.tar.gz does not exist"
    test -f patches/$bn.patch || die "patches/$bn.patch does not exist"
  done
  new_mods=
  for x in $mods
  do
    set_bn $x
    test -f patches/$bn.patch || die "patches/$bn.patch does not exist"
    if [ -f SOURCE/$bn.tar.gz ] || [ -f SOURCE/$bn.tar.bz2 ]
    then
      new_mods="$new_mods $x"
    elif [ -z "$o_m" ]
    then
      die "SOURCE/$bn.tar.gz does not exist"
    else
      echo "SOURCE/$bn.tar.gz does not exist -- module $x won't be built"
    fi
  done
  test "$mods" != "$new_mods" && echo Selected modules: $a_host $a_sdk $a_emx $new_mods
  mods="$new_mods"
fi

# Checking installation
for x in $host $mods
do
  set_bn $x
  if [ -z "$o_c" ]
  then
    # TODO: host/$x
    is_special $x || test -d epoc/$x || die "epoc/$x does not exist"
    if [ -n "$o_d" ]
    then
      rm -rf local/$bn
    elif [ -z "$o_u" ]
    then
      for opt in -f -d
      do
        test $opt local/$bn && die "local/$bn exists -- use -d or -u (or -j)"
      done
    fi
  fi
done

# Environment checks
recode /crlf.. </dev/null || die "recode: not installed or too old"
echo 'Checking the patch utility:'
patch --version </dev/null 2>&1 | grep '^patch 2\.[5-9]' || die "patch: not installed or not GNU patch (need GNU patch 2.5 or later)"
echo 'Checking the make utility:'
make -v -f /dev/null 2>&1 | grep -i '^gnu make' || die "make: not installed or not GNU make (need GNU make)"
test -d /usr/local/epocemx || die "/usr/local/epocemx: does not exist"
test -d SDK-inc || die "Please configure the SDK path with ./cfg-sdk"
test -d SDK-lib || die "Please configure the SDK path with ./cfg-sdk"

(
  ok=
  IFS=':'
  for x in $PATH
  do
    test "$x" = "/usr/local/epocemx/bin" && ok=yes
    test "$x" = "/usr/local/epocemx/bin/" && ok=yes
  done
  test -n "$ok"
) || die "/usr/local/epocemx/bin: not in PATH"

# -c
if [ -n "$o_c" ]
then
  for x in $host
  do
    (cd host/$x; ./myclean)
  done
  if [ -n "$host" ]
  then
    (cd tools; make clean)
    (cd lib; make clean)
    (cd hello; make clean)
  fi
  if [ -n "$a_emx" ]
  then
    (cd console; make clean)
    (cd lib; make clean)
    (cd tools; make clean)
    (cd tools; make -f Makefile.epoc clean)
    (cd estlib; make clean)
    clean_sis emxuser.sis emxdev.sis
  fi
  for x in $mods
  do
    set_bn $x
    if is_special $x
    then
      (clean_$x)
    else
      set_sis $x
      (cd epoc/$x; ./myclean)
      clean_sis $sis
    fi
  done
  exit
fi

if [ -z "$o_n" ]
then

  # Unpacking archives and applying patches
  test -d local || mkdir local || die "mkdir failed"
  for x in $host $mods
  do
    set_bn $x
    if [ ! -d local/$bn ]
    then
      if [ -f SOURCE/$bn.tar.gz ]
      then
        echo "Unpacking $bn.tar.gz ..."
        gunzip <SOURCE/$bn.tar.gz | (cd local;tar xf -) || die "tar failed for $bn.tar.gz"
      else
        echo "Unpacking $bn.tar.bz2 ..."
        bunzip2 <SOURCE/$bn.tar.bz2 | (cd local;tar xf -) || die "tar failed for $bn.tar.bz2"
      fi
      echo "Patching $bn ..."
      (cd local/$bn; patch -p 2 <../../patches/$bn.patch) || die "patch failed"
    fi
  done

  # Module `host' (first part)
  if [ -n "$host" ]
  then
    echo "Guessing system type..."
    local/$bn_bu/config.guess >SYSTEM || die "config.guess failed"
    echo "Building binary utilities (host)..."
    (cd host/bu;./myall $allarg;./myinst >>out 2>&1)
    echo "Building GCC (host)..."
    (cd host/gcc;./myall $allarg;./myinst >>out 2>&1)
    for x in xgcc cpp cpp0 tradcpp0 cc1 cc1plus
    do
      test -f host/gcc/gcc/$x || die "make failed: $x not built"
    done
    echo "Building tools (host)..."
    (cd tools;make) || die "make failed"
    (cd tools;make install) || die "make install failed"
  fi

  # Module `sdk'
  if [ -n "$a_sdk" ]
  then
    echo "Installing SDK (host)..."
    (cd tools;make install-sdk) || die "make failed"
  fi

  # Module `host' (second part)
  if [ -n "$host" ]
  then
    echo "Installing libraries (host)..."
    (cd lib;make install) || die "make failed"
    echo "Testing installation (host)..."
    (cd hello;make) || die "make failed"
  fi

  # Module `emx'
  if [ -n "$a_emx" ]
  then
    echo "Building emx: library..."
    (cd lib;make) || die "make failed"
    (cd lib;make sis) || die "make sis failed"
    echo "Building emx: console application..."
    (cd console;make sis) || die "make failed"
    echo "Building emx: tools..."
    (cd tools;make -f Makefile.epoc) || die "make failed"
    (cd tools;make -f Makefile.epoc sis) || die "make sis failed"
    (cd tools;make epoc.imp) || die "make sis failed"
    (cd sis;make emxuser.sis emxdev.sis) || die "make emxuser.sis emxdev.sis failed"
    make_zip emxuser.sis emxdev.sis
    echo "Building emx: estlib..."
    (cd estlib;make) || die "make failed"
  fi
fi

# EPOC modules

if [ -n "$o_i" ]
then
  (cd tools; make -f Makefile.epoc mkdir) || die "mkdir failed"
  if [ -n "$a_emx" ]
  then
    (cd lib; make install-epoc) || die "make failed"
  fi
fi

if [ -n "$mods" ]
then
  test -s SYSTEM || die "unknown system type"
fi

for x in $mods
do
  set_bn $x
  if [ -z "$o_n" ]
  then
    echo "Building module $x ($bn)..."
    spec=false
    if is_special $x
    then
      (build_$x) || die "build_$x failed"
    else
      set_sis $x
      (cd epoc/$x; ./myall $allarg) || die "myall failed"
      (cd sis; make $sis) || die "make $sis failed"
      make_zip $sis
    fi
  fi
  if [ -n "$o_i" ]
  then
    if [ -f epoc/$x/myinst ]
    then
      echo "Installing module $x ($bn)..."
      (cd epoc/$x; ./myinst) || die "myinst failed"
    elif [ -f local/$bn/myinst ]
    then
      # bzip2, gcc, unzip, zip
      echo "Installing module $x ($bn)..."
      (cd local/$bn; ./myinst) || die "myinst failed"
    else
      echo "epoc/$x/myinst is missing -- cannot install module $x ($bn)"
    fi
  fi
done

echo "Done"
