#! /bin/bash

# Tool versions
declare -A tool_hash
tool_hash["binutils-2.25.1.tar.bz2"]='b5b14added7d78a8d1ca70b5cb75fef57ce2197264f4f5835326b0df22ac9f22'
tool_hash["binutils-2.25.tar.bz2"]='22defc65cfa3ef2a3395faaea75d6331c6e62ea5dfacfed3e2ec17b08c882923'
tool_hash["binutils-2.29.1.tar.bz2"]='1509dff41369fb70aed23682351b663b56db894034773e6dbf7d5d6071fc55cc'
tool_hash["binutils-2.32.tar.bz2"]='de38b15c902eb2725eac6af21183a5f34ea4634cb0bcef19612b50e5ed31072d'
tool_hash["binutils-2.41.tar.bz2"]='a4c4bec052f7b8370024e60389e194377f3f48b56618418ea51067f67aaab30b'
tool_hash["gcc-4.9.2.tar.bz2"]='2020c98295856aa13fda0f2f3a4794490757fc24bcca918d52cc8b4917b972dd'
tool_hash["gcc-6.2.0.tar.bz2"]='9944589fc722d3e66308c0ce5257788ebd7872982a718aa2516123940671b7c5'
tool_hash["gcc-7.3.0.tar.xz"]='832ca6ae04636adbb430e865a1451adf6979ab44ca1c8374f61fba65645ce15c'
tool_hash["gcc-9.1.0.tar.xz"]='79a66834e96a6050d8fe78db2c3b32fb285b230b855d0a66288235bc04b327a0'
tool_hash["gcc-13.2.0.tar.xz"]='e275e76442a6067341a27f04c5c6b83d8613144004c0413528863dc6b5c743da'
tool_hash["glibc-2.22.tar.gz"]='a62610c4084a0fd8cec58eee12ef9e61fdf809c31e7cecbbc28feb8719f08be5'
tool_hash["glibc-2.26.tar.gz"]='dcc2482b00fdb1c316f385f8180e182bbd37c065dc7d8281a4339d2834ef1be7'
tool_hash["glibc-2.27.tar.gz"]='881ca905e6b5eec724de7948f14d66a07d97bdee8013e1b2a7d021ff5d540522'
tool_hash["glibc-ports-2.16.0.tar.gz"]='1092e81d0c9c1bc29343004c1d01fb0d89eb49dd0fd5339b2f2e64a44b582d10'
tool_hash["gmp-6.0.0a.tar.bz2"]='7f8e9a804b9c6d07164cf754207be838ece1219425d64e28cfa3e70d5c759aaf'
tool_hash["gmp-6.1.2.tar.bz2"]='5275bb04f4863a13516b2f39392ac5e272f5e1bb8057b18aec1c9b79d73d8fb2'
tool_hash["gmp-6.3.0.tar.bz2"]='ac28211a7cfb609bae2e2c8d6058d66c8fe96434f740cf6fe2e47b000d1c20cb'
tool_hash["mpc-1.0.2.tar.gz"]='b561f54d8a479cee3bc891ee52735f18ff86712ba30f036f8b8537bae380c488'
tool_hash["mpc-1.1.0.tar.gz"]='6985c538143c1208dcb1ac42cedad6ff52e267b47e5f970183a3e75125b43c2e'
tool_hash["mpc-1.3.1.tar.gz"]='ab642492f5cf882b74aa0cb730cd410a81edcdbec895183ce930e706c1c759b8'
tool_hash["mpfr-3.1.2.tar.bz2"]='79c73f60af010a30a5c27a955a1d2d01ba095b72537dab0ecaad57f5a7bb1b6b'
tool_hash["mpfr-4.0.0.tar.bz2"]='6aa31fbf3bd1f9f95bcfa241590a9d11cb0f874e2bb93b99c9e2de8eaea6d5fd'
tool_hash["mpfr-4.0.0.tar.xz"]='fbe2cd1418b321f5c899ce4f0f0f4e73f5ecc7d02145b0e1fd096f5c3afb8a1d'
tool_hash["mpfr-4.0.2.tar.xz"]='1d3be708604eae0e42d578ba93b390c2a145f17743a744d8f3f8c2ad5855a38a'
tool_hash["mpfr-4.2.1.tar.xz"]='277807353a6726978996945af13e52829e3abd7a9a5b7fb2793894e18f1fcbb2'
tool_hash["llvm-8.0.0.tar.xz"]='8872be1b12c61450cacc82b3d153eab02be2546ef34fa3580ed14137bb26224c'
tool_hash["clang-8.0.0.tar.xz"]='084c115aab0084e63b23eee8c233abb6739c399e29966eaeccfc6e088e0b736b'
tool_hash["compiler-rt-8.0.0.tar.xz"]='b435c7474f459e71b2831f1a4e3f1d21203cb9c0172e94e9d9b69f50354f21b1'

# Functions
function _download_file() {
	local file url headers
	local header
	local try_download_command
	local args

	file="$1"
	url="$2"
	shift 2
	headers=("$@")

	if [ -z "${_download_command}" ]; then
		for try_download_command in curl wget; do
			if command -v "${try_download_command}" 2>/dev/null >/dev/null; then
				_download_command="${try_download_command}"

				break
			fi
		done
	fi

	args=()
	for header in "${headers[@]}"; do
		case "${_download_command}" in
			curl)
				args+=(--header "${header}")
				;;
			wget)
				args+=(--header="${header}")
				;;
		esac
	done

	case "${_download_command}" in
		curl)
			curl "${args[@]}" --silent --show-error --location --output "${file}" "${url}" || return 1
			;;
		wget)
			wget "${args[@]}" --output-document="${file}" "${url}" || return 1
			;;
	esac

	return 0
}

function download () {
	local url
	local file
	local checksum dl_checksum checksum_type
	local tmpfile

	url="$1"
	file="$2"
	checksum="$3"

	# If no checksum was provided, try to guess one
	if [ -z "${checksum}" ]; then
		local tool_name
		tool_name="$(echo "${url}" | sed 's@\?.*$@@;s@^.*/@@')"
		if [ -n "${tool_hash[${tool_name}]}" ]; then
			checksum="${tool_hash[${tool_name}]}"
		fi
	fi

	# Emit a warning if no checksum is provided
	if [ -z "${checksum}" ]; then
		echo '*********************************************************' >&2
		echo "WARNING: Downloading ${url} -> ${file} with no checksum !" >&2
		echo '*********************************************************' >&2
	fi

	# Use the download helper if possible
	if [ -n "${BUILD_CC_DOWNLOAD_HELPER}" ]; then
		"${BUILD_CC_DOWNLOAD_HELPER}" "${url}" "${file}" "${checksum}"

		return "$?"
	fi

	checksum_type='unknown'
	if [ -n "${checksum}" ]; then
		case "${checksum}" in
			????????????????????????????????????????)
				checksum_type='sha1'
				;;
			????????????????????????????????????????????????????????????????)
				checksum_type='sha256'
				;;
			*)
				;;
		esac
	fi

	tmpfile="${file}.tmp"

	if [ -s "${file}" ]; then
		return 0
	fi

	mkdir -p "$(dirname "${tmpfile}")" 2>/dev/null >/dev/null

	rm -f "${tmpfile}"
	if [ "${checksum_type}" != 'unknown' ]; then
		_download_file "${tmpfile}" "http://hashcache.rkeene.org/${checksum_type}/${checksum}" "X-Cache-URL: ${url}" || rm -f "${tmpfile}"
	fi
	if [ ! -s "${tmpfile}" ]; then
		_download_file "${tmpfile}" "${url}"
	fi

	case "${checksum_type}" in
		sha1)
			dl_checksum="$(openssl dgst -sha1 "${tmpfile}" 2>/dev/null | sed 's@.*= *@@')"
			;;
		sha256)
			dl_checksum="$(openssl dgst -sha256 "${tmpfile}" 2>/dev/null | sed 's@.*= *@@')"
			;;
	esac

	if [ "${checksum_type}" != 'unknown' ]; then
		if [ "${checksum}" != "${dl_checksum}" ]; then
			echo "Checksum mismatch.  Got checksum: ${dl_checksum}; Expected checksum: ${checksum}" >&2

			return 1
		fi
	fi

	mv "${tmpfile}" "${file}"

	return 0
}

function extract() {
	local tarball outputdir checksum
	local tool
	local tmpdir tmpname
	local outputdirroot
	local retval

	tarball="$1"
	outputdir="$2"
	checksum="$3"

	if [ -e "${outputdir}" ]; then
		return 1
	fi

	case "${tarball}" in
		*.tar.bz2|*.tbz2)
			tool='bzip2'
			;;
		*.tar.xz|*.txz)
			tool='xz'
			;;
		*.tar.gz|*.tgz)
			tool='gzip'
			;;
		*)
			echo "error: Unable to extract \"${tarball}\"" >&2
			return 1
			;;
	esac

	tmpname="$(basename "${outputdir}")"
	outputdirroot="$(dirname "${outputdir}")"

	tmpdir="tmp.$(openssl rand -hex 20)" || return 1
	mkdir "${tmpdir}" || return 1
	mkdir "${tmpdir}/${tmpname}" || return 1

	# If the tarball is a URL, download it to a temporary location first
	case  "${tarball}" in
		*://*)
			download "${tarball}" "${tmpdir}/archive" "${checksum}"
			tarball="${tmpdir}/archive"
			;;
	esac

	"${tool}" -dc "${tarball}" | (
		cd "${tmpdir}/${tmpname}" || exit 1

		tar -xf - || exit 1

		shopt -s dotglob
		singledir="$(echo *)"
		if [ -e "${singledir}" ]; then
			mv "${singledir}" "${tmpdir}" || exit 1
			cd "${tmpdir}" || exit 1
			mv * .. || exit 1
			cd .. || exit 1
			rm -rf "${tmpdir}"
		fi
	) || return 1

	retval='1'
	mv "${tmpdir}/${tmpname}" "${outputdirroot}" && retval='0'

	rm -f "${tmpdir}/archive" || return 1
	rmdir "${tmpdir}" || return 1

	return "${retval}"
}

function fix_pkgconfig_file () {
	local file

	file="$1"

	sed 's@^prefix=.*@prefix=/usr@;s@\$(libdir)@${libdir}@g' "${file}" > "${file}.new"
	chmod u+w "${file}"
	cat "${file}.new" > "${file}"
	rm -f "${file}.new"

	return 0
}

# Expects:
#    CC
#    CCNAME
#    PREFIX
function multilib () {
	local arch
	local mode
	local archs host libdir cflags
	local addprefix

	mode='cflags'

	if [ "$1" = '--libdir' ]; then
		mode='libdir'

		shift
	fi

	if [ "$1" = '--host' ]; then
		mode='host'

		shift
	fi

	if [ "$1" = '--cflags' ]; then
		mode='cflags'

		shift
	fi

	addprefix='1'
	if [ "$1" = '--noprefix' ]; then
		addprefix='0'

		shift
	fi

	arch="$1"

	# If no architecture is given, return the list of architectures
	if [ -z "${arch}" ]; then
		mode='list'
	else
		cflags=""
		if [ "${arch}" != '_' ]; then
			cflags="${arch}"
		fi
	fi

	case "${mode}" in
		list)
			archs="$(${CC} -print-multi-lib | grep -v '^[^;]*/' | sed 's/^.*;//;s/^@/-/;s@^ *$@_@')"
			if [ -z "${archs}" ]; then
				archs='_'
			fi

			echo "${archs}"

			return 0
			;;
		cflags)
			echo "${cflags}"

			return 0
			;;
		libdir)
			libdir="${PREFIX}/lib"
			mkdir -p "${libdir}" || exit 1

			libdir="${libdir}/$(${CC} ${cflags} -print-multi-os-directory)"
			mkdir -p "${libdir}" || exit 1

			libdir="$(cd "${libdir}" && pwd)" || exit 1

			if [ "${addprefix}" = '0' ]; then
				libdir="$(echo "${libdir}" | sed 's@^'"${PREFIX}"'/@/@')"
			fi

			echo "${libdir}"

			return 0
			;;
		host)
			if [ "${arch}" = '_' ]; then
				echo "${CCNAME}"
				return 0
			fi

			case "${arch}" in
				-m32)
					host="$(echo "${CCNAME}" | sed 's@^x86_64-@i486-@;s@^sparcv9-@sparc-@')"
					;;
				-m64)
					host="$(echo "${CCNAME}" | sed 's@^i.86-@x86_64-@;s@-x32-@-@;s@^x32-@x86_64-@;s@^sparc-@sparcv9-@')"
					;;
				*)
					host="${CCNAME}.${arch}"
					;;
			esac

			echo "${host}"

			return 0
			;;
	esac
}

# Determine Linux and uClibc arch name
## alpha arm avr32 bfin cris e1 frv h8300 hppa i386 i960 ia64 m68k microblaze mips nios nios2 powerpc sh sh64 sparc v850 vax x86_64
arch="$(echo "${CCNAME}" | cut -f 1 -d '-')"
case "${arch}" in
	arm*)
		arch=arm
		;;
	mips*)
		arch=mips
		;;
	hppa*)
		arch=hppa
		;;
	sparc*)
		arch=sparc
		;;
	i?86)
		arch=i386
		;;
esac
