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