xref: /freebsd/contrib/bc/scripts/locale_install.sh (revision a970610a3af63b3f4df5b69d91c6b4093a00ed8f)
144d4804dSStefan Eßer#! /bin/sh
244d4804dSStefan Eßer#
344d4804dSStefan Eßer# SPDX-License-Identifier: BSD-2-Clause
444d4804dSStefan Eßer#
5*a970610aSStefan Eßer# Copyright (c) 2018-2024 Gavin D. Howard and contributors.
644d4804dSStefan Eßer#
744d4804dSStefan Eßer# Redistribution and use in source and binary forms, with or without
844d4804dSStefan Eßer# modification, are permitted provided that the following conditions are met:
944d4804dSStefan Eßer#
1044d4804dSStefan Eßer# * Redistributions of source code must retain the above copyright notice, this
1144d4804dSStefan Eßer#   list of conditions and the following disclaimer.
1244d4804dSStefan Eßer#
1344d4804dSStefan Eßer# * Redistributions in binary form must reproduce the above copyright notice,
1444d4804dSStefan Eßer#   this list of conditions and the following disclaimer in the documentation
1544d4804dSStefan Eßer#   and/or other materials provided with the distribution.
1644d4804dSStefan Eßer#
1744d4804dSStefan Eßer# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1844d4804dSStefan Eßer# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1944d4804dSStefan Eßer# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2044d4804dSStefan Eßer# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
2144d4804dSStefan Eßer# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2244d4804dSStefan Eßer# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2344d4804dSStefan Eßer# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2444d4804dSStefan Eßer# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2544d4804dSStefan Eßer# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2644d4804dSStefan Eßer# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2744d4804dSStefan Eßer# POSSIBILITY OF SUCH DAMAGE.
2844d4804dSStefan Eßer#
2944d4804dSStefan Eßer
3044d4804dSStefan Eßer# Just print the usage and exit with an error.
314fca8e0fSStefan Eßer# @param 1  A message to print.
3244d4804dSStefan Eßerusage() {
3344d4804dSStefan Eßer	if [ $# -eq 1 ]; then
3444d4804dSStefan Eßer		printf '%s\n' "$1"
3544d4804dSStefan Eßer	fi
3644d4804dSStefan Eßer	printf "usage: %s [-l] NLSPATH main_exec [DESTDIR]\n" "$0" 1>&2
3744d4804dSStefan Eßer	exit 1
3844d4804dSStefan Eßer}
3944d4804dSStefan Eßer
4044d4804dSStefan Eßer# Run gencat on one file.
4144d4804dSStefan Eßer# @param loc   The location of the resulting cat file.
4244d4804dSStefan Eßer# @param file  The file to use as the source for the cat file.
4344d4804dSStefan Eßergencatfile() {
4444d4804dSStefan Eßer
4544d4804dSStefan Eßer	_gencatfile_loc="$1"
4644d4804dSStefan Eßer	shift
4744d4804dSStefan Eßer
4844d4804dSStefan Eßer	_gencatfile_file="$1"
4944d4804dSStefan Eßer	shift
5044d4804dSStefan Eßer
5144d4804dSStefan Eßer	mkdir -p $(dirname "$_gencatfile_loc")
5244d4804dSStefan Eßer	gencat "$_gencatfile_loc" "$_gencatfile_file" > /dev/null 2>&1
5344d4804dSStefan Eßer}
5444d4804dSStefan Eßer
5544d4804dSStefan Eßer# Return an exit code based on whether a locale exists.
5644d4804dSStefan Eßer# @param locales  The list of locales.
5744d4804dSStefan Eßer# @param locale   The locale to search for.
5844d4804dSStefan Eßer# @param destdir  The DESTDIR that locales should be installed to.
5944d4804dSStefan Eßerlocaleexists() {
6044d4804dSStefan Eßer
6144d4804dSStefan Eßer	_localeexists_locales="$1"
6244d4804dSStefan Eßer	shift
6344d4804dSStefan Eßer
6444d4804dSStefan Eßer	_localeexists_locale="$1"
6544d4804dSStefan Eßer	shift
6644d4804dSStefan Eßer
6744d4804dSStefan Eßer	_localeexists_destdir="$1"
6844d4804dSStefan Eßer	shift
6944d4804dSStefan Eßer
7044d4804dSStefan Eßer	if [ "$_localeexists_destdir" != "" ]; then
7144d4804dSStefan Eßer		_localeexists_char="@"
7244d4804dSStefan Eßer		_localeexists_locale="${_localeexists_locale%%_localeexists_char*}"
7344d4804dSStefan Eßer		_localeexists_char="."
7444d4804dSStefan Eßer		_localeexists_locale="${_localeexists_locale##*$_localeexists_char}"
7544d4804dSStefan Eßer	fi
7644d4804dSStefan Eßer
7744d4804dSStefan Eßer	test ! -z "${_localeexists_locales##*$_localeexists_locale*}"
7844d4804dSStefan Eßer	return $?
7944d4804dSStefan Eßer}
8044d4804dSStefan Eßer
8144d4804dSStefan Eßer# Split a path into its components. They will be separated by newlines, so paths
8244d4804dSStefan Eßer# cannot have newlines in them.
8344d4804dSStefan Eßer# @param path  The path to split.
8444d4804dSStefan Eßersplitpath() {
8544d4804dSStefan Eßer
8644d4804dSStefan Eßer	_splitpath_path="$1"
8744d4804dSStefan Eßer	shift
8844d4804dSStefan Eßer
8944d4804dSStefan Eßer	if [ "$_splitpath_path" = "${_splitpath_path#/}" ]; then
9044d4804dSStefan Eßer		printf 'Must use absolute paths\n'
9144d4804dSStefan Eßer		exit 1
9244d4804dSStefan Eßer	fi
9344d4804dSStefan Eßer
9444d4804dSStefan Eßer	if [ "${_splitpath_path#\n*}" != "$_splitpath_path" ]; then
9544d4804dSStefan Eßer		exit 1
9644d4804dSStefan Eßer	fi
9744d4804dSStefan Eßer
9844d4804dSStefan Eßer	_splitpath_list=""
9944d4804dSStefan Eßer	_splitpath_item=""
10044d4804dSStefan Eßer
10144d4804dSStefan Eßer	while [ "$_splitpath_path" != "/" ]; do
10244d4804dSStefan Eßer		_splitpath_item=$(basename "$_splitpath_path")
10344d4804dSStefan Eßer		_splitpath_list=$(printf '\n%s%s' "$_splitpath_item" "$_splitpath_list")
10444d4804dSStefan Eßer		_splitpath_path=$(dirname "$_splitpath_path")
10544d4804dSStefan Eßer	done
10644d4804dSStefan Eßer
10744d4804dSStefan Eßer	if [ "$_splitpath_list" != "/" ]; then
10844d4804dSStefan Eßer		_splitpath_list="${_splitpath_list#?}"
10944d4804dSStefan Eßer	fi
11044d4804dSStefan Eßer
11144d4804dSStefan Eßer	printf '%s' "$_splitpath_list"
11244d4804dSStefan Eßer}
11344d4804dSStefan Eßer
11444d4804dSStefan Eßer# Generate a relative path from one path to another.
11544d4804dSStefan Eßer# @param path1  The target path.
11644d4804dSStefan Eßer# @param path2  The other path.
11744d4804dSStefan Eßerrelpath() {
11844d4804dSStefan Eßer
11944d4804dSStefan Eßer	_relpath_path1="$1"
12044d4804dSStefan Eßer	shift
12144d4804dSStefan Eßer
12244d4804dSStefan Eßer	_relpath_path2="$1"
12344d4804dSStefan Eßer	shift
12444d4804dSStefan Eßer
12544d4804dSStefan Eßer	# Very carefully set IFS in a portable way. No, you cannot do IFS=$'\n'.
12644d4804dSStefan Eßer	_relpath_nl=$(printf '\nx')
12744d4804dSStefan Eßer	_relpath_nl="${_relpath_nl%x}"
12844d4804dSStefan Eßer
12944d4804dSStefan Eßer	_relpath_splitpath1=`splitpath "$_relpath_path1"`
13044d4804dSStefan Eßer	_relpath_splitpath2=`splitpath "$_relpath_path2"`
13144d4804dSStefan Eßer
13244d4804dSStefan Eßer	_relpath_path=""
13344d4804dSStefan Eßer	_relpath_temp1="$_relpath_splitpath1"
13444d4804dSStefan Eßer
13544d4804dSStefan Eßer	IFS="$_relpath_nl"
13644d4804dSStefan Eßer
13744d4804dSStefan Eßer	# What this function does is find the parts that are the same and then
13844d4804dSStefan Eßer	# calculates the difference based on how many folders up and down you must
13944d4804dSStefan Eßer	# go.
14044d4804dSStefan Eßer
14144d4804dSStefan Eßer	# This first loop basically removes the parts that are the same between
14244d4804dSStefan Eßer	# them.
14344d4804dSStefan Eßer	for _relpath_part in $_relpath_temp1; do
14444d4804dSStefan Eßer
14544d4804dSStefan Eßer		_relpath_temp2="${_relpath_splitpath2#$_relpath_part$_relpath_nl}"
14644d4804dSStefan Eßer
14744d4804dSStefan Eßer		if [ "$_relpath_temp2" = "$_relpath_splitpath2" ]; then
14844d4804dSStefan Eßer			break
14944d4804dSStefan Eßer		fi
15044d4804dSStefan Eßer
15144d4804dSStefan Eßer		_relpath_splitpath2="$_relpath_temp2"
15244d4804dSStefan Eßer		_relpath_splitpath1="${_relpath_splitpath1#$_relpath_part$_relpath_nl}"
15344d4804dSStefan Eßer
15444d4804dSStefan Eßer	done
15544d4804dSStefan Eßer
15644d4804dSStefan Eßer	# Go up the appropriate number of times.
15744d4804dSStefan Eßer	for _relpath_part in $_relpath_splitpath2; do
15844d4804dSStefan Eßer		_relpath_path="../$_relpath_path"
15944d4804dSStefan Eßer	done
16044d4804dSStefan Eßer
16144d4804dSStefan Eßer	_relpath_path="${_relpath_path%../}"
16244d4804dSStefan Eßer
16344d4804dSStefan Eßer	# Go down the appropriate number of times.
16444d4804dSStefan Eßer	for _relpath_part in $_relpath_splitpath1; do
16544d4804dSStefan Eßer		_relpath_path="$_relpath_path$_relpath_part/"
16644d4804dSStefan Eßer	done
16744d4804dSStefan Eßer
16844d4804dSStefan Eßer	_relpath_path="${_relpath_path%/}"
16944d4804dSStefan Eßer
17044d4804dSStefan Eßer	unset IFS
17144d4804dSStefan Eßer
17244d4804dSStefan Eßer	printf '%s\n' "$_relpath_path"
17344d4804dSStefan Eßer}
17444d4804dSStefan Eßer
17544d4804dSStefan Eßerscript="$0"
17644d4804dSStefan Eßerscriptdir=$(dirname "$script")
17744d4804dSStefan Eßer
17844d4804dSStefan Eßer. "$scriptdir/functions.sh"
17944d4804dSStefan Eßer
18044d4804dSStefan Eßer# Set a default.
18144d4804dSStefan Eßerall_locales=0
18244d4804dSStefan Eßer
18344d4804dSStefan Eßer# Process command-line args.
18444d4804dSStefan Eßerwhile getopts "l" opt; do
18544d4804dSStefan Eßer
18644d4804dSStefan Eßer	case "$opt" in
187103d7cdfSStefan Eßer		l) all_locales=1 ;;
18844d4804dSStefan Eßer		?) usage "Invalid option: $opt" ;;
18944d4804dSStefan Eßer	esac
19044d4804dSStefan Eßer
19144d4804dSStefan Eßerdone
192103d7cdfSStefan Eßershift $(($OPTIND - 1))
19344d4804dSStefan Eßer
1944fca8e0fSStefan Eßertest "$#" -ge 2 || usage "Must have at least two arguments"
19544d4804dSStefan Eßer
19644d4804dSStefan Eßernlspath="$1"
19744d4804dSStefan Eßershift
19844d4804dSStefan Eßer
19944d4804dSStefan Eßermain_exec="$1"
20044d4804dSStefan Eßershift
20144d4804dSStefan Eßer
20244d4804dSStefan Eßerif [ "$#" -ge 1 ]; then
20344d4804dSStefan Eßer	destdir="$1"
20444d4804dSStefan Eßer	shift
20544d4804dSStefan Eßerelse
20644d4804dSStefan Eßer	destdir=""
20744d4804dSStefan Eßerfi
20844d4804dSStefan Eßer
20944d4804dSStefan Eßer# Uninstall locales first.
21044d4804dSStefan Eßer"$scriptdir/locale_uninstall.sh" "$nlspath" "$main_exec" "$destdir"
21144d4804dSStefan Eßer
21244d4804dSStefan Eßerlocales_dir="$scriptdir/../locales"
21344d4804dSStefan Eßer
21444d4804dSStefan Eßer# What this does is if installing to a package, it installs all locales that
21544d4804dSStefan Eßer# match supported charsets instead of installing all directly supported locales.
21644d4804dSStefan Eßerif [ "$destdir" = "" ]; then
21744d4804dSStefan Eßer	locales=$(locale -a)
21844d4804dSStefan Eßerelse
21944d4804dSStefan Eßer	locales=$(locale -m)
22044d4804dSStefan Eßerfi
22144d4804dSStefan Eßer
22244d4804dSStefan Eßer# For each relevant .msg file, run gencat.
22344d4804dSStefan Eßerfor file in $locales_dir/*.msg; do
22444d4804dSStefan Eßer
22544d4804dSStefan Eßer	locale=$(basename "$file" ".msg")
22644d4804dSStefan Eßer
22744d4804dSStefan Eßer	# If we are not installing all locales, there's a possibility we need to
22844d4804dSStefan Eßer	# skip this one.
22944d4804dSStefan Eßer	if [ "$all_locales" -eq 0 ]; then
23044d4804dSStefan Eßer
23144d4804dSStefan Eßer		# Check if the locale exists and if not skip.
23244d4804dSStefan Eßer		localeexists "$locales" "$locale" "$destdir"
23344d4804dSStefan Eßer		err="$?"
23444d4804dSStefan Eßer
23544d4804dSStefan Eßer		if [ "$err" -eq 0 ]; then
23644d4804dSStefan Eßer			continue
23744d4804dSStefan Eßer		fi
23844d4804dSStefan Eßer	fi
23944d4804dSStefan Eßer
24044d4804dSStefan Eßer	# We skip the symlinks for now.
24144d4804dSStefan Eßer	if [ -L "$file" ]; then
24244d4804dSStefan Eßer		continue
24344d4804dSStefan Eßer	fi
24444d4804dSStefan Eßer
2454fca8e0fSStefan Eßer	printf 'Installing %s...' "$locale"
2464fca8e0fSStefan Eßer
24744d4804dSStefan Eßer	# Generate the proper location for the cat file.
24844d4804dSStefan Eßer	loc=$(gen_nlspath "$destdir/$nlspath" "$locale" "$main_exec")
24944d4804dSStefan Eßer
25044d4804dSStefan Eßer	gencatfile "$loc" "$file"
25144d4804dSStefan Eßer
2524fca8e0fSStefan Eßer	printf 'done\n'
2534fca8e0fSStefan Eßer
25444d4804dSStefan Eßerdone
25544d4804dSStefan Eßer
25644d4804dSStefan Eßer# Now that we have done the non-symlinks, it's time to do the symlinks. Think
25744d4804dSStefan Eßer# that this second loop is unnecessary and that you can combine the two? Well,
25844d4804dSStefan Eßer# make sure that when you figure out you are wrong that you add to this comment
25944d4804dSStefan Eßer# with your story. Fortunately for me, I learned fast.
26044d4804dSStefan Eßerfor file in $locales_dir/*.msg; do
26144d4804dSStefan Eßer
26244d4804dSStefan Eßer	locale=$(basename "$file" ".msg")
26344d4804dSStefan Eßer
26444d4804dSStefan Eßer	# Do the same skip as the above loop.
26544d4804dSStefan Eßer	if [ "$all_locales" -eq 0 ]; then
26644d4804dSStefan Eßer
26744d4804dSStefan Eßer		localeexists "$locales" "$locale" "$destdir"
26844d4804dSStefan Eßer		err="$?"
26944d4804dSStefan Eßer
27044d4804dSStefan Eßer		if [ "$err" -eq 0 ]; then
27144d4804dSStefan Eßer			continue
27244d4804dSStefan Eßer		fi
27344d4804dSStefan Eßer	fi
27444d4804dSStefan Eßer
27544d4804dSStefan Eßer	# Generate the proper location for the cat file.
27644d4804dSStefan Eßer	loc=$(gen_nlspath "$destdir/$nlspath" "$locale" "$main_exec")
27744d4804dSStefan Eßer
27844d4804dSStefan Eßer	# Make sure the directory exists.
27944d4804dSStefan Eßer	mkdir -p $(dirname "$loc")
28044d4804dSStefan Eßer
28144d4804dSStefan Eßer	# Make sure to skip non-symlinks; they are already done.
28244d4804dSStefan Eßer	if [ -L "$file" ]; then
28344d4804dSStefan Eßer
2844fca8e0fSStefan Eßer		printf 'Linking %s...' "$locale"
2854fca8e0fSStefan Eßer
28644d4804dSStefan Eßer		# This song and dance is because we want to generate relative symlinks.
28744d4804dSStefan Eßer		# They take less space, but also, they are more resilient to being
28844d4804dSStefan Eßer		# moved.
28944d4804dSStefan Eßer		link=$(readlink "$file")
29044d4804dSStefan Eßer		linkdir=$(dirname "$file")
29144d4804dSStefan Eßer		locale=$(basename "$link" .msg)
29244d4804dSStefan Eßer		linksrc=$(gen_nlspath "$nlspath" "$locale" "$main_exec")
29344d4804dSStefan Eßer		relloc="${loc##$destdir/}"
29444d4804dSStefan Eßer		rel=$(relpath "$linksrc" "$relloc")
29544d4804dSStefan Eßer
29644d4804dSStefan Eßer		# If the target file doesn't exist (because it's for a locale that is
29744d4804dSStefan Eßer		# not installed), generate it anyway. It's easier this way.
29844d4804dSStefan Eßer		if [ ! -f "$destdir/$linksrc" ]; then
29944d4804dSStefan Eßer			gencatfile "$destdir/$linksrc" "$linkdir/$link"
30044d4804dSStefan Eßer		fi
30144d4804dSStefan Eßer
30244d4804dSStefan Eßer		# Finally, symlink to the install of the generated cat file that
30344d4804dSStefan Eßer		# corresponds to the correct msg file.
30444d4804dSStefan Eßer		ln -fs "$rel" "$loc"
3054fca8e0fSStefan Eßer
3064fca8e0fSStefan Eßer		printf 'done\n'
30744d4804dSStefan Eßer	fi
30844d4804dSStefan Eßer
30944d4804dSStefan Eßerdone
310