#!/bin/sh
#
# Build-init-2.3.0.sh
#
# Functions/Definitions for Pure LFS Build
# ----------------------------------------
#
# Authors:  Ryan Oliver  (PHA)(ryan.oliver@pha.com.au)
#           Greg Schafer (ZIP)(gschafer@zip.com.au)
#
# Created:  2003-03-07 - Functions and package version definitions common to
#                        build-ch5-x and build-ch6-x moved here.
#
#                      =========================================================
# Modified: 2003-05-14 - Call posix2fixrecursive from unpack_tarballs if
#                        POSIX_CONFORM set to Y in plfs-config.
#                        Wont be run for coreutils.
#                      =========================================================
# Modified: 2003-05-10 - Added 2 functions, posix2fixfile and posix2fixrecursive
#                        The first seds the given input file and changes all
#                        coreutils commands to be POSIX 200112L (ISO/IEC 9945-1)
#                        compliant
#                        The second fixes every file recursively from the
#                        working directory, renaming modified files to -ORIG
#                        and producinq a patchfile of the changes done.
#                      =========================================================
#           2003-05-09 - new function remove_dir removes directories
#                        after succesful package build.
#                        Enabled by specifying REMOVE_PKGDIR=Y in plfs-config
#                        Erik-Jan Post <ej.lfs@xs4all.nl> 
#                      =========================================================
#           2003-05-05 - Split off build options to a seperate file.
#                        These have now gone into 'plfs-config' along with
#                        the package version information.
#                        All configuration should be done there now.
#                      =========================================================
#           2003-05-03 - add option to use --program-suffix during ch6
#                        gcc builds
#                      =========================================================
#           2003-04-20 - Change version number to 2.3.0
#                      - add option to use NPTL 
#                        (beware, only use with CVS glibc)
#                      - split out version information to a separate file
#                        (purelfs-package-versions)
#                      =========================================================
#           2003-04-08 - Change version number to 2.2.7
#                      =========================================================
#           2003-04-03 - Change version number to 2.2.6
#                      - Fix regexp in check_patches/tarballs
#                        (\s)* replaced with [[:blank:]]* to check for preceding
#                        whitespace
#                      =========================================================
#           2003-04-02 - Change version number to 2.2.5
#                      =========================================================
#           2003-03-31 - Change version number to 2.2.4
#                      - Set umask to 0022
#                      - Fix errors due to C'n'P
#                        Nicolas Roeser <n-roeser@gmx.net>
#                      =========================================================
#           2003-03-28 - Change version number to 2.2.3
#                      - Fix output from check_binutils for displaying whether
#                        the '--with-libpath' option is available
#                        Erik-Jan Post <ej.lfs@xs4all.nl>
#                      =========================================================
#           2003-03-27 - Change version number to 2.2.2
#                      - Add forgotten MAKEDEV_VER :-/
#                        Bill Maltby <lfsbill@wlmcs.com>
#                      =========================================================
#           2003-03-24 - Make --enable-version-specific-runtime-libs optional
#                        for final gcc build.
#                        Set USE_VER_SPEC_RT_LIBS to Y to enable this option.
#                      =========================================================
#           2003-03-22 - Change version number to 2.2.2-beta1
#                      - Fixup fubar in output for check_patches.
#                        Martin Imobersteg <imm@gmx.ch>
#                      =========================================================
#           2003-03-17 - Add the option of using coreutils instead of
#                        fileutils, sh-utils and textutils (Set USE_COREUTILS=Y)
#                      - Add the option to skip bootstrap of gcc during the
#                        second build (Set NOBOOTSTRAP=Y )
#                      - gen_pkgname function removed, eval now used to expand
#                        strings sent to apply_patch and unpack_tarball
#                      - Add hacks to get around limitations in check_tarballs
#                        and check_patches (check_pkg_used and check_patch_used)
#                      =========================================================
#           2003-03-11 - Change version number to 2.2.1
#                      - unpack_tarball now
#                        a) checks the tarball to determine where it will 
#                           unpack the package source to. Returns this as the
#                           environment var PKGDIR
#                        b) removes the target directory ( ${PKGDIR} ) before
#                           unpacking the tarball
#                        PKGDIR is now used throughout the script(s) when 
#                        cd'ing into the packages source tree.
#                      - move TZ and LC_ALL here
#                      =========================================================
#           2003-03-08 - Cleaned up and added logging to check_binutils
#                      - Moved package version defs to start
#                      =========================================================
#           2003-03-08 - Added check_binutils function.
#                      - checks the following in binutils
#                        o Makefile.in for 'configure-host' target.
#                          This target needs to be run after configure with HJL
#                          binutils versions.
#                          Sets the env var 'BINUTILS_CONF_HOST' to Y 
#                          if the target exists
#                        o configure for '--with-lib-path' option.
#                          Found in HJL's versions. If available we will use 
#                          this during configure to setup ld's search order.
#                          Sets the env var BINUTILS_WITH_LIB_PATH to "Y" 
#                          if this option is available.
#                        o ld/Makefile.in to ensure the desired ld search order
#                          (stored in LIB_PATH) gets passed into the
#                          environment for genscripts.sh (used for generating
#                          the linker scripts).
#
# Changes concerning functions/defs from build-ch5 scripts pre 2.0.0
#                      =========================================================
# Modified: 2003-03-03 - Updated to glibc 2.3.2
#                      =========================================================
#                      - added definition for SCRIPTS, points at directory
#                        containing the buildscripts.
#                      - Add check_patches ( modified from check_patch supplied
#                        by Ronald Hummelink )
#                      - Add apply_patch for smart patch application
#                        Ronald Hummelink (ronald@hummelink.xs4all.nl) 
#                      - Automate check_tarballs function.
#                      - check_tarballs loops through this list, expanding the 
#                        package names as it goes with the gen_pkname function,
#                        and checking for its existence in ${TARBALLS}
#                      =========================================================
#           2003-03-01 - Logging Enhancements.
#                      - code minimised between max_log_init and min_log_init.
#                      - max_log_init sets LOGFNAME ( passed log with appended
#                        timestamp  eg gcc-init.log-yyyymmdd )
#                      - min_log_init now only takes the log directory as an 
#                        argument. Sets LOGFILE (prepends the log directory
#                        onto LOGFNAME) 
#                      - LOGFILE now used throughout the script as the sole
#                        logging target.
#                      =========================================================
#           2003-02-27 - Added check_tarball routine
#                        Added check_patch routine
#                        Move export of Tcl/Expat/Dejagnu version to beginning
#                        Ronald Hummelink (ronald@hummelink.xs4all.nl) 
#           2003-02-25 - Set shell to utilize glob style matches
#                        (unpack_tarball was broken)
#           2003-02-23 - Add tgz support to unpack_tarball, bugfixes
#                        and fix some more of the logging stuff
#                        Bill Maltby (lfsbill@wlmcs.com) (Thanks Bill)
#           2003-02-20 - Add tarball unpacking function
#           2003-02-13 - Add std log init functions, replace log init
#                        code with new. Shorten logging append code.
#                        Bill Maltby (lfsbill@wlmcs.com)
#           2003-02-05 - Added Logging, numerous enhancements (see hint)
#
# Builds a complete toolchain for compiling and
# linking against a different glibc version.
# Then builds packages required for our final Ch6
# build
#

# Source build options and package versions
. ${SCRIPTS}/plfs-config

# Set your umask
umask 0022

#set shell to allow glob style matches
# ( bash specific )
shopt -s extglob

set +h

######################################################################
# Standard log initialization functions
######################################################################
BRKLN='================================================================================' # Break line


max_log_init() { # $1=pkg $2=vers or text $3=dynam|stat|init|some text
              # $4=<log-directory> $5=<log-filename>

    LOGFNAME="${5}-${DATE}"
    min_log_init ${4} ||
    return 1  # Control in mainline. Chg to exit for bail out!

    echo "### ${1} ${2} - ${3} - ${TS} ###"
    
}

min_log_init() { # $1=<log-directory>
    # If log start fails, error out w/message and return code
    TS=$(date)        # Save a call
    LOGFILE="${1}/${LOGFNAME}"
    echo -e "${SELF} - ${LOGFNAME} - ${TS}\n${BRKLN}" > ${LOGFILE} ||
    {
      echo "min_log_init: writing ${LOGFILE} fail. Space/permissions?" \
        &>/dev/tty
      return 2  # Control in mainline. Chg to exit for bail out!
    }
}


# unpacks the specified package intelligently,
unpack_tarball() { # ${1}=<package-${PACKAGE_VER}>
   local pkgname=${1}
   # Easier add of .tgz

   local archive=`ls -t ${TARBALLS}/${pkgname}.@(tgz|tar.gz|tar.bz2) \
      2> /dev/null | head -n 1`

   test -z ${archive} &&
   {
      echo "unpack_tarball: unable to locate tarball for '${pkgname}' in ${TARBALLS} ... exiting"
      return 1
   }

   case ${archive} in
      *.gz | *.tgz )
         local tarflags="zf"
      ;;

      *.bz2 )
         local tarflags="jf"
      ;;

      * )
         echo "unpack_tarball: unable to determine tarball type... exiting"
         return 1
      ;;
   esac

   # May as well provide a method for passing back the directory the tarball 
   # unpacks to.
   # Should save some trauma when a tarball doesn't extract to where is expected
   # ( usually package-${PACKAGE_VER} but not always... )
   # store in environment as PKGDIR.

   echo -e "\n${BRKLN}"
   echo -n "Checking tarball install directory... "
   export PKGDIR=`tar -t${tarflags} ${archive} | head -n 1 | sed -e 's@^\./@@g' -e 's@/.*$@@g'`

   test -z ${PKGDIR} &&
   {
      echo "Error: unable to determine tarball contents, exiting"
      return 1
   } || {
      echo "${PKGDIR}"
   }

   # If the directory already exists, delete it
   test -d ${PKGDIR} &&
   {
      echo -n "Removing existing ${PKGDIR} directory... "
      rm -rf ${PKGDIR} &&
      {
         echo "DONE"
      } || {
         echo "Error removing ${PKGDIR}... "
         #return 1
      }
   }

   echo "Unpacking ${archive}"
   tar -x${tarflags} ${archive} 2> /dev/null &&
   echo " o ${1} unpacked successfully" ||
   {
      echo "unpack_tarball: unable to unpack tarball ${archive}... exiting"
      return 1
   }

   test "Y" = "${POSIX_CONFORM}" &&
   {
      # Dont run fixes on coreutils
      echo "${PKGDIR}" | grep "coreutils" ||
      # Apply posix fixes (fix deprecated features in head/tail etc
      posix2fixrecursive "${PKGDIR}"
   }
   return 0
}

apply_patch () { # ${1}=<package-${PATCH_VER}> ${2}= patch flag (defaults to -Np1)
   local patchname=${1}
   local patchflags=${2}

   local patch=`ls -t ${PATCHES}/${patchname}.@(patch|patch.gz|patch.bz2) \
      2> /dev/null | head -n 1`

   test -e ${PATCHES}/${patchname} || 
   test -z ${patch} &&
    {
       echo "apply_patch: unable to locate patch '${patchname}' in ${PATCHES} ... exiting"
       exit 1;
    }

   test -z ${patchflags} && patchflags='-Np1'

   case ${patch} in
      *.patch.gz )
         local CAT="zcat"
      ;;
      *.patch.bz2 )
         local CAT="bzcat" 
      ;;
      *.patch )
         local CAT="cat"
      ;;
      * )
         echo "apply_patch: unable to determine patch type... exiting"
         exit 1
      ;;
   esac

   echo "Applying ${patch}"
   
   ${CAT} ${patch} | patch ${patchflags} 2> /dev/null

   if [ "${PIPESTATUS[*]}" = "0 0" ]
   then
      echo " o ${patch} applied successfully"
   else
      echo "apply_patch: unable to apply patch ${patch}... exiting"
      exit 1;
   fi
}

check_binutils () {
   # This should be run immediately after unpack_tarballs for binutils
   # so PKGDIR is set to the right directory

   # Check if this version of binutils requires
   # 'make configure-host'
   echo -e "Checking Binutils features...\n${BRKLN}"
   grep configure-host ${SRC}/${PKGDIR}/Makefile.in > /dev/null 2>&1 &&
      export BINUTILS_CONF_HOST=Y ||
      export BINUTILS_CONF_HOST=N 
   echo -e " o Requires 'make configure-host' ........... ${BINUTILS_CONF_HOST}"

   # Do we have --with-lib-path option to ld/configure 
   grep with-lib-path ${SRC}/${PKGDIR}/ld/configure > /dev/null 2>&1 &&
      export BINUTILS_WITH_LIB_PATH=Y ||
      export BINUTILS_WITH_LIB_PATH=N
   echo -e " o Has '--with-lib-path=' configure option .. ${BINUTILS_WITH_LIB_PATH}\n"

   # Modify ld/Makefile.in if necessary
   grep "GENSCRIPTS = LIB_PATH" ${SRC}/${PKGDIR}/ld/Makefile.in > /dev/null 2>&1 ||
   {
      echo " o adding 'LIB_PATH = \$(LIB_PATH)' to GENSCRIPTS definition"
      echo "   in ld/Makefile.in"
      echo "   ( Passes value of LIB_PATH to genscripts.sh environment"
      echo -e "     for ldscript creation. )\n"

      test -f ${SRC}/${PKGDIR}/ld/Makefile.in-ORIG ||
         cp ${SRC}/${PKGDIR}/ld/Makefile.in \
            ${SRC}/${PKGDIR}/ld/Makefile.in-ORIG
      
      #TODO: fix this sed
      sed 's@^GENSCRIPTS = @GENSCRIPTS = LIB_PATH=\$\(LIB_PATH\) @g' \
         ${SRC}/${PKGDIR}/ld/Makefile.in-ORIG \
         > ${SRC}/${PKGDIR}/ld/Makefile.in
   }
}

check_tarballs () {
   # greps through the either the calling script or the script(s)
   # passed as args for calls to unpack_tarball.
   # This function expects the scripts to be stored in ${SCRIPTS}.
   #
   # It will store the list of packages required in the list PKGS
   # All will have their variable components unexpanded.

   SCRIPTLIST=""
   test ! -z ${@} &&
   {
      ARGS=${@}
      for script in ${ARGS}; do
         test -f ${SCRIPTS}/${script} &&
            SCRIPTLIST="${SCRIPTS}/${script} ${SCRIPTLIST}" ||
            {
               echo "check_tarballs: build script ${SCRIPTS}/${script} not found... skipping" 
            } 
      done
   } || {
      test ! -z ${SELF} &&
      test -f ${SCRIPTS}/${SELF} &&
      SCRIPTLIST=${SCRIPTS}/${SELF}
   }

   test -z ${SCRIPTLIST} &&
   {
      echo "check_tarballs: no build scripts found... exiting"
      exit 1
   }

   # Retrieve package defs from unpack_tarball calls into a list
   local PKGS=$( cat ${SCRIPTLIST} | \
                 grep -E '^[[:blank:]]*unpack_tarball (\w|-)*\${\w*}' | \
                 awk '{print $2}' | sort -u )

   echo -e "\nChecking for required tarballs in ${TARBALLS}\n${BRKLN}"

   # loop through list
   for pkg in ${PKGS} ; do
      # do variable expansion on ${pkg}
      eval pkgname=${pkg}
      # check if this package is used
      check_pkg_used ${pkgname} || continue
      echo -n " o Looking for ${pkgname}... "
      # check for the existence of the tarball
      local archive=`ls -t ${TARBALLS}/${pkgname}.@(tgz|tar.gz|tar.bz2) \
         2> /dev/null | head -n 1`

      test -z ${archive} &&
      {
         echo -e "NOT OK\n   XXXXXX NOT FOUND: Unable to locate tarball for '${pkgname}' in ${TARBALLS} XXXXXX"
         exit 1
      } || 
      echo -e "OK\n   Found: ${archive}"

   done
   echo -e " o ALL OK\n${BRKLN}\n"
}

check_patches () { 
   # greps through the calling script for calls to apply_patch, storing
   # the list of patches required in the list PATCHLIST
   # All will have their variable components unexpanded.

   # Retrieve patch defs from apply_patch calls into a list
   SCRIPTLIST=""
   test ! -z ${@} &&
   {
      ARGS=${@}
      for script in ${ARGS}; do
         test -f ${SCRIPTS}/${script} &&
            SCRIPTLIST="${SCRIPTS}/${script} ${SCRIPTLIST}" ||
            {
               echo "check_patches: build script ${SCRIPTS}/${script} not found... skipping" 
            } 
      done
   } || {
      test ! -z ${SELF} &&
      test -f ${SCRIPTS}/${SELF} &&
      SCRIPTLIST=${SCRIPTS}/${SELF}
   }

   test -z ${SCRIPTLIST} &&
   {
      echo "check_patches: no build scripts found... exiting"
      return 1
   }

   # Retrieve package defs from apply_patch calls into a list
   local PATCHLIST=$( cat ${SCRIPTLIST} | \
                      grep -E '^[[:blank:]]*apply_patch (\w|-)*\${\w*}' | \
                      awk '{print $2}' | sort -u )
   
   echo -e "\nChecking for required patches in ${PATCHES}\n${BRKLN}"

   # loop through list
   for patch in ${PATCHLIST} ; do
      # do variable expansion on ${patch} 
      eval patchname=${patch}
      # check if this is used or not
      check_patch_used ${patchname} || continue

      echo -n " o Looking for ${patchname}... "
      # check for the existence of the patch
      local patchfile=`ls -t ${PATCHES}/${patchname}.@(patch|patch.gz|patch.bz2) \
         2> /dev/null | head -n 1`

      test -z ${patchfile} &&
      {
         echo -e "NOT OK\n   XXXXXX NOT FOUND: Unable to locate patch for '${patchname}' in ${PATCHES} XXXXXX"
         exit 1
      } || 
      echo -e "OK\n   Found: ${patchfile}"

   done
   echo -e " o ALL OK\n${BRKLN}\n"
}

# 20030508 - Added to accomodate posix 200112L
#
posix2fixfile () {
test  -z "${1}" &&
{
   echo "${0}: posix2fixfile: require filename" 1>&2
   return 1
}

# Make file posix2 conformant
#-----------------------------

# TODO: More needs to be done with
#       tail and head ( need to be able to handle -COUNT[bkm] )
sed 's@\(tail\|head\) -\([1-9][0-9]*\)c@\1 -c \2@g;
     s@\(tail\) \(\+[1-9][0-9]*\)c@\1 -c \2@g;
     s@\(tail\|head\) -\([1-9][0-9]*\)l\?@\1 -n \2@g;
     s@\(tail\) \(\+[1-9][0-9]*\)l\?@\1 -n \2@g;
     s@\(expand\) -\([1-9][0-9]*\)@\1 -t \2@g;
     s@\(unexpand\) -\([1-9][0-9]*\)@\1 --first-only -t \2@g;
     s@\(fold\) -\([1-9][0-9]*\)@\1 -w \2@g;
     s@\(split\) -\([1-9][0-9]*\)@\1 -l \2@g;
     s@\(uniq\) -\([1-9][0-9]*\)@\1 -f \2@g;
     s@\(sort\) +\([1-9][0-9]*\) -\([1-9][0-9]*\)@\1 -k \2,\3@g;
     s@\(sort\) +\([1-9][0-9]*\)@\1 -k \2@g;
     s@ od -s@od --strings@g;
     s@ od -w@od --width@g;
     s@pr -S@pr --sep-string@g' ${1}
}

posix2fixrecursive () { # ${1} = direcory

dir="${1}"
test -z "${dir}" &&
{
   dir="."
   patchfile="posix2fixes.diff"
} || {
   patchfile="${1}-posix.patch"
}

# Fixes file from the present directory recursively
# Creates a diff file of all changes
test -f ${patchfile} &&
   rm -f ${patchfile}

editlist=`grep -l -d recurse -E "(head [-+][0-9]|tail [-+][0-9]|sort +[0-9]|expand -[0-9]|unexpand -[0-9]|od -[sw]|pr -S)" ${dir}/* | \
   grep -Ev "(DIST$|[cC]hange[lL]og|README)"`

for file in ${editlist}; do
   test -f ${file}-DIST ||
      cp ${file} ${file}-DIST

   echo "Attempting to fix ${file}"
   posix2fixfile ${file}-DIST > ${file}
   diff -uNr ${file}-DIST ${file} >> ${patchfile}
done

}

# Following two functions are interim hacks for check_patches and
# check_tarballs to get around conditional packages/patches
# these will be revisited

check_patch_used () { 
   # Use to override individual patches, depending on package
   # version
   # Only findutils is here for the moment 
   # (does not req patch for 4.1.7+ )

   case ${1} in
      findutils-4.1 )
         return 0 
      ;;
      findutils-* )
         return 1
      ;;
      zlib-1.1.4-2-vsnprintf )
         test 1.1.4 != "${ZLIB_VER}" && return 1 
      ;;
      tar-1.13* )
         test 1.13 != "${TAR_VER}" && return 1
      ;;
   esac
   return 0
}

check_pkg_used () {
   case ${1} in 
      sh-utils* | textutils* | fileutils* )
         test Y = "${USE_COREUTILS}" && return 1
      ;;
      coreutils* )
         test Y = "${USE_COREUTILS}" || return 1
      ;;
      glibc-linuxthreads* )
         test Y = "${USE_NPTL}" && return 1
      ;;
      nptl-* )
         test Y = "${USE_NPTL}" || return 1
      ;;
   esac
   return 0
}

# remove_dir
remove_dir() { # removes directory ${1}
    test -d ${1} &&
       {
       echo -n "Removing directory ${1}... "
       rm -rf ${1} &&
        {
           echo "DONE"
        } || {
           echo "Nope, couldn't do it"
        }
       }
}


