xref: /freebsd/contrib/bc/scripts/locale_install.sh (revision 942815c54820783d3d4f7f6faa71ab7919b5f0e5)
1#! /bin/sh
2#
3# SPDX-License-Identifier: BSD-2-Clause
4#
5# Copyright (c) 2018-2023 Gavin D. Howard and contributors.
6#
7# Redistribution and use in source and binary forms, with or without
8# modification, are permitted provided that the following conditions are met:
9#
10# * Redistributions of source code must retain the above copyright notice, this
11#   list of conditions and the following disclaimer.
12#
13# * Redistributions in binary form must reproduce the above copyright notice,
14#   this list of conditions and the following disclaimer in the documentation
15#   and/or other materials provided with the distribution.
16#
17# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27# POSSIBILITY OF SUCH DAMAGE.
28#
29
30# Just print the usage and exit with an error.
31# @param 1  A message to print.
32usage() {
33	if [ $# -eq 1 ]; then
34		printf '%s\n' "$1"
35	fi
36	printf "usage: %s [-l] NLSPATH main_exec [DESTDIR]\n" "$0" 1>&2
37	exit 1
38}
39
40# Run gencat on one file.
41# @param loc   The location of the resulting cat file.
42# @param file  The file to use as the source for the cat file.
43gencatfile() {
44
45	_gencatfile_loc="$1"
46	shift
47
48	_gencatfile_file="$1"
49	shift
50
51	mkdir -p $(dirname "$_gencatfile_loc")
52	gencat "$_gencatfile_loc" "$_gencatfile_file" > /dev/null 2>&1
53}
54
55# Return an exit code based on whether a locale exists.
56# @param locales  The list of locales.
57# @param locale   The locale to search for.
58# @param destdir  The DESTDIR that locales should be installed to.
59localeexists() {
60
61	_localeexists_locales="$1"
62	shift
63
64	_localeexists_locale="$1"
65	shift
66
67	_localeexists_destdir="$1"
68	shift
69
70	if [ "$_localeexists_destdir" != "" ]; then
71		_localeexists_char="@"
72		_localeexists_locale="${_localeexists_locale%%_localeexists_char*}"
73		_localeexists_char="."
74		_localeexists_locale="${_localeexists_locale##*$_localeexists_char}"
75	fi
76
77	test ! -z "${_localeexists_locales##*$_localeexists_locale*}"
78	return $?
79}
80
81# Split a path into its components. They will be separated by newlines, so paths
82# cannot have newlines in them.
83# @param path  The path to split.
84splitpath() {
85
86	_splitpath_path="$1"
87	shift
88
89	if [ "$_splitpath_path" = "${_splitpath_path#/}" ]; then
90		printf 'Must use absolute paths\n'
91		exit 1
92	fi
93
94	if [ "${_splitpath_path#\n*}" != "$_splitpath_path" ]; then
95		exit 1
96	fi
97
98	_splitpath_list=""
99	_splitpath_item=""
100
101	while [ "$_splitpath_path" != "/" ]; do
102		_splitpath_item=$(basename "$_splitpath_path")
103		_splitpath_list=$(printf '\n%s%s' "$_splitpath_item" "$_splitpath_list")
104		_splitpath_path=$(dirname "$_splitpath_path")
105	done
106
107	if [ "$_splitpath_list" != "/" ]; then
108		_splitpath_list="${_splitpath_list#?}"
109	fi
110
111	printf '%s' "$_splitpath_list"
112}
113
114# Generate a relative path from one path to another.
115# @param path1  The target path.
116# @param path2  The other path.
117relpath() {
118
119	_relpath_path1="$1"
120	shift
121
122	_relpath_path2="$1"
123	shift
124
125	# Very carefully set IFS in a portable way. No, you cannot do IFS=$'\n'.
126	_relpath_nl=$(printf '\nx')
127	_relpath_nl="${_relpath_nl%x}"
128
129	_relpath_splitpath1=`splitpath "$_relpath_path1"`
130	_relpath_splitpath2=`splitpath "$_relpath_path2"`
131
132	_relpath_path=""
133	_relpath_temp1="$_relpath_splitpath1"
134
135	IFS="$_relpath_nl"
136
137	# What this function does is find the parts that are the same and then
138	# calculates the difference based on how many folders up and down you must
139	# go.
140
141	# This first loop basically removes the parts that are the same between
142	# them.
143	for _relpath_part in $_relpath_temp1; do
144
145		_relpath_temp2="${_relpath_splitpath2#$_relpath_part$_relpath_nl}"
146
147		if [ "$_relpath_temp2" = "$_relpath_splitpath2" ]; then
148			break
149		fi
150
151		_relpath_splitpath2="$_relpath_temp2"
152		_relpath_splitpath1="${_relpath_splitpath1#$_relpath_part$_relpath_nl}"
153
154	done
155
156	# Go up the appropriate number of times.
157	for _relpath_part in $_relpath_splitpath2; do
158		_relpath_path="../$_relpath_path"
159	done
160
161	_relpath_path="${_relpath_path%../}"
162
163	# Go down the appropriate number of times.
164	for _relpath_part in $_relpath_splitpath1; do
165		_relpath_path="$_relpath_path$_relpath_part/"
166	done
167
168	_relpath_path="${_relpath_path%/}"
169
170	unset IFS
171
172	printf '%s\n' "$_relpath_path"
173}
174
175script="$0"
176scriptdir=$(dirname "$script")
177
178. "$scriptdir/functions.sh"
179
180# Set a default.
181all_locales=0
182
183# Process command-line args.
184while getopts "l" opt; do
185
186	case "$opt" in
187		l) all_locales=1 ; shift ;;
188		?) usage "Invalid option: $opt" ;;
189	esac
190
191done
192
193test "$#" -ge 2 || usage "Must have at least two arguments"
194
195nlspath="$1"
196shift
197
198main_exec="$1"
199shift
200
201if [ "$#" -ge 1 ]; then
202	destdir="$1"
203	shift
204else
205	destdir=""
206fi
207
208# Uninstall locales first.
209"$scriptdir/locale_uninstall.sh" "$nlspath" "$main_exec" "$destdir"
210
211locales_dir="$scriptdir/../locales"
212
213# What this does is if installing to a package, it installs all locales that
214# match supported charsets instead of installing all directly supported locales.
215if [ "$destdir" = "" ]; then
216	locales=$(locale -a)
217else
218	locales=$(locale -m)
219fi
220
221# For each relevant .msg file, run gencat.
222for file in $locales_dir/*.msg; do
223
224	locale=$(basename "$file" ".msg")
225
226	# If we are not installing all locales, there's a possibility we need to
227	# skip this one.
228	if [ "$all_locales" -eq 0 ]; then
229
230		# Check if the locale exists and if not skip.
231		localeexists "$locales" "$locale" "$destdir"
232		err="$?"
233
234		if [ "$err" -eq 0 ]; then
235			continue
236		fi
237	fi
238
239	# We skip the symlinks for now.
240	if [ -L "$file" ]; then
241		continue
242	fi
243
244	printf 'Installing %s...' "$locale"
245
246	# Generate the proper location for the cat file.
247	loc=$(gen_nlspath "$destdir/$nlspath" "$locale" "$main_exec")
248
249	gencatfile "$loc" "$file"
250
251	printf 'done\n'
252
253done
254
255# Now that we have done the non-symlinks, it's time to do the symlinks. Think
256# that this second loop is unnecessary and that you can combine the two? Well,
257# make sure that when you figure out you are wrong that you add to this comment
258# with your story. Fortunately for me, I learned fast.
259for file in $locales_dir/*.msg; do
260
261	locale=$(basename "$file" ".msg")
262
263	# Do the same skip as the above loop.
264	if [ "$all_locales" -eq 0 ]; then
265
266		localeexists "$locales" "$locale" "$destdir"
267		err="$?"
268
269		if [ "$err" -eq 0 ]; then
270			continue
271		fi
272	fi
273
274	# Generate the proper location for the cat file.
275	loc=$(gen_nlspath "$destdir/$nlspath" "$locale" "$main_exec")
276
277	# Make sure the directory exists.
278	mkdir -p $(dirname "$loc")
279
280	# Make sure to skip non-symlinks; they are already done.
281	if [ -L "$file" ]; then
282
283		printf 'Linking %s...' "$locale"
284
285		# This song and dance is because we want to generate relative symlinks.
286		# They take less space, but also, they are more resilient to being
287		# moved.
288		link=$(readlink "$file")
289		linkdir=$(dirname "$file")
290		locale=$(basename "$link" .msg)
291		linksrc=$(gen_nlspath "$nlspath" "$locale" "$main_exec")
292		relloc="${loc##$destdir/}"
293		rel=$(relpath "$linksrc" "$relloc")
294
295		# If the target file doesn't exist (because it's for a locale that is
296		# not installed), generate it anyway. It's easier this way.
297		if [ ! -f "$destdir/$linksrc" ]; then
298			gencatfile "$destdir/$linksrc" "$linkdir/$link"
299		fi
300
301		# Finally, symlink to the install of the generated cat file that
302		# corresponds to the correct msg file.
303		ln -fs "$rel" "$loc"
304
305		printf 'done\n'
306	fi
307
308done
309