]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/bc/scripts/functions.sh
contrib/bc: merge version 5.1.0 from vendor branch
[FreeBSD/FreeBSD.git] / contrib / bc / scripts / functions.sh
1 #! /bin/sh
2 #
3 # SPDX-License-Identifier: BSD-2-Clause
4 #
5 # Copyright (c) 2018-2021 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 # This script is NOT meant to be run! It is meant to be sourced by other
31 # scripts.
32
33 # Reads and follows a link until it finds a real file. This is here because the
34 # readlink utility is not part of the POSIX standard. Sigh...
35 # @param f  The link to find the original file for.
36 readlink() {
37
38         _readlink_f="$1"
39         shift
40
41         _readlink_arrow="-> "
42         _readlink_d=$(dirname "$_readlink_f")
43
44         _readlink_lsout=""
45         _readlink_link=""
46
47         _readlink_lsout=$(ls -dl "$_readlink_f")
48         _readlink_link=$(printf '%s' "${_readlink_lsout#*$_readlink_arrow}")
49
50         while [ -z "${_readlink_lsout##*$_readlink_arrow*}" ]; do
51                 _readlink_f="$_readlink_d/$_readlink_link"
52                 _readlink_d=$(dirname "$_readlink_f")
53                 _readlink_lsout=$(ls -dl "$_readlink_f")
54                 _readlink_link=$(printf '%s' "${_readlink_lsout#*$_readlink_arrow}")
55         done
56
57         printf '%s' "${_readlink_f##*$_readlink_d/}"
58 }
59
60 # Quick function for exiting with an error.
61 # @param 1  A message to print.
62 # @param 2  The exit code to use.
63 err_exit() {
64
65         if [ "$#" -ne 2 ]; then
66                 printf 'Invalid number of args to err_exit\n'
67                 exit 1
68         fi
69
70         printf '%s\n' "$1"
71         exit "$2"
72 }
73
74 # Check the return code on a test and exit with a fail if it's non-zero.
75 # @param d     The calculator under test.
76 # @param err   The return code.
77 # @param name  The name of the test.
78 checktest_retcode() {
79
80         _checktest_retcode_d="$1"
81         shift
82
83         _checktest_retcode_err="$1"
84         shift
85
86         _checktest_retcode_name="$1"
87         shift
88
89         if [ "$_checktest_retcode_err" -ne 0 ]; then
90                 printf 'FAIL!!!\n'
91                 err_exit "$_checktest_retcode_d failed test '$_checktest_retcode_name' with error code $_checktest_retcode_err" 1
92         fi
93 }
94
95 # Check the result of a test. First, it checks the error code using
96 # checktest_retcode(). Then it checks the output against the expected output
97 # and fails if it doesn't match.
98 # @param d             The calculator under test.
99 # @param err           The error code.
100 # @param name          The name of the test.
101 # @param test_path     The path to the test.
102 # @param results_name  The path to the file with the expected result.
103 checktest() {
104
105         _checktest_d="$1"
106         shift
107
108         _checktest_err="$1"
109         shift
110
111         _checktest_name="$1"
112         shift
113
114         _checktest_test_path="$1"
115         shift
116
117         _checktest_results_name="$1"
118         shift
119
120         checktest_retcode "$_checktest_d" "$_checktest_err" "$_checktest_name"
121
122         _checktest_diff=$(diff "$_checktest_test_path" "$_checktest_results_name")
123
124         _checktest_err="$?"
125
126         if [ "$_checktest_err" -ne 0 ]; then
127                 printf 'FAIL!!!\n'
128                 printf '%s\n' "$_checktest_diff"
129                 err_exit "$_checktest_d failed test $_checktest_name" 1
130         fi
131 }
132
133 # Die. With a message.
134 # @param d     The calculator under test.
135 # @param msg   The message to print.
136 # @param name  The name of the test.
137 # @param err   The return code from the test.
138 die() {
139
140         _die_d="$1"
141         shift
142
143         _die_msg="$1"
144         shift
145
146         _die_name="$1"
147         shift
148
149         _die_err="$1"
150         shift
151
152         _die_str=$(printf '\n%s %s on test:\n\n    %s\n' "$_die_d" "$_die_msg" "$_die_name")
153
154         err_exit "$_die_str" "$_die_err"
155 }
156
157 # Check that a test did not crash and die if it did.
158 # @param d      The calculator under test.
159 # @param error  The error code.
160 # @param name   The name of the test.
161 checkcrash() {
162
163         _checkcrash_d="$1"
164         shift
165
166         _checkcrash_error="$1"
167         shift
168
169         _checkcrash_name="$1"
170         shift
171
172
173         if [ "$_checkcrash_error" -gt 127 ]; then
174                 die "$_checkcrash_d" "crashed ($_checkcrash_error)" \
175                         "$_checkcrash_name" "$_checkcrash_error"
176         fi
177 }
178
179 # Check that a test had an error or crash.
180 # @param d        The calculator under test.
181 # @param error    The error code.
182 # @param name     The name of the test.
183 # @param out      The file that the test results were output to.
184 # @param exebase  The name of the executable.
185 checkerrtest()
186 {
187         _checkerrtest_d="$1"
188         shift
189
190         _checkerrtest_error="$1"
191         shift
192
193         _checkerrtest_name="$1"
194         shift
195
196         _checkerrtest_out="$1"
197         shift
198
199         _checkerrtest_exebase="$1"
200         shift
201
202         checkcrash "$_checkerrtest_d" "$_checkerrtest_error" "$_checkerrtest_name"
203
204         if [ "$_checkerrtest_error" -eq 0 ]; then
205                 die "$_checkerrtest_d" "returned no error" "$_checkerrtest_name" 127
206         fi
207
208         # This is to check for memory errors with Valgrind, which is told to return
209         # 100 on memory errors.
210         if [ "$_checkerrtest_error" -eq 100 ]; then
211
212                 _checkerrtest_output=$(cat "$_checkerrtest_out")
213                 _checkerrtest_fatal_error="Fatal error"
214
215                 if [ "${_checkerrtest_output##*$_checkerrtest_fatal_error*}" ]; then
216                         printf "%s\n" "$_checkerrtest_output"
217                         die "$_checkerrtest_d" "had memory errors on a non-fatal error" \
218                                 "$_checkerrtest_name" "$_checkerrtest_error"
219                 fi
220         fi
221
222         if [ ! -s "$_checkerrtest_out" ]; then
223                 die "$_checkerrtest_d" "produced no error message" "$_checkerrtest_name" "$_checkerrtest_error"
224         fi
225
226         # To display error messages, uncomment this line. This is useful when
227         # debugging.
228         #cat "$_checkerrtest_out"
229 }
230
231 # Replace a substring in a string with another. This function is the *real*
232 # workhorse behind configure.sh's generation of a Makefile.
233 #
234 # This function uses a sed call that uses exclamation points `!` as delimiters.
235 # As a result, needle can never contain an exclamation point. Oh well.
236 #
237 # @param str          The string that will have any of the needle replaced by
238 #                     replacement.
239 # @param needle       The needle to replace in str with replacement.
240 # @param replacement  The replacement for needle in str.
241 substring_replace() {
242
243         _substring_replace_str="$1"
244         shift
245
246         _substring_replace_needle="$1"
247         shift
248
249         _substring_replace_replacement="$1"
250         shift
251
252         _substring_replace_result=$(printf '%s\n' "$_substring_replace_str" | \
253                 sed -e "s!$_substring_replace_needle!$_substring_replace_replacement!g")
254
255         printf '%s' "$_substring_replace_result"
256 }
257
258 # Generates an NLS path based on the locale and executable name.
259 #
260 # This is a monstrosity for a reason.
261 #
262 # @param nlspath   The $NLSPATH
263 # @param locale    The locale.
264 # @param execname  The name of the executable.
265 gen_nlspath() {
266
267         _gen_nlspath_nlspath="$1"
268         shift
269
270         _gen_nlspath_locale="$1"
271         shift
272
273         _gen_nlspath_execname="$1"
274         shift
275
276         # Split the locale into its modifier and other parts.
277         _gen_nlspath_char="@"
278         _gen_nlspath_modifier="${_gen_nlspath_locale#*$_gen_nlspath_char}"
279         _gen_nlspath_tmplocale="${_gen_nlspath_locale%%$_gen_nlspath_char*}"
280
281         # Split the locale into charset and other parts.
282         _gen_nlspath_char="."
283         _gen_nlspath_charset="${_gen_nlspath_tmplocale#*$_gen_nlspath_char}"
284         _gen_nlspath_tmplocale="${_gen_nlspath_tmplocale%%$_gen_nlspath_char*}"
285
286         # Check for an empty charset.
287         if [ "$_gen_nlspath_charset" = "$_gen_nlspath_tmplocale" ]; then
288                 _gen_nlspath_charset=""
289         fi
290
291         # Split the locale into territory and language.
292         _gen_nlspath_char="_"
293         _gen_nlspath_territory="${_gen_nlspath_tmplocale#*$_gen_nlspath_char}"
294         _gen_nlspath_language="${_gen_nlspath_tmplocale%%$_gen_nlspath_char*}"
295
296         # Check for empty territory and language.
297         if [ "$_gen_nlspath_territory" = "$_gen_nlspath_tmplocale" ]; then
298                 _gen_nlspath_territory=""
299         fi
300
301         if [ "$_gen_nlspath_language" = "$_gen_nlspath_tmplocale" ]; then
302                 _gen_nlspath_language=""
303         fi
304
305         # Prepare to replace the format specifiers. This is done by wrapping the in
306         # pipe characters. It just makes it easier to split them later.
307         _gen_nlspath_needles="%%:%L:%N:%l:%t:%c"
308
309         _gen_nlspath_needles=$(printf '%s' "$_gen_nlspath_needles" | tr ':' '\n')
310
311         for _gen_nlspath_i in $_gen_nlspath_needles; do
312                 _gen_nlspath_nlspath=$(substring_replace "$_gen_nlspath_nlspath" "$_gen_nlspath_i" "|$_gen_nlspath_i|")
313         done
314
315         # Replace all the format specifiers.
316         _gen_nlspath_nlspath=$(substring_replace "$_gen_nlspath_nlspath" "%%" "%")
317         _gen_nlspath_nlspath=$(substring_replace "$_gen_nlspath_nlspath" "%L" "$_gen_nlspath_locale")
318         _gen_nlspath_nlspath=$(substring_replace "$_gen_nlspath_nlspath" "%N" "$_gen_nlspath_execname")
319         _gen_nlspath_nlspath=$(substring_replace "$_gen_nlspath_nlspath" "%l" "$_gen_nlspath_language")
320         _gen_nlspath_nlspath=$(substring_replace "$_gen_nlspath_nlspath" "%t" "$_gen_nlspath_territory")
321         _gen_nlspath_nlspath=$(substring_replace "$_gen_nlspath_nlspath" "%c" "$_gen_nlspath_charset")
322
323         # Get rid of pipe characters.
324         _gen_nlspath_nlspath=$(printf '%s' "$_gen_nlspath_nlspath" | tr -d '|')
325
326         # Return the result.
327         printf '%s' "$_gen_nlspath_nlspath"
328 }