#!/bin/bash

# Script for building MTOC
#

if [ -z "$WORKSPACE" ]
then
  echo WORKSPACE must be defined to Clover root path
  export WORKSPACE=`pwd`
fi

# Ctools source version
# here we can change source versions of tools
#
OSXVER="`/usr/bin/sw_vers -productVersion | cut -d '.' -f1,2`"
if [[ ${OSXVER} < 10.15 ]]; then
	export CCTOOLS_VERSION=${CCTOOLS_VERSION:-cctools-949.0.1}
else
	export CCTOOLS_VERSION=${CCTOOLS_VERSION:-cctools-986}
fi
# Change PREFIX if you want mtoc installed on different place
#
TOOLCHAIN_DIR=${TOOLCHAIN_DIR:-~/src/opt/local}
export PREFIX=${PREFIX:-$TOOLCHAIN_DIR}

# You can change DIR_MAIN if u want cctools source downloaded
# in different folder.
#
export RAMDISK_MNT_PT=/tmp/buildmtoc-ramdisk
export DIR_MAIN=${DIR_MAIN:-~/src}
export DIR_TOOLS=${DIR_TOOLS:-$DIR_MAIN/tools}
export DIR_BUILD=${DIR_BUILD:-$RAMDISK_MNT_PT}
export DIR_DOWNLOADS=${DIR_DOWNLOADS:-$DIR_TOOLS/download}
export DIR_LOGS=${DIR_LOGS:-$DIR_TOOLS/logs}

# Here we set MAKEFLAGS for GMAKE so it knows how many cores can use
# faster compile!
#
export MAKEFLAGS="-j `sysctl -n hw.ncpu`"

set -u

### Check Functions ###

# Function: checking installation of Xcode Tools
fnCheckXcode () {
    [ ! -f /usr/bin/xcodebuild ] && \
        echo "ERROR: Install Xcode Tools from Apple before using this script." && \
        exit
}


### Main Function START ###

# Function: Creating directory structure for EDK

[ ! -d ${DIR_MAIN} ]       && mkdir ${DIR_MAIN}
[ ! -d ${DIR_TOOLS} ]      && mkdir ${DIR_TOOLS}
[ ! -d ${DIR_DOWNLOADS} ]  && mkdir ${DIR_DOWNLOADS}
[ ! -d ${DIR_LOGS} ]       && mkdir ${DIR_LOGS}
[ ! -d ${PREFIX}/bin ]     && mkdir -p ${PREFIX}/bin
echo

# Function: to manage PATH
pathmunge () {
    if [[ ! $PATH =~ (^|:)$1(:|$) ]]; then
        if [[ "${2:-}" = "after" ]]; then
            export PATH=$PATH:$1
        else
            export PATH=$1:$PATH
        fi
    fi
}

# RAMdisk
function mountRamDisk() {
    dev_ramdisk=$(mount | grep "$RAMDISK_MNT_PT" | awk '{print $1}')
    if [ -z "$dev_ramdisk" ];then
        echo "- Creating new RAM disk"
        dev_ramdisk=`hdiutil attach -nomount ram://614400 | awk '{print $1}'`
        echo
        [ -n "$dev_ramdisk" ] && newfs_hfs -v "Build Mtoc RamDisk" "$dev_ramdisk"
        [ ! -d "$RAMDISK_MNT_PT" ] && mkdir "$RAMDISK_MNT_PT"
        mount -t hfs "$dev_ramdisk" "$RAMDISK_MNT_PT"
        touch "$RAMDISK_MNT_PT/.metadata_never_index"
    fi
    # Automatically remove RAMDISK on exit
    trap 'echo; echo "- Ejecting RAM disk"; cd "$HOME"; umount "$RAMDISK_MNT_PT" && hdiutil detach "$dev_ramdisk"' EXIT
}


### Download ###

fnDownloadCctools ()
# Function: Download cctools source
{
    cd "$DIR_DOWNLOADS"
    local tarball="${CCTOOLS_VERSION}.tar.gz"
    if [[ ! -f ${DIR_DOWNLOADS}/${CCTOOLS_VERSION}.tar.gz ]]; then
        echo "Status: ${CCTOOLS_VERSION} not found."
        curl -k -f -o download.tmp --remote-name https://codeload.github.com/apple-oss-distributions/cctools/tar.gz/refs/tags/${CCTOOLS_VERSION} || exit 1
        mv download.tmp $tarball
    fi
}
#https://github.com/apple-oss-distributions/cctools/archive/refs/tags/cctools-973.0.1.tar.gz

### Extract ###

# Function to extract source tarballs
fnExtract ()
{
    exec 3>&1 1>&2 # Save stdout and redirect stdout to stderr
		
		# OS version check
		local OSXVER="`/usr/bin/sw_vers -productVersion | cut -d '.' -f1,2`"

    local tarball="$1"
    local package=${tarball%%.tar*}
    tarball="${DIR_DOWNLOADS}/$tarball"
    local flagfile="${DIR_BUILD}/$package.extracted"
		
    local filetype=$(file -L --brief "$tarball" | tr '[A-Z]' '[a-z]')
    local tar_filter_option=""

    case ${filetype} in # convert to lowercase
        gzip\ *)  tar_filter_option='--gzip' ;;
        bzip2\ *) tar_filter_option='--bzip2';;
        lzip\ *)  tar_filter_option='--lzip' ;;
        lzop\ *)  tar_filter_option='--lzop' ;;
        lzma\ *)  tar_filter_option='--lzma' ;;
        xz\ *)    tar_filter_option='--xz'   ;;
        *tar\ archive*) tar_filter_option='';;
        *) echo "Unrecognized file format of '$tarball'"
           exit 1
           ;;
    esac

    # Get the root directory from the tarball
    local first_line=$(dd if="$tarball" bs=1024 count=256 2>/dev/null | \
        tar -t $tar_filter_option -f - 2>/dev/null | head -1)
    local top_level_dir=${first_line#./}  # remove leading ./
    top_level_dir=${top_level_dir%%/*}    # keep only the top level directory

    [ -z "$top_level_dir" ] && echo "Error can't extract top level dir from $tarball" && exit 1

    if [[ ! -d "${DIR_BUILD}/$top_level_dir" || ! -f "$flagfile" ]]; then
        echo "-  ${package} extract..."
        rm -rf "${DIR_BUILD}/$top_level_dir" # Remove old directory if exists
        tar -C "$DIR_BUILD" -x "$tar_filter_option" -f "${tarball}" && touch "${DIR_BUILD}/$package.extracted"
        
        #jief copy the modified version that keeps __mod_init_func section
        #cp "$WORKSPACE"/BaseTools/Source/C/mtoc/mtoc-v921_jief.c "$DIR_BUILD/$top_level_dir"/efitools/mtoc.c
				if [[ ${OSXVER} < 10.15 ]]; then
					cp "$WORKSPACE"/Patches/Mtoc/mtoc-v973_jief.c "$DIR_BUILD/$top_level_dir"/efitools/mtoc.c
				else
					cp "$WORKSPACE"/Patches/Mtoc/mtoc-v986_jief.c "$DIR_BUILD/$top_level_dir"/efitools/mtoc.c
					cp "$WORKSPACE"/Patches/Mtoc/libstuff.xcconfig "$DIR_BUILD/$top_level_dir"/xcode/
				fi
    fi

    # Restore stdout for the result and close file desciptor 3
    exec 1>&3-
    echo "${DIR_BUILD}/$top_level_dir" # Return the full path where the tarball has been extracted
}

### Compile ###

fnCompileMtoc ()
# Function: Compiling Mtoc in PREFIX location
{
    # Mount RamDisk
    mountRamDisk
		
		# OS version check
		local OSXVER="`/usr/bin/sw_vers -productVersion | cut -d '.' -f1,2`"
		
    # Extract the tarball
    local CCTOOLS_DIR=$(fnExtract "${CCTOOLS_VERSION}.tar.gz")

    # Set SDKROOT for Makefiles
    export SDKROOT="$(xcrun -n --show-sdk-path)"

    # Mtoc build
    local cmd logfile
    cd "$CCTOOLS_DIR"

# Replace deprecated DT_TOOLCHAIN_DIR as a workaround for building in Xcode 15
	xcodeapp=$(defaults read /Applications/Xcode.app/Contents/version.plist CFBundleShortVersionString)
	if [[ $xcodeapp == 15.* ]]; then
		sed -i '' 's/DT_TOOLCHAIN_DIR/TOOLCHAIN_DIR/g' "$CCTOOLS_DIR"/xcode/cctools.xcconfig
		sed -i '' 's/DT_TOOLCHAIN_DIR/TOOLCHAIN_DIR/g' "$CCTOOLS_DIR"/xcode/libstuff.xcconfig
		sed -i '' 's/DT_TOOLCHAIN_DIR/TOOLCHAIN_DIR/g' "$CCTOOLS_DIR"/xcode/strip.xcconfig
	fi
    # Removal of _structs.h needed as a workaround for a bug in cctools-900 or above
    /bin/rm -f ./include/mach/i386/_structs.h
    echo "-  cctools-${CCTOOLS_VERSION} make mtoc..."
		if [[ ${OSXVER} < 10.15 ]]; then
			cmd="(make LTO= EFITOOLS=efitools -C libstuff) && (make -C efitools)"
		else
			cmd="(xcodebuild -scheme mtoc -configuration Release ARCHS=x86_64 ONLY_ACTIVE_ARCH=YES CONFIGURATION_BUILD_DIR=$PREFIX/bin)"
		fi
    logfile="$DIR_LOGS/mtoc.make.log.txt"
    echo "$cmd" > "$logfile"
    eval "$cmd" >> "$logfile" 2>&1
    if [[ $? -ne 0 ]]; then
        echo "Error compiling cctools-${CCTOOLS_VERSION} mtoc ! Check the log $logfile"
        exit 1
    fi
    echo "-  cctools-${CCTOOLS_VERSION} installing mtoc..."
		if [[ ${OSXVER} < 10.15 ]]; then
			cmd="install -c -s -m 555 efitools/mtoc.NEW ${PREFIX}/bin/mtoc.NEW_jief"
		else
			cmd="mv ${PREFIX}/bin/mtoc ${PREFIX}/bin/mtoc.NEW_jief"
		fi
    logfile="$DIR_LOGS/mtoc.install.log.txt"
    echo "$cmd" > "$logfile"
    eval "$cmd" >> "$logfile" 2>&1
    if [[ $? -ne 0 ]]; then
        echo "Error installing cctools-${CCTOOLS_VERSION} mtoc ! Check the log $logfile"
        exit 1
    fi
    rm -rf "$CCTOOLS_DIR"
    echo "-  cctools-${CCTOOLS_VERSION} mtoc installed in $PREFIX"
}

# remove unused additional files
fnCleanUp()
{
	if [[ ${OSXVER} > 10.15 ]]; then
		rm -r $PREFIX/bin/*.dSYM $PREFIX/bin/*.a
	fi
}

### fnFunctions ###

fnMtoc ()
# Function: Mtoc main script
{
    fnDownloadCctools
    fnCompileMtoc
		fnCleanUp
}


### Main ###

# Add XCode bin directory for the command line tools to the PATH
#pathmunge "$(xcode-select --print-path)"/usr/bin

fnMtoc
