xref: /src/contrib/bc/scripts/functions.sh (revision fdc4a7c8012b214986cfa2e2fb6d99731f004b1b)
11f958cfaSStefan Eßer#! /bin/sh
21f958cfaSStefan Eßer#
33960d892SStefan Eßer# SPDX-License-Identifier: BSD-2-Clause
41f958cfaSStefan Eßer#
5682da5a0SStefan Eßer# Copyright (c) 2018-2025 Gavin D. Howard and contributors.
61f958cfaSStefan Eßer#
71f958cfaSStefan Eßer# Redistribution and use in source and binary forms, with or without
81f958cfaSStefan Eßer# modification, are permitted provided that the following conditions are met:
91f958cfaSStefan Eßer#
101f958cfaSStefan Eßer# * Redistributions of source code must retain the above copyright notice, this
111f958cfaSStefan Eßer#   list of conditions and the following disclaimer.
121f958cfaSStefan Eßer#
131f958cfaSStefan Eßer# * Redistributions in binary form must reproduce the above copyright notice,
141f958cfaSStefan Eßer#   this list of conditions and the following disclaimer in the documentation
151f958cfaSStefan Eßer#   and/or other materials provided with the distribution.
161f958cfaSStefan Eßer#
171f958cfaSStefan Eßer# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
181f958cfaSStefan Eßer# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
191f958cfaSStefan Eßer# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
201f958cfaSStefan Eßer# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
211f958cfaSStefan Eßer# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
221f958cfaSStefan Eßer# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
231f958cfaSStefan Eßer# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
241f958cfaSStefan Eßer# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
251f958cfaSStefan Eßer# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
261f958cfaSStefan Eßer# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
271f958cfaSStefan Eßer# POSSIBILITY OF SUCH DAMAGE.
281f958cfaSStefan Eßer#
291f958cfaSStefan Eßer
302f57ecaeSStefan Eßer# This script is NOT meant to be run! It is meant to be sourced by other
312f57ecaeSStefan Eßer# scripts.
322f57ecaeSStefan Eßer
332f57ecaeSStefan Eßer# Reads and follows a link until it finds a real file. This is here because the
342f57ecaeSStefan Eßer# readlink utility is not part of the POSIX standard. Sigh...
352f57ecaeSStefan Eßer# @param f  The link to find the original file for.
361f958cfaSStefan Eßerreadlink() {
371f958cfaSStefan Eßer
381f958cfaSStefan Eßer	_readlink_f="$1"
391f958cfaSStefan Eßer	shift
401f958cfaSStefan Eßer
411f958cfaSStefan Eßer	_readlink_arrow="-> "
421f958cfaSStefan Eßer	_readlink_d=$(dirname "$_readlink_f")
431f958cfaSStefan Eßer
441f958cfaSStefan Eßer	_readlink_lsout=""
451f958cfaSStefan Eßer	_readlink_link=""
461f958cfaSStefan Eßer
471f958cfaSStefan Eßer	_readlink_lsout=$(ls -dl "$_readlink_f")
481f958cfaSStefan Eßer	_readlink_link=$(printf '%s' "${_readlink_lsout#*$_readlink_arrow}")
491f958cfaSStefan Eßer
501f958cfaSStefan Eßer	while [ -z "${_readlink_lsout##*$_readlink_arrow*}" ]; do
511f958cfaSStefan Eßer		_readlink_f="$_readlink_d/$_readlink_link"
521f958cfaSStefan Eßer		_readlink_d=$(dirname "$_readlink_f")
531f958cfaSStefan Eßer		_readlink_lsout=$(ls -dl "$_readlink_f")
541f958cfaSStefan Eßer		_readlink_link=$(printf '%s' "${_readlink_lsout#*$_readlink_arrow}")
551f958cfaSStefan Eßer	done
561f958cfaSStefan Eßer
571f958cfaSStefan Eßer	printf '%s' "${_readlink_f##*$_readlink_d/}"
581f958cfaSStefan Eßer}
591f958cfaSStefan Eßer
602f57ecaeSStefan Eßer# Quick function for exiting with an error.
612f57ecaeSStefan Eßer# @param 1  A message to print.
622f57ecaeSStefan Eßer# @param 2  The exit code to use.
631f958cfaSStefan Eßererr_exit() {
641f958cfaSStefan Eßer
651f958cfaSStefan Eßer	if [ "$#" -ne 2 ]; then
661f958cfaSStefan Eßer		printf 'Invalid number of args to err_exit\n'
671f958cfaSStefan Eßer		exit 1
681f958cfaSStefan Eßer	fi
691f958cfaSStefan Eßer
701f958cfaSStefan Eßer	printf '%s\n' "$1"
711f958cfaSStefan Eßer	exit "$2"
721f958cfaSStefan Eßer}
731f958cfaSStefan Eßer
74aaf1213cSStefan Eßer# Function for checking the "d"/"dir" argument of scripts. This function expects
75aaf1213cSStefan Eßer# a usage() function to exist in the caller.
76aaf1213cSStefan Eßer# @param 1  The argument to check.
77aaf1213cSStefan Eßercheck_d_arg() {
78aaf1213cSStefan Eßer
79aaf1213cSStefan Eßer	if [ "$#" -ne 1 ]; then
80aaf1213cSStefan Eßer		printf 'Invalid number of args to check_d_arg\n'
81aaf1213cSStefan Eßer		exit 1
82aaf1213cSStefan Eßer	fi
83aaf1213cSStefan Eßer
84aaf1213cSStefan Eßer	_check_d_arg_arg="$1"
85aaf1213cSStefan Eßer	shift
86aaf1213cSStefan Eßer
87aaf1213cSStefan Eßer	if [ "$_check_d_arg_arg" != "bc" ] && [ "$_check_d_arg_arg" != "dc" ]; then
88aaf1213cSStefan Eßer		_check_d_arg_msg=$(printf 'Invalid d arg: %s\nMust be either "bc" or "dc".\n\n' \
89aaf1213cSStefan Eßer			"$_check_d_arg_arg")
90aaf1213cSStefan Eßer		usage "$_check_d_arg_msg"
91aaf1213cSStefan Eßer	fi
92aaf1213cSStefan Eßer}
93aaf1213cSStefan Eßer
94aaf1213cSStefan Eßer# Function for checking the boolean arguments of scripts. This function expects
95aaf1213cSStefan Eßer# a usage() function to exist in the caller.
96aaf1213cSStefan Eßer# @param 1  The argument to check.
97aaf1213cSStefan Eßercheck_bool_arg() {
98aaf1213cSStefan Eßer
99aaf1213cSStefan Eßer	if [ "$#" -ne 1 ]; then
100aaf1213cSStefan Eßer		printf 'Invalid number of args to check_bool_arg\n'
101aaf1213cSStefan Eßer		exit 1
102aaf1213cSStefan Eßer	fi
103aaf1213cSStefan Eßer
104aaf1213cSStefan Eßer	_check_bool_arg_arg="$1"
105aaf1213cSStefan Eßer	shift
106aaf1213cSStefan Eßer
107aaf1213cSStefan Eßer	if [ "$_check_bool_arg_arg" != "0" ] && [ "$_check_bool_arg_arg" != "1" ]; then
108aaf1213cSStefan Eßer		_check_bool_arg_msg=$(printf 'Invalid bool arg: %s\nMust be either "0" or "1".\n\n' \
109aaf1213cSStefan Eßer			"$_check_bool_arg_arg")
110aaf1213cSStefan Eßer		usage "$_check_bool_arg_msg"
111aaf1213cSStefan Eßer	fi
112aaf1213cSStefan Eßer}
113aaf1213cSStefan Eßer
114aaf1213cSStefan Eßer# Function for checking the executable arguments of scripts. This function
115aaf1213cSStefan Eßer# expects a usage() function to exist in the caller.
116aaf1213cSStefan Eßer# @param 1  The argument to check.
117aaf1213cSStefan Eßercheck_exec_arg() {
118aaf1213cSStefan Eßer
119aaf1213cSStefan Eßer	if [ "$#" -ne 1 ]; then
120aaf1213cSStefan Eßer		printf 'Invalid number of args to check_exec_arg\n'
121aaf1213cSStefan Eßer		exit 1
122aaf1213cSStefan Eßer	fi
123aaf1213cSStefan Eßer
124aaf1213cSStefan Eßer	_check_exec_arg_arg="$1"
125aaf1213cSStefan Eßer	shift
126aaf1213cSStefan Eßer
127aaf1213cSStefan Eßer	if [ ! -x "$_check_exec_arg_arg" ]; then
128aaf1213cSStefan Eßer		if ! command -v "$_check_exec_arg_arg" >/dev/null 2>&1; then
129aaf1213cSStefan Eßer			_check_exec_arg_msg=$(printf 'Invalid exec arg: %s\nMust be an executable file.\n\n' \
130aaf1213cSStefan Eßer				"$_check_exec_arg_arg")
131aaf1213cSStefan Eßer			usage "$_check_exec_arg_msg"
132aaf1213cSStefan Eßer		fi
133aaf1213cSStefan Eßer	fi
134aaf1213cSStefan Eßer}
135aaf1213cSStefan Eßer
136aaf1213cSStefan Eßer# Function for checking the file arguments of scripts. This function expects a
137aaf1213cSStefan Eßer# usage() function to exist in the caller.
138aaf1213cSStefan Eßer# @param 1  The argument to check.
139aaf1213cSStefan Eßercheck_file_arg() {
140aaf1213cSStefan Eßer
141aaf1213cSStefan Eßer	if [ "$#" -ne 1 ]; then
142aaf1213cSStefan Eßer		printf 'Invalid number of args to check_file_arg\n'
143aaf1213cSStefan Eßer		exit 1
144aaf1213cSStefan Eßer	fi
145aaf1213cSStefan Eßer
146aaf1213cSStefan Eßer	_check_file_arg_arg="$1"
147aaf1213cSStefan Eßer	shift
148aaf1213cSStefan Eßer
149aaf1213cSStefan Eßer	if [ ! -f "$_check_file_arg_arg" ]; then
150aaf1213cSStefan Eßer		_check_file_arg_msg=$(printf 'Invalid file arg: %s\nMust be a file.\n\n' \
151aaf1213cSStefan Eßer			"$_check_file_arg_arg")
152aaf1213cSStefan Eßer		usage "$_check_file_arg_msg"
153aaf1213cSStefan Eßer	fi
154aaf1213cSStefan Eßer}
155aaf1213cSStefan Eßer
1562f57ecaeSStefan Eßer# Check the return code on a test and exit with a fail if it's non-zero.
1572f57ecaeSStefan Eßer# @param d     The calculator under test.
1582f57ecaeSStefan Eßer# @param err   The return code.
1592f57ecaeSStefan Eßer# @param name  The name of the test.
16047a52dc4SStefan Eßerchecktest_retcode() {
16147a52dc4SStefan Eßer
16247a52dc4SStefan Eßer	_checktest_retcode_d="$1"
16347a52dc4SStefan Eßer	shift
16447a52dc4SStefan Eßer
16547a52dc4SStefan Eßer	_checktest_retcode_err="$1"
16647a52dc4SStefan Eßer	shift
16747a52dc4SStefan Eßer
16847a52dc4SStefan Eßer	_checktest_retcode_name="$1"
16947a52dc4SStefan Eßer	shift
17047a52dc4SStefan Eßer
17147a52dc4SStefan Eßer	if [ "$_checktest_retcode_err" -ne 0 ]; then
17247a52dc4SStefan Eßer		printf 'FAIL!!!\n'
17347a52dc4SStefan Eßer		err_exit "$_checktest_retcode_d failed test '$_checktest_retcode_name' with error code $_checktest_retcode_err" 1
17447a52dc4SStefan Eßer	fi
17547a52dc4SStefan Eßer}
17647a52dc4SStefan Eßer
1772f57ecaeSStefan Eßer# Check the result of a test. First, it checks the error code using
1782f57ecaeSStefan Eßer# checktest_retcode(). Then it checks the output against the expected output
1792f57ecaeSStefan Eßer# and fails if it doesn't match.
1802f57ecaeSStefan Eßer# @param d             The calculator under test.
1812f57ecaeSStefan Eßer# @param err           The error code.
1822f57ecaeSStefan Eßer# @param name          The name of the test.
1832f57ecaeSStefan Eßer# @param test_path     The path to the test.
1842f57ecaeSStefan Eßer# @param results_name  The path to the file with the expected result.
18547a52dc4SStefan Eßerchecktest() {
18647a52dc4SStefan Eßer
18747a52dc4SStefan Eßer	_checktest_d="$1"
18847a52dc4SStefan Eßer	shift
18947a52dc4SStefan Eßer
19047a52dc4SStefan Eßer	_checktest_err="$1"
19147a52dc4SStefan Eßer	shift
19247a52dc4SStefan Eßer
19347a52dc4SStefan Eßer	_checktest_name="$1"
19447a52dc4SStefan Eßer	shift
19547a52dc4SStefan Eßer
19647a52dc4SStefan Eßer	_checktest_test_path="$1"
19747a52dc4SStefan Eßer	shift
19847a52dc4SStefan Eßer
19947a52dc4SStefan Eßer	_checktest_results_name="$1"
20047a52dc4SStefan Eßer	shift
20147a52dc4SStefan Eßer
20247a52dc4SStefan Eßer	checktest_retcode "$_checktest_d" "$_checktest_err" "$_checktest_name"
20347a52dc4SStefan Eßer
20447a52dc4SStefan Eßer	_checktest_diff=$(diff "$_checktest_test_path" "$_checktest_results_name")
20547a52dc4SStefan Eßer
20647a52dc4SStefan Eßer	_checktest_err="$?"
20747a52dc4SStefan Eßer
20847a52dc4SStefan Eßer	if [ "$_checktest_err" -ne 0 ]; then
20947a52dc4SStefan Eßer		printf 'FAIL!!!\n'
21047a52dc4SStefan Eßer		printf '%s\n' "$_checktest_diff"
21147a52dc4SStefan Eßer		err_exit "$_checktest_d failed test $_checktest_name" 1
21247a52dc4SStefan Eßer	fi
21347a52dc4SStefan Eßer}
21447a52dc4SStefan Eßer
2152f57ecaeSStefan Eßer# Die. With a message.
2162f57ecaeSStefan Eßer# @param d     The calculator under test.
2172f57ecaeSStefan Eßer# @param msg   The message to print.
2182f57ecaeSStefan Eßer# @param name  The name of the test.
2192f57ecaeSStefan Eßer# @param err   The return code from the test.
2201f958cfaSStefan Eßerdie() {
2211f958cfaSStefan Eßer
2221f958cfaSStefan Eßer	_die_d="$1"
2231f958cfaSStefan Eßer	shift
2241f958cfaSStefan Eßer
2251f958cfaSStefan Eßer	_die_msg="$1"
2261f958cfaSStefan Eßer	shift
2271f958cfaSStefan Eßer
2281f958cfaSStefan Eßer	_die_name="$1"
2291f958cfaSStefan Eßer	shift
2301f958cfaSStefan Eßer
2311f958cfaSStefan Eßer	_die_err="$1"
2321f958cfaSStefan Eßer	shift
2331f958cfaSStefan Eßer
2341f958cfaSStefan Eßer	_die_str=$(printf '\n%s %s on test:\n\n    %s\n' "$_die_d" "$_die_msg" "$_die_name")
2351f958cfaSStefan Eßer
2361f958cfaSStefan Eßer	err_exit "$_die_str" "$_die_err"
2371f958cfaSStefan Eßer}
2381f958cfaSStefan Eßer
2392f57ecaeSStefan Eßer# Check that a test did not crash and die if it did.
2402f57ecaeSStefan Eßer# @param d      The calculator under test.
2412f57ecaeSStefan Eßer# @param error  The error code.
2422f57ecaeSStefan Eßer# @param name   The name of the test.
2431f958cfaSStefan Eßercheckcrash() {
2441f958cfaSStefan Eßer
2451f958cfaSStefan Eßer	_checkcrash_d="$1"
2461f958cfaSStefan Eßer	shift
2471f958cfaSStefan Eßer
2481f958cfaSStefan Eßer	_checkcrash_error="$1"
2491f958cfaSStefan Eßer	shift
2501f958cfaSStefan Eßer
2511f958cfaSStefan Eßer	_checkcrash_name="$1"
2521f958cfaSStefan Eßer	shift
2531f958cfaSStefan Eßer
2542f57ecaeSStefan Eßer
2551f958cfaSStefan Eßer	if [ "$_checkcrash_error" -gt 127 ]; then
2561f958cfaSStefan Eßer		die "$_checkcrash_d" "crashed ($_checkcrash_error)" \
2571f958cfaSStefan Eßer			"$_checkcrash_name" "$_checkcrash_error"
2581f958cfaSStefan Eßer	fi
2591f958cfaSStefan Eßer}
2601f958cfaSStefan Eßer
2612f57ecaeSStefan Eßer# Check that a test had an error or crash.
2622f57ecaeSStefan Eßer# @param d        The calculator under test.
2632f57ecaeSStefan Eßer# @param error    The error code.
2642f57ecaeSStefan Eßer# @param name     The name of the test.
2652f57ecaeSStefan Eßer# @param out      The file that the test results were output to.
2662f57ecaeSStefan Eßer# @param exebase  The name of the executable.
26747a52dc4SStefan Eßercheckerrtest()
2681f958cfaSStefan Eßer{
26947a52dc4SStefan Eßer	_checkerrtest_d="$1"
2701f958cfaSStefan Eßer	shift
2711f958cfaSStefan Eßer
27247a52dc4SStefan Eßer	_checkerrtest_error="$1"
2731f958cfaSStefan Eßer	shift
2741f958cfaSStefan Eßer
27547a52dc4SStefan Eßer	_checkerrtest_name="$1"
2761f958cfaSStefan Eßer	shift
2771f958cfaSStefan Eßer
27847a52dc4SStefan Eßer	_checkerrtest_out="$1"
2791f958cfaSStefan Eßer	shift
2801f958cfaSStefan Eßer
28147a52dc4SStefan Eßer	_checkerrtest_exebase="$1"
2821f958cfaSStefan Eßer	shift
2831f958cfaSStefan Eßer
28447a52dc4SStefan Eßer	checkcrash "$_checkerrtest_d" "$_checkerrtest_error" "$_checkerrtest_name"
2851f958cfaSStefan Eßer
28647a52dc4SStefan Eßer	if [ "$_checkerrtest_error" -eq 0 ]; then
28747a52dc4SStefan Eßer		die "$_checkerrtest_d" "returned no error" "$_checkerrtest_name" 127
2881f958cfaSStefan Eßer	fi
2891f958cfaSStefan Eßer
2902f57ecaeSStefan Eßer	# This is to check for memory errors with Valgrind, which is told to return
2912f57ecaeSStefan Eßer	# 100 on memory errors.
29247a52dc4SStefan Eßer	if [ "$_checkerrtest_error" -eq 100 ]; then
2931f958cfaSStefan Eßer
29447a52dc4SStefan Eßer		_checkerrtest_output=$(cat "$_checkerrtest_out")
29547a52dc4SStefan Eßer		_checkerrtest_fatal_error="Fatal error"
2961f958cfaSStefan Eßer
29747a52dc4SStefan Eßer		if [ "${_checkerrtest_output##*$_checkerrtest_fatal_error*}" ]; then
29847a52dc4SStefan Eßer			printf "%s\n" "$_checkerrtest_output"
29947a52dc4SStefan Eßer			die "$_checkerrtest_d" "had memory errors on a non-fatal error" \
30047a52dc4SStefan Eßer				"$_checkerrtest_name" "$_checkerrtest_error"
3011f958cfaSStefan Eßer		fi
3021f958cfaSStefan Eßer	fi
3031f958cfaSStefan Eßer
30447a52dc4SStefan Eßer	if [ ! -s "$_checkerrtest_out" ]; then
30547a52dc4SStefan Eßer		die "$_checkerrtest_d" "produced no error message" "$_checkerrtest_name" "$_checkerrtest_error"
3061f958cfaSStefan Eßer	fi
3071f958cfaSStefan Eßer
3085d58a515SStefan Eßer	# To display error messages, uncomment this line. This is useful when
3095d58a515SStefan Eßer	# debugging.
3105d58a515SStefan Eßer	#cat "$_checkerrtest_out"
3111f958cfaSStefan Eßer}
3121f958cfaSStefan Eßer
3132f57ecaeSStefan Eßer# Replace a substring in a string with another. This function is the *real*
3142f57ecaeSStefan Eßer# workhorse behind configure.sh's generation of a Makefile.
3152f57ecaeSStefan Eßer#
3162f57ecaeSStefan Eßer# This function uses a sed call that uses exclamation points `!` as delimiters.
3172f57ecaeSStefan Eßer# As a result, needle can never contain an exclamation point. Oh well.
3182f57ecaeSStefan Eßer#
3192f57ecaeSStefan Eßer# @param str          The string that will have any of the needle replaced by
3202f57ecaeSStefan Eßer#                     replacement.
3212f57ecaeSStefan Eßer# @param needle       The needle to replace in str with replacement.
3222f57ecaeSStefan Eßer# @param replacement  The replacement for needle in str.
3231f958cfaSStefan Eßersubstring_replace() {
3241f958cfaSStefan Eßer
3251f958cfaSStefan Eßer	_substring_replace_str="$1"
3261f958cfaSStefan Eßer	shift
3271f958cfaSStefan Eßer
3281f958cfaSStefan Eßer	_substring_replace_needle="$1"
3291f958cfaSStefan Eßer	shift
3301f958cfaSStefan Eßer
3311f958cfaSStefan Eßer	_substring_replace_replacement="$1"
3321f958cfaSStefan Eßer	shift
3331f958cfaSStefan Eßer
3341f958cfaSStefan Eßer	_substring_replace_result=$(printf '%s\n' "$_substring_replace_str" | \
3351f958cfaSStefan Eßer		sed -e "s!$_substring_replace_needle!$_substring_replace_replacement!g")
3361f958cfaSStefan Eßer
3371f958cfaSStefan Eßer	printf '%s' "$_substring_replace_result"
3381f958cfaSStefan Eßer}
3391f958cfaSStefan Eßer
3402f57ecaeSStefan Eßer# Generates an NLS path based on the locale and executable name.
3412f57ecaeSStefan Eßer#
3422f57ecaeSStefan Eßer# This is a monstrosity for a reason.
3432f57ecaeSStefan Eßer#
3442f57ecaeSStefan Eßer# @param nlspath   The $NLSPATH
3452f57ecaeSStefan Eßer# @param locale    The locale.
3462f57ecaeSStefan Eßer# @param execname  The name of the executable.
3471f958cfaSStefan Eßergen_nlspath() {
3481f958cfaSStefan Eßer
3491f958cfaSStefan Eßer	_gen_nlspath_nlspath="$1"
3501f958cfaSStefan Eßer	shift
3511f958cfaSStefan Eßer
3521f958cfaSStefan Eßer	_gen_nlspath_locale="$1"
3531f958cfaSStefan Eßer	shift
3541f958cfaSStefan Eßer
3551f958cfaSStefan Eßer	_gen_nlspath_execname="$1"
3561f958cfaSStefan Eßer	shift
3571f958cfaSStefan Eßer
3582f57ecaeSStefan Eßer	# Split the locale into its modifier and other parts.
3591f958cfaSStefan Eßer	_gen_nlspath_char="@"
3601f958cfaSStefan Eßer	_gen_nlspath_modifier="${_gen_nlspath_locale#*$_gen_nlspath_char}"
3611f958cfaSStefan Eßer	_gen_nlspath_tmplocale="${_gen_nlspath_locale%%$_gen_nlspath_char*}"
3621f958cfaSStefan Eßer
3632f57ecaeSStefan Eßer	# Split the locale into charset and other parts.
3641f958cfaSStefan Eßer	_gen_nlspath_char="."
3651f958cfaSStefan Eßer	_gen_nlspath_charset="${_gen_nlspath_tmplocale#*$_gen_nlspath_char}"
3661f958cfaSStefan Eßer	_gen_nlspath_tmplocale="${_gen_nlspath_tmplocale%%$_gen_nlspath_char*}"
3671f958cfaSStefan Eßer
3682f57ecaeSStefan Eßer	# Check for an empty charset.
3691f958cfaSStefan Eßer	if [ "$_gen_nlspath_charset" = "$_gen_nlspath_tmplocale" ]; then
3701f958cfaSStefan Eßer		_gen_nlspath_charset=""
3711f958cfaSStefan Eßer	fi
3721f958cfaSStefan Eßer
3732f57ecaeSStefan Eßer	# Split the locale into territory and language.
3741f958cfaSStefan Eßer	_gen_nlspath_char="_"
3751f958cfaSStefan Eßer	_gen_nlspath_territory="${_gen_nlspath_tmplocale#*$_gen_nlspath_char}"
3761f958cfaSStefan Eßer	_gen_nlspath_language="${_gen_nlspath_tmplocale%%$_gen_nlspath_char*}"
3771f958cfaSStefan Eßer
3782f57ecaeSStefan Eßer	# Check for empty territory and language.
3791f958cfaSStefan Eßer	if [ "$_gen_nlspath_territory" = "$_gen_nlspath_tmplocale" ]; then
3801f958cfaSStefan Eßer		_gen_nlspath_territory=""
3811f958cfaSStefan Eßer	fi
3821f958cfaSStefan Eßer
3831f958cfaSStefan Eßer	if [ "$_gen_nlspath_language" = "$_gen_nlspath_tmplocale" ]; then
3841f958cfaSStefan Eßer		_gen_nlspath_language=""
3851f958cfaSStefan Eßer	fi
3861f958cfaSStefan Eßer
3872f57ecaeSStefan Eßer	# Prepare to replace the format specifiers. This is done by wrapping the in
3882f57ecaeSStefan Eßer	# pipe characters. It just makes it easier to split them later.
3891f958cfaSStefan Eßer	_gen_nlspath_needles="%%:%L:%N:%l:%t:%c"
3901f958cfaSStefan Eßer
3911f958cfaSStefan Eßer	_gen_nlspath_needles=$(printf '%s' "$_gen_nlspath_needles" | tr ':' '\n')
3921f958cfaSStefan Eßer
3931f958cfaSStefan Eßer	for _gen_nlspath_i in $_gen_nlspath_needles; do
3941f958cfaSStefan Eßer		_gen_nlspath_nlspath=$(substring_replace "$_gen_nlspath_nlspath" "$_gen_nlspath_i" "|$_gen_nlspath_i|")
3951f958cfaSStefan Eßer	done
3961f958cfaSStefan Eßer
3972f57ecaeSStefan Eßer	# Replace all the format specifiers.
3981f958cfaSStefan Eßer	_gen_nlspath_nlspath=$(substring_replace "$_gen_nlspath_nlspath" "%%" "%")
3991f958cfaSStefan Eßer	_gen_nlspath_nlspath=$(substring_replace "$_gen_nlspath_nlspath" "%L" "$_gen_nlspath_locale")
4001f958cfaSStefan Eßer	_gen_nlspath_nlspath=$(substring_replace "$_gen_nlspath_nlspath" "%N" "$_gen_nlspath_execname")
4011f958cfaSStefan Eßer	_gen_nlspath_nlspath=$(substring_replace "$_gen_nlspath_nlspath" "%l" "$_gen_nlspath_language")
4021f958cfaSStefan Eßer	_gen_nlspath_nlspath=$(substring_replace "$_gen_nlspath_nlspath" "%t" "$_gen_nlspath_territory")
4031f958cfaSStefan Eßer	_gen_nlspath_nlspath=$(substring_replace "$_gen_nlspath_nlspath" "%c" "$_gen_nlspath_charset")
4041f958cfaSStefan Eßer
4052f57ecaeSStefan Eßer	# Get rid of pipe characters.
4061f958cfaSStefan Eßer	_gen_nlspath_nlspath=$(printf '%s' "$_gen_nlspath_nlspath" | tr -d '|')
4071f958cfaSStefan Eßer
4082f57ecaeSStefan Eßer	# Return the result.
4091f958cfaSStefan Eßer	printf '%s' "$_gen_nlspath_nlspath"
4101f958cfaSStefan Eßer}
4115bdd6265SStefan Eßer
4125bdd6265SStefan EßerALL=0
4135bdd6265SStefan EßerNOSKIP=1
4145bdd6265SStefan EßerSKIP=2
4155bdd6265SStefan Eßer
4165bdd6265SStefan Eßer# Filters text out of a file according to the build type.
4175bdd6265SStefan Eßer# @param in    File to filter.
4185bdd6265SStefan Eßer# @param out   File to write the filtered output to.
4195bdd6265SStefan Eßer# @param type  Build type.
4205bdd6265SStefan Eßerfilter_text() {
4215bdd6265SStefan Eßer
4225bdd6265SStefan Eßer	_filter_text_in="$1"
4235bdd6265SStefan Eßer	shift
4245bdd6265SStefan Eßer
4255bdd6265SStefan Eßer	_filter_text_out="$1"
4265bdd6265SStefan Eßer	shift
4275bdd6265SStefan Eßer
4285bdd6265SStefan Eßer	_filter_text_buildtype="$1"
4295bdd6265SStefan Eßer	shift
4305bdd6265SStefan Eßer
4315bdd6265SStefan Eßer	# Set up some local variables.
4325bdd6265SStefan Eßer	_filter_text_status="$ALL"
4331576f667SStefan Eßer	_filter_text_last_line=""
4345bdd6265SStefan Eßer
4355bdd6265SStefan Eßer	# We need to set IFS, so we store it here for restoration later.
4365bdd6265SStefan Eßer	_filter_text_ifs="$IFS"
4375bdd6265SStefan Eßer
4385bdd6265SStefan Eßer	# Remove the file- that will be generated.
4391576f667SStefan Eßer	rm -rf "$_filter_text_out"
4405bdd6265SStefan Eßer
4415bdd6265SStefan Eßer	# Here is the magic. This loop reads the template line-by-line, and based on
4425bdd6265SStefan Eßer	# _filter_text_status, either prints it to the markdown manual or not.
4435bdd6265SStefan Eßer	#
4445bdd6265SStefan Eßer	# Here is how the template is set up: it is a normal markdown file except
4455bdd6265SStefan Eßer	# that there are sections surrounded tags that look like this:
4465bdd6265SStefan Eßer	#
4475bdd6265SStefan Eßer	# {{ <build_type_list> }}
4485bdd6265SStefan Eßer	# ...
4495bdd6265SStefan Eßer	# {{ end }}
4505bdd6265SStefan Eßer	#
4515bdd6265SStefan Eßer	# Those tags mean that whatever build types are found in the
4525bdd6265SStefan Eßer	# <build_type_list> get to keep that section. Otherwise, skip.
4535bdd6265SStefan Eßer	#
4545bdd6265SStefan Eßer	# Obviously, the tag itself and its end are not printed to the markdown
4555bdd6265SStefan Eßer	# manual.
4561576f667SStefan Eßer	while IFS= read -r _filter_text_line; do
4575bdd6265SStefan Eßer
4585bdd6265SStefan Eßer		# If we have found an end, reset the status.
4591576f667SStefan Eßer		if [ "$_filter_text_line" = "{{ end }}" ]; then
4605bdd6265SStefan Eßer
4615bdd6265SStefan Eßer			# Some error checking. This helps when editing the templates.
4625bdd6265SStefan Eßer			if [ "$_filter_text_status" -eq "$ALL" ]; then
4635bdd6265SStefan Eßer				err_exit "{{ end }} tag without corresponding start tag" 2
4645bdd6265SStefan Eßer			fi
4655bdd6265SStefan Eßer
4665bdd6265SStefan Eßer			_filter_text_status="$ALL"
4675bdd6265SStefan Eßer
4685bdd6265SStefan Eßer		# We have found a tag that allows our build type to use it.
4691576f667SStefan Eßer		elif [ "${_filter_text_line#\{\{* $_filter_text_buildtype *\}\}}" != "$_filter_text_line" ]; then
4705bdd6265SStefan Eßer
4715bdd6265SStefan Eßer			# More error checking. We don't want tags nested.
4725bdd6265SStefan Eßer			if [ "$_filter_text_status" -ne "$ALL" ]; then
4735bdd6265SStefan Eßer				err_exit "start tag nested in start tag" 3
4745bdd6265SStefan Eßer			fi
4755bdd6265SStefan Eßer
4765bdd6265SStefan Eßer			_filter_text_status="$NOSKIP"
4775bdd6265SStefan Eßer
4785bdd6265SStefan Eßer		# We have found a tag that is *not* allowed for our build type.
4791576f667SStefan Eßer		elif [ "${_filter_text_line#\{\{*\}\}}" != "$_filter_text_line" ]; then
4805bdd6265SStefan Eßer
4815bdd6265SStefan Eßer			if [ "$_filter_text_status" -ne "$ALL" ]; then
4825bdd6265SStefan Eßer				err_exit "start tag nested in start tag" 3
4835bdd6265SStefan Eßer			fi
4845bdd6265SStefan Eßer
4855bdd6265SStefan Eßer			_filter_text_status="$SKIP"
4865bdd6265SStefan Eßer
4875bdd6265SStefan Eßer		# This is for normal lines. If we are not skipping, print.
4885bdd6265SStefan Eßer		else
4895bdd6265SStefan Eßer			if [ "$_filter_text_status" -ne "$SKIP" ]; then
4901576f667SStefan Eßer				if [ "$_filter_text_line" != "$_filter_text_last_line" ]; then
4911576f667SStefan Eßer					printf '%s\n' "$_filter_text_line" >> "$_filter_text_out"
4921576f667SStefan Eßer				fi
4931576f667SStefan Eßer				_filter_text_last_line="$_filter_text_line"
4945bdd6265SStefan Eßer			fi
4955bdd6265SStefan Eßer		fi
4965bdd6265SStefan Eßer
4975bdd6265SStefan Eßer	done < "$_filter_text_in"
4985bdd6265SStefan Eßer
4995bdd6265SStefan Eßer	# Reset IFS.
5005bdd6265SStefan Eßer	IFS="$_filter_text_ifs"
5015bdd6265SStefan Eßer}
502