#!/bin/bash

#####################################################################
# Program: /usr/share/slackdev/buildkit.sh
# Purpose: Provide a sourceable environment for build scripts
#          via ScratchBox or natively
# Author : Stuart Winter <mozes@slackware.com>
# Date...: 17-Jan-2004
#####################################################################
# Caveats:
# [1] This script is full of cruft.  It needs trimming.  If you have
#     any comments or optimisations then please email me.
#     I'm very keen to improve speed where I can because you
#     really *can* feel the difference on my StrongARM RiscPCs!
#####################################################################

# Source in the config file
source /usr/share/slackdev/slackdev.config

# Test if we're using distcc.  This enables setting parallel jobs to
# the number of local cores when a package is incompatible with distcc.
function using_distcc() {
  [ -z "${DISTCC_HOSTS}" ] && return 1 || return 0
}

# Determine whether a function exists:
function fnexists() {
   local estat=1
   type -t $1 >/dev/null && { [ $( type -t $1 ) = "function" ] && estat=0 ;}
   return $estat
}

# Call a function with any supplied arguments, if it exists:
function fnexists_call() {
   local estat=0
   if type -t $1 >/dev/null ; then
      if [ $( type -t $1 ) = "function" ]; then
         # Launch the supplied function name with any arguments, returning the
         # exit value from it:
         echo "Calling build plugin function: $@"
         $@
         return $?
       else
         # Return 0 (non-error) if the function requested doesn't exist.
	 return 0
      fi
   fi
}

# Call a shell function if it exists.
# This enables a build system to supply a bunch of plugin names, and have the build system
# execute a custom function specific to that plugin.
# e.g. within a shell script file plugin named "rk3399", we could have a function called "<pluginname>_prepatch"
# i.e. "rk3399_prepatch"
#
# This would be called by the following function in this way:
# BUILD_PLUGINS="rk3399 bcm2711 others"
# fnexists_multicall "$BUILD_PLUGINS" prepatch
function fnexists_multicall() {
  local plugin_list="$1"    # the full list of plugins
  local call_function="$2"  # e.g. "prepatch"
  local plugin
  # Iterate through the plugin list, calling the specified function. e.g. "rk3399_prepatch"
  for plugin in ${plugin_list}; do
    fnexists_call "${plugin}_${call_function}"
    # We won't return any error status here, as such functions can terminate the build process as they see fit.
  done
}

# Load a plugin's shell script configuration into the build system:
# BUILD_PLUGINS="rk3399 rpi foo"
# Usage: fnexists_loadplugins "${BUILD_PLUGINS}" $PORTCWD/buildplugins
# The loaded plugin file would be named: $PORTCWD/buildplugins/rk3399/rk3399.conf
function fnexists_loadplugins() {
  local plugin
  local plugin_conffile
  for plugin in $1 ; do
     plugin_conffile="${2}/${plugin}/${plugin}.conf"
     if [ -s "${plugin_conffile}" ]; then
       echo "Loading plugin script: ${plugin_conffile}"
       . ${plugin_conffile}
     fi
   done
}

# Kill off daemons and any other processes which tend to modify the contents
# of the file system (creating files, modifying dirs etc).
# The purpose of this is so that when building a package through altertrack, altertrack
# it less likely to detect a file that was not created during the installation routine
# of the software it's building.
function altertrackprep() {
  /etc/rc.d/rc.cups stop > /dev/null 2>&1
  /etc/rc.d/rc.sendmail stop > /dev/null 2>&1
  killall crond > /dev/null 2>&1
}

# From the current directory (presumed to be a linux source tree)
# install the headers into /usr/local/arm where our cross compile
# tool chain lives.
#
# 12-Jul-04: *** This is old rubbish now. Needs to be removed ***
function kernheads() {
  rm -rf /usr/local/arm/include
  mkdir -p /usr/local/arm/include
 # make ARCH=$ARCH menuconfig
 # make ARCH=$ARCH symlinks include/linux/version.h
 # need to edit ARCH=arm and CROSSCOMPILE=arm-linux-
 cp -a include/linux /usr/local/arm/include
 cp -a include/asm-arm /usr/local/arm/include/asm
}

# *** This always needs to positioned AFTER 'slackset_var_cwds' ****
#
# To save on maintenance, and since we carry the same versions as x86 Slackware,
# let's pull the version numbers from the x86 trunk:
function slack_setvarfromupstream() {
   local upstreamvar
   local XSB=$CWD/$PKGNAM.SlackBuild
   pushd $CWD
   [ ! -x $XSB ] && { echo "ERROR: Cannot find x86 SlackBuild for ${PKGNAM}!" ; exit 1; }
   for upstreamvar in $@ ; do
      eval $( grep -E "^${upstreamvar}=" $XSB  )
      echo "Upstream variable: ${upstreamvar} version $( eval $( echo "echo \$${upstreamvar}" ) )"
   done
   popd
}

# Determine ARM architecture
# "arm" = ARMv7 hard float
# aarch64 = ARM 64 bit
function slack_archtype() {
  if [ ! -z "$( readelf -h /usr/bin/readelf | grep -E 'Machine:.*AArch64' )" ]; then
     export ARCH=aarch64
     export LIBDIRSUFFIX="64"
     # Autoconf settings for --host, --build, --target
     export SLK_ARCH_HOST="$ARCH-slackware-linux-gnu"
     export SLK_ARCH_BUILD="$ARCH-slackware-linux-gnu"
     # Used by gcc, binutils and llvm.
     export SLK_ARCH_TARGET="$ARCH-slackware-linux-gnu"
   else
     export ARCH=arm
     export LIBDIRSUFFIX=""
     # Autoconf settings for --host, --build, --target
     export SLK_ARCH_HOST="$ARCH-slackware-linux-gnueabihf"
     export SLK_ARCH_BUILD="$ARCH-slackware-linux-gnueabihf"
     # Used by gcc, binutils and llvm.
     export SLK_ARCH_TARGET="$ARCH-slackware-linux-gnueabihf"
 fi
}

# Utilize /dev/shm if more than 8GB of RAM is available.
# This assumes /dev/shm is mounted without the 'noexec' option, which
# is not the default configuration for Slackware, but it's adjusted for
# Slackware ARM build hosts.
# Utilizing /dev/shm speeds up builds significantly and reduces wear on storage.
# This feature is supported on machines with ample RAM, such as the HoneyComb LX2.
# Caution: Running this command will clear the root of /dev/shm/buildtmp,
# preventing simultaneous builds of packages that utilise this function
# to set the temporary build location.
# This limitation arises due to the absence of cleanup routines in most,
# if not all, Slackware ARM build scripts, necessitating pre-emptive
# clearing of the entire area.
# While storage capacity is typically ample, with tens or hundreds of GBs
# available, RAM storage is more constrained.
function shm_tmp() {
   local shmtmpbuilddir=/dev/shm/buildtmp
   if ! findmnt -o options /dev/shm | grep -q noexec; then
      rm -rf ${shmtmpbuilddir} # needs removing first due to no cleanup in build scripts
      [ $( df --output=avail /dev/shm | tail -n1 ) -gt $((8 * 1024 * 1024)) ] && {
         echo "Sufficient RAM available: using /dev/shm for temporary storage"
         export TMP=${shmtmpbuilddir} # this overrides the setting in /usr/share/slackdev/slackdev.config
         mkdir -vpm755 $TMP ;}
   fi
}

# Delete and re-create package temporary directories
function mkpkgdirs() {
  echo -n "Preparing build area: cleansing; "
  rm -rf $TMPBUILD $PKG
  echo -n "creating; "
  mkdir -pm755 $TMPBUILD $PKG
  echo -n "cd $TMPBUILD "
  cd $TMPBUILD
  echo "... done"
}

# Apply Debian patch set.
# Normally we wouldn't want to do this entirely but it can be
# helpful when testing builds:
function apply_full_debian_patches() {
#  grep -Ev "^#|^$" debian/patches/series | awk '{print $1}' | while read patchfile ; do
   find debian/patches -type f -printf "%f\n" | while read patchfile ; do
    if [ -s "debian/patches/$patchfile" ]; then
        # Most patches should not require more levels than this:
        success=0
        for (( pl=0 ; pl<=5 ; pl++ )) ; do
            echo "Patch : $patchfile , trying patch level $pl"
            patch -N --fuzz=20 -t --dry-run -p$pl < debian/patches/$patchfile > /dev/null 2>&1 && success=1 && break
        done
        if [ $success = 1 ]; then
           echo "Patch: $patchfile will apply at level $pl"
           patch -N --fuzz=20 --verbose -p$pl < debian/patches/$patchfile
         else
          echo "Patch: $patchfile failed to apply"
        fi
     fi
  done
}

# GNU autotools stuff
# If there's no ./configure but there's an autogen, build the confgiure;
# otherwise force a reconfiguration and script rebuild.
# This is the original code:
#if [ ! -r configure ]; then
#  if [ -x ./autogen.sh ]; then
#    NOCONFIGURE=1 ./autogen.sh
#  else
#   autoreconf -vif
#  fi
#fi
function slack_autotoolsprep() {
#   [ ! -r configure ] && { [ -x ./autogen.sh ] && ./autogen.sh || autoreconf -vif ;}
   if [ ! -r configure ]; then
      if [ -x ./autogen.sh ]; then
         ./autogen.sh
        else
         autoreconf -vif
      fi
   fi
}

# Automatically unpack patches and determine patch level, and apply:
function auto_apply_patch () {
 local patchfile=$1
 # Original patch file name:
 local origpatchfile="${1##*/}"

 echo
 echo "***********************************************************"
 echo "** Working on Patch: $patchfile"
 echo "***********************************************************"
 echo

 # Decompress the patch if it's compressed with a known method:
 FTYPE=$( file $patchfile )
 case "$FTYPE" in
    *xz*compressed*)
        xz -dc $patchfile > $TMPBUILD/$(basename $patchfile).unpacked
        patchfile=$TMPBUILD/$(basename $patchfile).unpacked ;;
    *bzip2*compressed*)
        bzcat -f $patchfile > $TMPBUILD/$(basename $patchfile).unpacked
        patchfile=$TMPBUILD/$(basename $patchfile).unpacked ;;
    *gzip*compressed*)
        zcat -f $patchfile > $TMPBUILD/$(basename $patchfile).unpacked
        patchfile=$TMPBUILD/$(basename $patchfile).unpacked ;;
 esac

 # By now the patch is decompressed or wasn't compressed originally.
 #
 # Most patches should not require more levels than this:
 success=0
 for (( pl=0 ; pl<=5 ; pl++ )) ; do
    # Some patches don't work with --dry-run, so we can suffix the patch
    # level to the file name: e.g. 'foo-fix.patch.xz_p1'
    [[ ${origpatchfile: -2} =~ p[0-9] ]] && {
       pl="${origpatchfile: -1}"
       echo "Hard coded patch level found: ${pl}"
       success=1
       break ;}
    echo "Patch : $patchfile , trying patch level $pl"
    patch -N --fuzz=20 -t --dry-run -lp$pl < $patchfile > /dev/null 2>&1 && success=1 && break
 done
 if [ $success = 1 ]; then
    echo "Patch: $patchfile will apply at level $pl"
    patch -N --fuzz=20 --verbose -lp$pl < $patchfile
    return 0
  else
    echo "Patch: $patchfile failed to apply at levels 0-5"
    return 1
 fi
}

# Reduce changelog size:
# Syntax: changelogliposuction <filename> <package name> <version>
# This allows change log reduction when there are more than one app
# bundled into a package.
function changelogliposuction() {
  # If there's a ChangeLog, installing at least part of the recent history
  # is useful, but don't let it get totally out of control:
  if [ -r $1 ]; then
     echo "Liposuction on $PKG/usr/doc/$2-$3/$1"
     DOCSDIR=$(echo $PKG/usr/doc/$2-$3)
cat << EOF > $DOCSDIR/$1
$( head -n1000 $1)
[--snip--]
EOF
   touch -r $1 $DOCSDIR/$1
fi
}

# Record toolchain & some other info (useful to see in build logs)
function slackbuildinfo() {
echo "------------------------------------------------------------"
echo "Build starting on.....: $( date )"
echo "Build host............: $( uname -a )"
echo "Building for arch.....: $ARCH"
echo "Building as UNIX user : $( whoami ) on $( tty )"
echo "------------------------------------------------------------"
echo "Toolchain & development tools information"
echo "------------------------------------------------------------"
echo "glibc .....: $( /lib${LIBDIRSUFFIX}/libc.so.6  | head -n1 | grep -o 'version [0-9.]*' )"
echo "binutils ..: $( ld --version | head -n1 | rev | cut -d' ' -f1 | rev )"
echo "libtool ...: $( libtool --version | head -n1 )"
echo "GCC .......: $( gcc --version | head -n1 )"
echo "GCC-C++ ...: $( g++ --version | head -n1 )"
[ -x /usr/bin/clang ] && \
echo "llvm/clang : $( clang --version | head -n2 | xargs )"
echo "GNU make ..: $( make --version | head -n1 )"
echo "cmake .....: $( cmake --version | head -n1 )"
echo "automake ..: $( automake --version | head -n1 )"
echo "Perl ......: $( perl --version | grep -i "this is" )"
[ -x /usr/bin/python2 ] && \
echo "Python2 ...: $( python2 --version 2>&1 | head -n1 )"
[ -x /usr/bin/python3 ] && \
echo "Python3 ...: $( python3 --version 2>&1 | head -n1 )"
[ -x /usr/bin/ruby ] && \
echo "ruby ......: $( ruby --version | head -n1 )" || { echo "not installed" ; }
[ -x /usr/bin/meson ] && \
echo "meson .....: $( meson --version | head -n1 )" || { echo "not installed" ; }
[ -x /usr/bin/rustc ] && \
echo "rust.......: $( rustc -vV | grep -E '^release|^host|^LLVM' | xargs )" || { echo "not installed" ; }

echo "------------------------------------------------------------"
}

# ARM: Reinstall the default /targets/ARM -- clean our file system
# This function is only meant to be run from within scratchbox - ie not
# on a machine with an ARM processor.
function sboxsysrestore() {
 # Regardless of whether we're inside sbox or native, /install has to go
 # otherwise if we rebuild the same package twice, slack-desc runs the risk of
 # being ignored. You don't build packages that use .build scripts anyway.
 rm -rf /install

 if [ -d /targets/ARM -a -s $HOME/armedslack-current/source/slackdev/cleanfs/cleanfs*bz2 ]; then
    ( echo "Reinstalling the default /targets/ARM"
      cd /targets/
      chmod -R u+rwx ARM
      rm -rf ARM
      tar jxf $HOME/armedslack-current/source/slackdev/cleanfs/clean*bz2

      # re-install the Slackware passwd & group.
      # I need to remember to keep this up todate with the 'etc' package.
      ( cd $HOME/armedslack-current/source/slackdev/installdata
        cp -fa passwd shadow group /etc )

      # This is now in a Separate slackware devkit ('slackkit') but it's just
      # as easy to do this inside scratchbox:
      mkdir -p /usr/share
      ln -fs $HOME/armedslack-current/source/slackdev /usr/share/slackdev

      # Delete the Linux 2.6 headers because these cause things to break
      # This won't be necessary in future.  Probably. Hopefully.
      #echo "deleting SB's 2.6 headers;"
      #rm -rf /usr/include/{linux,asm,asm-generic}
      # Having the Linux Kernel headers installed is also a must (and they replace those we just rm -rf'd)
      #echo ${PKGSTORE}/d/kernel-headers*.t?z
      #if [ -s ${PKGSTORE}/d/kernel-headers*.t?z ]; then
      #   installpkg ${PKGSTORE}/d/kernel-headers*.t?z
      #  else
      #   read -p "Cannot find ${PKGSTORE}/d/kernel-headers*.t?z. There may be problems."
      #fi

      # Ensure target arch is ARMv3
      # perl -pi -e 's?^-D__ARM_ARCH_4T__?-D__ARM_ARCH_3__?;' /lib/gcc-lib/arm-linux/3.3.2/specs
       )
   else
      echo "Scratchbox not detected; not cleansing the OS"
 fi
}

# ARM: Find ldrh & strh instructions in all files
# These instructions cause problems with the StrongARM RiscPC
# and as such, we don't want our package to contain any binaries.
# The fix is to compile for the armv3.
# However, we occasionally find false positives: -- Jim Hawkins
# Well, if you pipe the objdump -d into less and search for them using the same rexep as
# grep -E you'll notice that they often come write at the very end of a section.
# It just takes each 32-bit instruction and decodes it; it doesn't know if it's actually an
# instruction or not.
# Although this data is different from actual data. The executable is split into several
# different bits. The most important are the ".text" and the ".data" sections. The .text is the
# code and the .data is data. But because of the way the ARM works it can't encode certain
# numeric values, so it stores them alongside the actuall instructions and uses a load
# instruction to use the value. BBC BASIC assembler reports "Bad immediate constant"
# when it can't encode them into an instruction, which you might have seen.
# So that's why you end up with data in the code section of the executable.
#
# Question: Why don't I optimise using -march=armv3m as suggested here:
#           http://groups.google.com/groups?selm=199905201007.LAA01988%40sun52.NIS.cambridge&output=gplain
#           It's because when I tried it, gcc choked.  If you find that stuff does compile
#           with it then please let me know, but I don't have time to wait for things to fail.
# --
function shortwords() {
echo "No longer checking shortwords - it's not neceessary"
#  local FOO
#  echo "Searching for half word instructions"
#  find . -type f \( -perm -100 -o -perm -010 -o -perm -001 \) | while read file ; do
#  if [ ! -z "$( file $file | grep -E '(ELF.*)' | cut -d: -f1 | xargs objdump -d | awk '{print $3}' | grep -E '(str|ldr)(\w\w)?h$' )" ]; then
#      echo "Shortwords in $file"
#  fi
#done
}

# This thing doesn't work with shopt turned on so we call it as a separate script.
function slackmp () {
 /usr/share/slackdev/slackmakepkg $@
}

# Refresh to support latest architectures:
function slackupdatelibtool() {
  find . -name config.guess -print0 | xargs -0i cp -favv /usr/share/libtool/build-aux/config.guess '{}'
  find . -name config.sub -print0 | xargs -0i cp -favv /usr/share/libtool/build-aux/config.sub '{}'
}

# gzip info and man pages and fix any resulting broken symlinks.
# This code is taken from slacktrack
# Syntax: gzpages [-i]
# where -i deletes usr/info/dir if it exists.  For everything other than
# the texinfo package you'll want to do this.
function slackgzpages() {

local MPLIST ILIST

  if [ "${1}" = "-i" ]; then
     rm -vf usr/info/dir
  fi

  MPLIST="/usr/man /usr/local/man /usr/X11R?/man /opt/kde/man"
  echo -n "gzipping (and removing zero size) man pages in $PWD"
  for man_dir in ${MPLIST}; do
      if [ -d "./${man_dir}" ]; then
         # Remove any zero length man pages:
         ( find ./${man_dir} -type f -size 0 -exec rm "{}" \; ) >/dev/null 2>&1
         # Decompress to maintain consistency:
         ( find ./${man_dir} -type f -name '*.bz2' -print0 | xargs -0 bzip2 -df ) >/dev/null 2>&1
         ( find ./${man_dir} -type f -name '*.gz' -print0 | xargs -0 gunzip -f ) >/dev/null 2>&1
         ( find ./${man_dir} -type f -name '*.xz' -print0 | xargs -0 xz -df ) >/dev/null 2>&1
         # Compress:
         ( find ./${man_dir} -type f -print0 | xargs -0 gzip -9f   ) >/dev/null 2>&1
         ( find ./${man_dir} -type f -print0 | xargs -0 chmod 644 ) >/dev/null 2>&1
      fi
   done
   echo " ... done"

 echo -n "Fixing any broken symlinks in man page directories in $PWD"
 for man_dir in ${MPLIST}; do
     if [ -d "./${man_dir}" ]; then
        ( cd ./${man_dir}
        # Enter each man page directory (man1,man2..) and whittle them down one by one
        for i in $( find . -type d -maxdepth 1 -printf "%P\n" | grep -v "^$" ); do
            cd ${i} && ( find . -type l -not -name '*.gz' -printf "rm -f %P ; ln -s %l.gz %p.gz\n" ) | /bin/bash && cd ..
        done )
     fi
 done
 echo " ... done"


 ILIST="/usr/info /usr/local/info"
 echo -n "gzipping info pages in $PWD"
 for info_dir in ${ILIST}; do
     if [ -d "./${info_dir}" ]; then
        ( find ./${man_dir} -type f -name '*.gz' -print0 | xargs -0 gunzip -f ) >/dev/null 2>&1
        ( find ./${info_dir} -type f -name '*.bz2' -print0 | xargs -0 bzip2 -df ) >/dev/null 2>&1
        ( find ./${info_dir} -type f -print0 | xargs -0 gzip -9f   ) >/dev/null 2>&1
        ( find ./${info_dir} -type f -print0 | xargs -0 chmod 644 ) >/dev/null 2>&1
     fi
 done
 echo " ... done"

 echo -n "Fixing any broken symlinks in info page directories"
 for info_dir in ${ILIST}; do
    if [ -d "./${info_dir}" ]; then
       ( cd ./${info_dir} && ( find . -type l -printf "rm -f %P ; ln -s %l.gz %p.gz\n" ) | /bin/bash )
    fi
 done
 echo " ... done"

}

# Determine whether we're building for /patches within a Stable Release, or
# whether we're in -current.
# The script's calling pwd needs to contain /patches/source, otherwise it's
# considered to be slackware-current:
function slack_findpkgstore_is_stablerelease() {
  # Determine if we're building within /patches:
  #if pwd | grep -Fq "/patches/source" -a ; then
  # Check what the Slackware upstream src dir is set to. If it's not -current, it's a stable release.
  if [[ ! "$SLACKSOURCE" =~ (-current) ]] ; then
     export SLACKPATCHING=yes
     return 0
   else
     export SLACKPATCHING=no
     return 1
  fi
}

# Strip shared object with the longest line ever ;-)
function slackstripso() {
 echo -n "Stripping unstripped ELF shared objects in $PWD"
 for i in /usr/lib /lib /usr/local/lib; do
  ( cd ./${i} && find . -name '*.so*' -type f \( -perm -100 -o -perm -010 -o -perm -001 \) -print0 | xargs -0 file | grep -E '(ELF.*shared.*not stripped)' | awk -F: '{print $1}' | xargs strip -p --strip-unneeded ) > /dev/null 2>&1
 done
 echo " ... done"
}

# Strip .a (archive) files:
function slackstripar() {
 echo -n "Stripping .a (archive) files in $PWD"
 ( find . -name '*.a' -type f -print0 | xargs -0 strip -p -g ) > /dev/null 2>&1
 echo " ... done"
}


# Strip binaries:
function slackstripbin() {
 echo -n "Stripping unstripped ELF binaries in $PWD"
 for i in /bin /sbin /usr/sbin /usr/bin /usr/local/bin /usr/local/sbin /usr/X11R?/bin; do
  ( cd ./${i} && find . -type f \( -perm -100 -o -perm -010 -o -perm -001 \) -print0 | xargs -0 file | grep -E '(ELF.*not stripped)' | awk -F: '{print $1}' | xargs strip -p --strip-unneeded ) >/dev/null 2>&1
 done
 echo " ... done"
}

# Strip everything?  This does the same as the above but instead it does it across
# the entire package directory -- therefore it finds stuff in /opt and anywhere else
# that files have been created.  You may prefer to use this option if you already use -jkA
# but it's worth noting that it will take longer (especially on a package with many files
# in a deep directory structure)
function slackstripall() {
 echo -n "Stripping all unstripped executable ELF files in $PWD"
  ( find . -type f \( -perm -100 -o -perm -010 -o -perm -001 \) -print0 | xargs -0 file | grep -E '(ELF.*not stripped)' | awk -F: '{print $1}' | xargs strip -p --strip-unneeded ) >/dev/null 2>&1
  # Strip the .a archives
  ( find . -name '*.a' -type f -print0 | xargs -0 strip -p -g ) > /dev/null 2>&1
  echo " ... done"
}

# Remove rpaths:
function slackstriprpaths() {
  local rpfile
  for rpfile in $(find . | xargs file | grep -e "executable" -e "shared object" | grep ELF | cut -f 1 -d : 2> /dev/null) ; do
    if [ ! "$(patchelf --print-rpath $rpfile 2> /dev/null)" = "" ]; then
       patchelf --remove-rpath $rpfile
    fi
  done
}

# chown root.bin stuff
# As of Slackware 11, we don't do root:bin anymore.
# This function is no longer required, but remains for the operability
# with older source trees.
function slackchown() {
 local dr
 echo -n "Setting root:root ownerships in $PWD"
 chmod 755 . # set pkg's root dir to the correct permission just incase
 # Handle coreutils 5.2.1's chown not perserving setuid bits:
 ( for dr in sbin bin usr/sbin usr/bin usr/local/sbin usr/local/bin usr/X11R?/bin ; do
#   ( cd ${dr} && chown root:root . && find . -type f -printf "chown root:bin '%p' && chmod %m '%p'\n" | bash )
   ( cd ${dr} && chown root:root . && find . -type f -printf "chown root:root '%p' && chmod %m '%p'\n" | bash )
   done ) > /dev/null 2>&1
 echo " ... done"
}

# Fix up duff ownerships & permissions in source balls
# This list has been compiled from various Slackware build scripts.
function slackhousekeeping() {
echo -n "Setting sane ownerships & permissions in $PWD"
(  chown -R root:root .
   chmod -Rf a-s,a+rX,u+w,g-w,o-w .
) > /dev/null 2>&1
echo " ... done"
}

# chmod 644 doc files and doc dirs
function slack644docs() {
 echo -n "Running chmod 644 over documents in usr/doc/ inside $PWD"
 ( find usr/doc/ -type f -print0 | xargs -0 chmod 644 ) >/dev/null 2>&1
 ( chown -R root:root usr/doc/ ) >/dev/null 2>&1
 ( find usr/doc -type d -print0 | xargs -0 chmod 755 ) >/dev/null 2>&1
 echo " ... done"
}

# Find hard links and also embedded temporary build paths
function slackhlinks() {
  echo "Scanning for hard links in $PWD"
  find . -type f -links +1 -printf "Hard link: %P\n"
  echo "Scanning for temporary embedded build paths in $PWD"
  grep -FHlr $TMPBUILD . | xargs strings -f | grep -F $TMPBUILD
}

# Check if we have any package dependencies.  This is a lame way of doing it and
# possibly proves nothing, but it saves me writing it in a few build scripts that
# would otherwise fail when they haven't got package X installed.
function slackcheckpkgdeps () {
local error pack
# Change comma separated input into spaces and consider them one by one
for pack in $( echo ${1} | sed s/,/\ /g ); do
  slack_is_package_installed "${pack}"
  if [ $? -eq 0 ]; then
     echo "Dependency Slackware package '${pack}' not installed"
     error=y
  else
     echo "Dependency Slackware package '${pack}' is installed. OK!"
  fi
done
if [ ! -z "${error}" ]; then
   echo "Error: Package dependencies failed"
   # In some cases where we're bootstrapping, or merging in a huge number of 'Added' packages,
   # we hit package circular dependencies, and many packages fail to initially even attempt to be built.
   # Therefore, r2b offers the option --ignore-prebuild-deps to permit the first 10 or so build passes.
   if [ "$R2BIGNOREPREBUILDDEPS" = "Yes" ]; then
      echo "Ignoring dependency failure due to runtime configuration"
     else
      echo "Enforcing dependency failure"
      return 1
   fi
fi
}

# Function to retrieve the package name.
# glibc-solibs-2.2-i386-1.t?z = glibc-solibs
function slack_tgz2package_name () {
  echo $1 | rev | cut -d- -f4- | rev
}

# Exit if a package is installed.  The purpose of this function is
# to prevent packages from being compiled against others that they should
# not be compiled against (to avoid an unwanted dependency).
function slackfailpkgdeps () {
local error pack
for pack in $( echo ${1} | sed s/,/\ /g ); do
  slack_is_package_installed "${pack}"
  if [ $? -eq 0 ]; then
     echo "Slackware package '${pack}' not installed.  OK!"
   else
     error=y
  fi
done

if [ ! -z "${error}" ]; then
   echo "Error: Found unwanted package(s) installed"
   # In some cases where we're bootstrapping, or merging in a huge number of 'Added' packages,
   # we hit package circular dependencies, and many packages fail to initially even attempt to be built.
   # Therefore, r2b offers the option --ignore-prebuild-deps to permit the first 10 or so build passes.
   if [ "$R2BIGNOREPREBUILDDEPS" = "Yes" ]; then
      echo "Not removing installed package due to runtime configuration"
     else
      echo "Unwanted Slackware package '${pack}' is installed"
      return 1
   fi
fi


}

# Function to determine whether a supplied package name is already installed
# Returns 0 if not installed, 1 if installed.
# This function allows us to specify 'autoconf' for example, without having
# to worry about the version number installed (unless you specifically want to,
# in which case specify the version number as well - e.g. autoconf-2.54)
function slack_is_package_installed () {
  local PACKAGENAME="$1"
  local installed_package

  # We have to go through each package like this (rather than just do if -f foobar-*
  # because otherwise packges such as glibc, glibc-solibs and so on get wildcarded
  # and things get confused.
   for installed_package in $( find /var/log/packages/${PACKAGENAME}-* -type f -printf "%f\n" 2>/dev/null ) ; do
       installed_package="$( slack_tgz2package_name ${installed_package} )"
       if [ "${installed_package}" = "${PACKAGENAME}" ]; then
           return 1 # the package 'short' name is installed
           break
       fi
   done
return 0
}

# Defaults for everything.  You WON'T always want to do this
# but in the main it's probably ok.
function slackslack() {
 local scansetuid=0
 echo -n "Running chmod -R og-w & chown -R root:root . in $PWD "
 chmod 755 . # set pkg's root dir to the correct permission just incase
 # For certain packages such as the Kernels, we have no setuid binaries.
 # As such, we can use chown directly.
 scansetuid=$( find . -type f -perm /4000 -print -quit | wc -l 2>/dev/null )
 if [ $scansetuid -eq 0 ]; then
    # No setuid binaries were found within the package, so we can
    # use fast mode:
    echo "[fast mode]"
    chown -R root:root .
   else
    # setuid binaries found, so we need to preserve the mode.
    # non-root ownerships are set within the SlackBuild explicitly.
    echo "[setuid preservation mode]"
    # Handle coreutils 5.2.1's chown not perserving setuid bits:
    ( find . -type f -printf "chown root:root '%p' && chmod %m '%p'\n" | bash )
 fi
 ( chmod -R og-w . ) > /dev/null 2>&1

# Since we're chown root:root across the entire package, there's no need
# to call 'slackchown'.  Originally this was to set the cosmetic 'root:bin'
# ownerships in Slackware v11 and earlier.
# slackchown
 slack644docs
 if [ -d usr/lib${LIBDIRSUFFIX} ]; then
    echo 'Running chmod 755 for usr/lib${LIBDIRSUFFIX}/lib*.so*'
    chmod 755 usr/lib${LIBDIRSUFFIX}/lib*.so*
 fi
 if [ -d lib${LIBDIRSUFFIX} ]; then
    echo 'Running chmod 755 over lib${LIBDIRSUFFIX}/lib*.so*'
    chmod 755 lib${LIBDIRSUFFIX}/lib*.so*
 fi
}

# Remove the set uid bit on everything
# You won't generally want to do this
function slacknosuid() {
 echo -n "Running chmod -R -s"
 ( chmod -R -s . ) > /dev/null 2>&1
 echo " ... done"
}

# Function to find Intel binaries.  You never know when
# cross compiling, even within scratchbox.
function slackx86() {
#if [ -d /scratchbox ]; then
   echo "Scanning for any x86 binaries in $PWD"
   exec 3<&0
    find . -type f -print | while read file ; do
     ( file grep | grep "Intel.*86" ) > /dev/null 2>&1
       if [ $? -eq 0 ]; then
          read -p "ERROR: Found Intel x86 file '${file}' ; press <ENTER>" <&3
       fi
    done
   exec 3<&-
# else
#  echo "Scratchbox not detected - not scanning for x86 binaries"
#fi
}

# Function to install the new package.  Note that this uses
# removepkg first.  This is DANGEROUS.  Don't use this in anything
# other than a simulated environment.
# If you're really keen to install the new package, I suggest that you
# replace the installpkg command with upgradepkg.
function slackipkg() {
 if [ -z "${PKGSERIES}" ]; then
    echo "Syntax: slackipkg <pkg_series_dir_name>"
  elif [ -s $PKGSTORE/$PKGSERIES/$PKGNAM-${VERSION}-${PKGARCH}-${BUILD}.t?z ]; then
    removepkg $PKGNAM > /dev/null 2>&1
    installpkg $PKGSTORE/$PKGSERIES/$PKGNAM-${VERSION}-${PKGARCH}-${BUILD}.t?z
 fi
}

# Install the slack-desc & doinst file from the slack source tree into
# the $PKG's /install
function slackdesc() {
  echo "Installing install/slack-desc"
  mkdir -pm755 install > /dev/null 2>&1
  if [ -f $PORTCWD/slack-desc ]; then
     echo "Installing slack-desc from $PORTCWD"
     install -vpm644 $PORTCWD/slack-desc install/
   else
     # Install the version from the official Slackware source tree:
     # We need to do it in this order to handle symlinked package sources:
     if [ -f $CWD/slack-desc.$PKGNAM ]; then
        echo "Installing slack-desc.$PKGNAM from $CWD"
        install -vpm644 $CWD/slack-desc.$PKGNAM install/slack-desc
      elif [ -f $CWD/slack-desc ]; then
        echo "Installing slack-desc from $CWD"
        install -vpm644 $CWD/slack-desc install
     fi
  fi
  if [ -s ${CWD}/doinst.sh.gz ]; then
     echo "Installing gzipped doinst.sh from $CWD"
     ( set -x ; zcat ${CWD}/doinst.sh.gz >> install/doinst.sh ) > /dev/null 2>&1
elif [ -s ${CWD}/doinst.sh ]; then
     echo "Installing doinst.sh from $CWD"
     ( set -x ; cat ${CWD}/doinst.sh >> install/doinst.sh ) # > /dev/null 2>&1
#     install -vpm644 ${CWD}/doinst.sh install > /dev/null 2>&1
elif [ -s ${PORTCWD}/doinst.sh ]; then
     echo "Installing doinst.sh from $PORTCWD"
#     install -vpm644 ${PORTCWD}/doinst.sh install/
     ( set -x ; cat ${PORTCWD}/doinst.sh >> install/doinst.sh ) # > /dev/null 2>&1

elif [ -s ${PORTCWD}/doinst.sh.gz ]; then
     echo "Installing gzipped doinst.sh from $PORTCWD"
     ( set -x ; zcat ${PORTCWD}/doinst.sh.gz >> install/doinst.sh ) #  > /dev/null 2>&1
  fi
}

# Function to ensure base system packages are installed.
# This is intended for use when compiling inside Scratchbox. Otherwise
# things build against Scratchbox's stuff, which isn't compiled for ARMv3.
#
# Obviously there are other glaringly obvious packages that should be
# installed but I'm assuming that you have these installed already;
# but I'm always open to suggestions, but don't suggest things like
# procps, coreutils -- without those the system wouldn't be running ;-)
# (but you may see that in some build scripts (tin's spring to mind),
#  I do ensure procps is installed but this is only required when
#  building inside Scratchbox)
#
# I strongly suggest installing all of the d/ package series.
#
function slackbasedeps() {
  # aaa_base contains the main directory structure.  Without it things like openssh
  # need to be force fed /var/run because the configure script can't find it:
  slackcheckpkgdeps aaa_base      || installpkg ${PKGSTORE}/a/aaa_base-*.t?z
  # having an ARM bash tends to upset scratchbox 0.9.8/qemu.
  #slackcheckpkgdeps bash          || installpkg ${PKGSTORE}/a/bash-*.t?z
  #
  if [ ! -d /scratchbox ]; then
     # Bash is linked against libtermcap:
     # termcap removed in post Slackware 14.2
     # slackcheckpkgdeps libtermcap    || installpkg ${PKGSTORE}/l/libtermcap-*.t?z
     #
     slackcheckpkgdeps sed           || installpkg ${PKGSTORE}/a/sed-*.t?z
     slackcheckpkgdeps gawk          || installpkg ${PKGSTORE}/a/gawk-*.t?z
     # Needed to build documentation:
     slackcheckpkgdeps groff         || installpkg ${PKGSTORE}/ap/groff-*.t?z
     slackcheckpkgdeps texinfo       || installpkg ${PKGSTORE}/ap/texinfo-*.t?z
     # No system should be without Perl:
     slackcheckpkgdeps perl          || installpkg ${PKGSTORE}/d/perl-*.t?z
     # Needed to build anything:
     slackcheckpkgdeps binutils      || installpkg ${PKGSTORE}/d/binutils-*.t?z
     # Needed for creating makefiles & configure scripts:
     slackcheckpkgdeps autoconf      || installpkg ${PKGSTORE}/d/autoconf-*.t?z
     slackcheckpkgdeps automake      || installpkg ${PKGSTORE}/d/automake-*.t?z
     # Lots of things need pkg-config these days:
     slackcheckpkgdeps pkg-config     || installpkg ${PKGSTORE}/d/pkg-config-*.t?z
  fi
  # Needed to build message files:
  slackcheckpkgdeps gettext-tools || installpkg ${PKGSTORE}/d/gettext-tools-*.t?z

  # And last but certainly not least, what would we do without glibc? :-)
  # This check is for Scratchbox, mainly.  Obvously you're going to have glibc
  # installed on a native ARMedSlack box!
  # (note that it's the 'glibc' package rather than 'glibc-solibs')
  slackcheckpkgdeps glibc || installpkg ${PKGSTORE}/l/glibc-[0-9]*-*.t?z
  slackcheckpkgdeps glibc || exit 99
  # We don't bail out of if we can't install the others because they're
  # not always necessary, plus if we haven't already built bash, libtermcap & friends
  # then we find ourselves in a catch 22 situation.
  # I did think about separating these out into different functions but I prefer it
  # this way.
}


# Some default error messages. Eventually the exit values will be used by an auto builder.
# Maybe anyway - that's the idea.
function failconfig()  { echo "${PACKAGE}: failed configure $1" ; exit 100 ; }
function failmake()    { echo "${PACKAGE}: failed make $1" ; exit 101 ; }
function failtest()    { echo "${PACKAGE}: failed test $1" ; exit 102 ; }
function failinstall() { echo "${PACKAGE}: failed install $1" ; exit 103 ; }
function failextract() { echo "${PACKAGE}: failed to extract source $1" ; exit 105 ; }
function failpatch()   { echo "${PACKAGE}: failed to patch source $1" ; exit 106 ; }
function faildocs()    { echo "${PACKAGE}: failed to install docs $1" ; exit 107 ; }
function failmisc()    { echo "${PACKAGE}: failed for some non descript reason $1" ; exit 108 ; }

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

# This is our architecture & our CFLAGS
# Exports variable "ARCH"
slack_archtype

# Set the variables - $CWD and $PORTCWD
# Handle building in /patches
function slackset_var_cwds() {
  # The ARM source repository - normally source/<series name>/<pkgname>
  # This function assumes that you're building within that directory.
  export PORTCWD=$PWD

  # Paths to skeleton port's source & real Slackware source tree:
  # Build directory for -current:
  export CWD=$SLACKSOURCE/$PKGSERIES/$PKGNAM
  # for /extra:
  pwd | grep -Fq "/extra/source/" && {
     # Overwrite the SLACKSOURCE that's defined in /usr/share/slackdev/slackdev.config
     # because for /extra on stable releases, patch packages aren't in /patches/packages:
     export SLACKSOURCE="$SLACKUPSTREAMROOTDIR/extra/source"
     export CWD=$SLACKSOURCE/$PKGNAM*
     export PKGSTORE="$PORTROOTDIR/extra/$PKGNAM/" ;}

  # for /patches - note that slackdev.config has SLACKSOURCE set (usually) to $HOME/slackware64-14.2/patches/source
  # which is why this works.
  #pwd | grep -Fq "/patches/source/" && export CWD=$SLACKSOURCE/$PKGNAM*
  # Unsure why I suffixed the * there, but it breaks with 'apr' and 'apr-util'
  # packages and I cannot think at this time why it'd be necessary.
  pwd | grep -Fq "/patches/source/" && export CWD=$SLACKSOURCE/$PKGNAM
  # for /pasture:
  #pwd | grep -Fq "/pasture/source/" && export CWD=$SLACKSOURCE/../pasture/source/$PKGNAM*
  pwd | grep -Fq "/pasture/source/" && export CWD=$SLACKSOURCE/../pasture/source/$PKGNAM

  # Only display the info if not running through r2b, otherwise this
  # triggers the pre-build checks list display:
  [ -z "$R2BRUNNING" ] && {
     echo "Source tree information"
     echo "-----------------------"
     echo "Master Slackware CWD: $CWD"
     echo "Port Overlay PORTCWD: $PORTCWD" ;}
}

# Delete *.la files:
function slack_delete_lafiles() {
  echo "Deleting any *.la files"
  rm -fv $PKG/{,usr/}lib${LIBDIRSUFFIX}/*.la
}

# Automatically determine the package series based on the pwd
function slack_var_pkgseries() {
  # If PKGSERIES is already set, do nothing.
  [ ! -z "$PKGSERIES" ] && return 0
  # Working in -current tree, where the pwd would be ~/ac/source/a/bash
  export PKGSERIES="$( pwd | grep -Eo '/a/|/ap/|/d/|/e/|/f/|/k/|/kde/|/kdei$|/l/|/n/|/t/|/tcl/|/x/|/xap/|/xfce/|/y/' | sed 's?\/??g' )"
  # for /extra:
  pwd | grep -Fq "/extra/source/" && export PKGSERIES=extra
  # for /patches:
  pwd | grep -Fq "/patches/source/" && export PKGSERIES=patches
  if [ -z "$PKGSERIES" ]; then
     echo "ERROR: Could not determine PKGSERIES variable."
     exit 1
  else
     # Output the package series, unless r2b is running:
     [ -z "$R2BRUNNING" ] && echo "Package series directory: $PKGSERIES"
  fi
}

# We need to give the minimum cpu as ARM3 otherwise our binaries have
# ldrh instructions compiled into them, which fail in funky ways
# on the RiscPC StrongARM110.  You can read about this in various places on the net.
# Chocky says that specifying StrongARM110 will most likely make the code
# execute slower on the XScale systems.  I only have RiscPCs at the moment so
# I'm not too fussed.
#export ARMCFLAGS="-march=armv4 -mtune=strongarm110"
#export PORTCFLAGS="${ARMCFLAGS}"
#export PORTCXXFLAGS="${ARMCFLAGS}"
#export SLKCFLAGS="${ARMCFLAGS}"
#export SLKCXXFLAGS="${ARMCFLAGS}"

# Ensure target arch is ARMv3
# This doesn't work as SB's gcc seems not to honour gcc specs files.
# Instead, you need an armv3 toolchain.  Having an armv3 toolchain also means
# you get a version of sbrshd that works on the SA110 RiscPC.
# perl -pi -e 's?^-D__ARM_ARCH_4T__?-D__ARM_ARCH_3__?;' /lib/gcc-lib/arm-linux/3.3.2/specs

# This is where our armedslack source tree lives
# and where we'll be doing our /tmp stuff.
# We cannot compile in /tmp because it's NFS exported to the ARM
# box, and whilst it may *appear* to build, it will fail in
# weird ways.
# However, if you're stuck between a rock and a hard place, you could
# always NFS export /tmp on the Scratchbox (x86 Slackware) host and NFS mount
# it as /tmp on the ARMedslack machine.  I've done this before and it was fine,
# and infact, since gcc has /tmp hard coded a gazillion times in its files,
# I guess you may want to use it when building gcc inside scratchbox.
#export BBASE=/home/build
export BBASE=/root

# The stash of ARM binary .t?z packages.
# I replace the versions in the repository manually incase
# the new build breaks.
export PKGSTORE=${BBASE}/tgzstash

# The package building logs:
export PBLOGS=${BBASE}/buildlogs
mkdir -p ${PBLOGS} >/dev/null 2>&1

# Within the scratchbox, our ARM root is /targets/ARM
# This setting is for altertrack.
if [ -f /targets/links/scratchbox.config ]; then
   export PORTSYSROOT="--rootdir=/targets/ARM/"
 else
   export PORTSYSROOT="--rootdir=/" # we're working natively
fi

# Build up the Slackware binary repository structure.
# This is where our .t?z packages will reside once built.
# This can eventually be scrapped when I've setup my scripts to track all dir
# additions/removals in slackware-current.
#for i in ../extra/source ../pasture ../testing ../extra/glibc-extra-packages \
# This is useless - the dirs will have already existed, and if not - create them manually!
#for i in a ap d e f k kde kdei l n t tcl x xap xfce y ; do
#    mkdir -pm755 ${PKGSTORE}/${i} >/dev/null 2>&1
#done

# Export all functions:
FUNCTIONS="auto_apply_patch
kernheads
altertrackprep
apply_full_debian_patches
changelogliposuction
sboxsysrestore
slackbuildinfo
shortwords
slackgzpages
slackstripso
slackstripar
slackstripbin
slackstripall
slackstriprpaths
slackchown
slack644docs
slackhlinks
slackhousekeeping
slackfailpkgdeps
slackcheckpkgdeps
slack_tgz2package_name
slack_is_package_installed
slack_autotoolsprep
slack_setvarfromupstream
slackslack
slacknosuid
slackx86
slackipkg
slackmp
slackdesc
slack_findpkgstore_is_stablerelease
slackbasedeps
slackset_var_cwds
slack_var_pkgseries
slack_delete_lafiles
slackupdatelibtool
shm_tmp
using_distcc
mkpkgdirs
failconfig
failmake
failinstall
failpatch
failextract
fnexists_call
fnexists
fnexists_multicall
fnexists_loadplugins"
for i in $FUNCTIONS; do
  export -f $i
done
