#!/bin/sh
#  SPDX-License-Identifier: GPL-2.0-or-later
# update-alternatives
#
# Copyright (C) 2001 Carl D. Worth
#
# This program was inspired by the Debian update-alternatives program
# which is Copyright (C) 1995 Ian Jackson. This version of
# update-alternatives is command-line compatible with Debian's for a
# subset of the options, (only --install, --remove, and --help)
#
# This program 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.
#
# This program 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.

set -e

# admin dir
ad="$OPKG_OFFLINE_ROOT/usr/lib/opkg/alternatives"

usage() {
	echo "update-alternatives: $*

Usage: update-alternatives --install <link> <name> <path> <priority>
       update-alternatives --remove <name> <path>
       update-alternatives --help
<link> is the link pointing to the provided path (ie. /usr/bin/foo).
<name> is the name in $ad/alternatives (ie. foo)
<path> is the name referred to (ie. /usr/bin/foo-extra-spiffy)
<priority> is an integer; options with higher numbers are chosen.
" >&2
	exit 2
}

quit() {
	echo "update-alternatives: $*" >&2
	exit 2
}

register_alt() {
	[ $# -lt 2 ] && return 1
	local name="$1"
	local link="$2"

	if [ ! -d $ad ]; then
		mkdir -p $ad
	fi

	if [ -e "$ad/$name" ]; then
		local olink=`head -n 1 $ad/$name`
		if [ "$link" != "$olink" ]; then
			echo "update-alternatives: renaming $name link from $olink to $link"
			local link_str=`echo $link | protect_slashes`
			sed -e "1s/.*/$link_str/" $ad/$name > $ad/$name.new
			mv $ad/$name.new $ad/$name
			mv $OPKG_OFFLINE_ROOT$olink $OPKG_OFFLINE_ROOT$link
		fi
	else
		echo "$link" > "$ad/$name"
	fi

	return 0
}

protect_slashes() {
	sed -e 's/\//\\\//g'
}

protect_special_character() {
	sed -e 's/\[/\\\[/g'
}

remove_alt() {
	[ $# -lt 2 ] && return 1
	local name="$1"
	local path="$2"

	[ ! -f $ad/$name ] && return 0

	path=`echo $path | protect_slashes | protect_special_character`
	sed -ne "/^$path\s.*/!p" $ad/$name > $ad/$name.new
	mv $ad/$name.new $ad/$name
}

add_alt() {
	[ $# -lt 3 ] && return 1
	local name="$1"
	local path="$2"
	local priority="$3"
	remove_alt $name $path
	if grep -qw "$priority" $ad/$name; then
		echo "Warn: update-alternatives: $name has multiple providers with the same priority, please check $ad/$name for details"
	fi
	echo "$path $priority" >> $ad/$name
}

find_best_alt() {
	[ $# -lt 1 ] && return 1
	[ ! -f $ad/$name ] && return 0

	link=$OPKG_OFFLINE_ROOT`head -n 1 $ad/$name`

	prio=`sed -ne "1!p" $ad/$name | sed -e "s/\(.*\) \(.*\)/\2 \1/g" | sort -nr | head -n 1 | sed 's/ [^ ]*$//'`
	if [ -z "$prio" ]; then
		echo "update-alternatives: removing $link as no more alternatives exist for it"
		rm $ad/$name
		if [ -L $link ]; then
			rm $link
		fi
		return 0
	fi

	## Find last line with highest priority.
	path=`grep "${prio}$" $ad/$name | tail -n 1 | sed 's/ [^ ]*$//'`

	if [ ! -e $link -o -L $link ]; then
		local link_dir=`dirname $link`
		if [ ! -d $link_dir ]; then
			mkdir -p $link_dir
		fi
		ln -snf $path $link
		echo "update-alternatives: Linking $link to $path"
	else
		echo "update-alternatives: Error: not linking $link to $path since $link exists and is not a link"
		return 1
	fi

	return 0
}

do_install() {
	if [ $# -lt 4 ]; then
		usage "--install needs <link> <name> <path> <priority>"
	fi
	local link="$1"
	local name="$2"
	local path="$3"
	local priority="$4"

	path=`echo $path | sed 's|/\+|/|g'`

	# This is a bad hack, but I haven't thought of a cleaner solution yet...
	[ -n "$OPKG_OFFLINE_ROOT" ] && path=`echo $path | sed "s|^$OPKG_OFFLINE_ROOT/*|/|"`

	register_alt $name $link
	add_alt $name $path $priority
	find_best_alt $name
}

do_remove() {
	if [ $# -lt 2 ]; then
		usage "--remove needs <name> <path>"
	fi
	local name="$1"
	local path="$2"

	path=`echo $path | sed 's|/\+|/|g'`

	# This is a bad hack, but I haven't thought of a cleaner solution yet...
	[ -n "$OPKG_OFFLINE_ROOT" ] && path=`echo $path | sed "s|^$OPKG_OFFLINE_ROOT/*|/|"`

	remove_alt $name $path
	find_best_alt $name
}

###
# update-alternatives "main"
###

while [ $# -gt 0 ]; do
	arg="$1"
	shift

	case $arg in
	--help)
		usage "help:"
		exit 0
		;;
	--install)
		do_install $*
		exit $?
		;;
	--remove)
		do_remove $*
		exit $?
		;;
	*)
		usage "unknown argument \`$arg'"
		;;
	esac
done

usage "at least one of --install or --remove must appear"

exit 0
