1#!/bin/sh 2# 3# Copyright 2010-2018 Brad Lanam Walnut Creek, CA, USA 4# Copyright 2020 Brad Lanam Pleasant Hill CA 5# 6 7if [ ! -f "${_MKCONFIG_DIR}/VERSION" ]; then 8 echo "Unable to locate ${_MKCONFIG_DIR}/VERSION." 9 echo "Not a valid mkconfig installation." 10 exit 1 11fi 12 13# dash on Mandriva 2011 segfaults intermittently when: 14# read _MKCONFIG_VERSION < ${_MKCONFIG_DIR}/VERSION 15# export _MKCONFIG_VERSION 16# was used. 17_MKCONFIG_VERSION=`cat ${_MKCONFIG_DIR}/VERSION` 18export _MKCONFIG_VERSION 19 20# posh set command doesn't output correct data; don't bother with it. 21# older yash has quoting/backquote issues (what version did this get fixed?) 22# bosh is a disaster. 23# zsh is not bourne shell compatible 24# set | grep can be fixed (nulls are output) with: set | strings | grep 25# and 'emulate ksh' can be set in mkconfig.sh, but there 26# are more issues, and I'm not interested in tracking them down. 27tryshell="bash bash5 bash4 bash3 ksh ksh88 ksh93 mksh pdksh yash ash dash bash2 sh sh5 osh" 28 29mkconfigversion () { 30 echo "mkconfig version ${_MKCONFIG_VERSION}" 31} 32 33dosubst () { 34 subvar=$1 35 shift 36 sa="" 37 while test $# -gt 0; do 38 pattern=$1 39 sub=$2 40 shift 41 shift 42 sa="${sa} -e \"s~${pattern}~${sub}~g\"" 43 done 44 cmd="${subvar}=\`echo \${${subvar}} | sed ${sa}\`" 45 eval $cmd; 46} 47 48test_echo () { 49 shhasprintf=0 50 shhasprintferr="" 51 (eval 'printf %s hello >/dev/null') 2>/dev/null 52 rc=$? 53 # Virtually all shells have printf. 54 # I had not known it was supported so far back -- most 55 # everything used echo, and printf was not mentioned much. 56 # 'printf' is POSIX compliant. 57 if [ $rc -eq 0 ]; then 58 shhasprintf=1 59 eval 'putsnonl () { printf '%s' "$*"; }' 60 eval 'puts () { printf "%s\n" "$*"; }' 61 else 62 shhasprintferr=none 63 fi 64 65 # 66 # Backslash interpolation with echo and single quotes has issues. 67 # Apparently I didn't code anything that ran into that problem. 68 # 69 # echo with single quotes should be avoided as too many shells 70 # interpolate backslashes when they should not. 71 # 72 # The read/printf combo fails due to differences from read/echo. 73 # 74 # 2019-6-26: Apparently some older ksh93 also have this issue. 75 # 2020-6-10: Apparently there are differences in quite a few shells here. 76 # I am surprised I did not run into portability issues with this. 77 # 78 # $ echo "a \\ b" 79 # a \ b 80 # $ printf "%s\n" "a \\ b" 81 # a \ b 82 # $ cat tt 83 # a \\ b 84 # $ read tdat < tt 85 # $ echo "$tdat" 86 # a \ b # should be: a \ b 87 # $ printf "%s\n" "$tdat" 88 # a \\ b # should be: a \ b 89 # $ echo 'a \\ b' 90 # a \ b # should be: a \\ b 91 # $ printf "%s\n" 'a \\ b' 92 # a \\ b # should be: a \\ b 93 # $ 94 # 95 96 # Test for interpolation bugs. 97 # If bugs are present, use 'echo'. 98 tz="a \\\\ b" # should always interpolate as: a \\ b 99 t1=`echo "$tz"` # and both of these should return: a \\ b 100 t2=`printf '%s\n' "$tz"` 101 # have to test against the original in order to catch the change 102 # if echo and printf do not match each other, it is very likely 103 # that the read/echo/printf mismatches also occur. 104 # osh does some odd stuff internally according to the output here, 105 # but echo and printf still seem to work. 106 if [ \( "$tz" != "$t1" \) -o \( "$tz" != "$t2" \) ]; then 107 shhasprintf=0 108 shhasprintferr=mismatch 109 fi 110 111 # 'echo' works everywhere, but is not a POSIX compliant command. 112 # Have not found any bourne compatible shell that does not support 113 # either -n or \c. 114 if [ $shhasprintf -eq 0 ]; then 115 _tEN='-n' 116 _tEC='' 117 if [ "`echo -n test`" = "-n test" ]; then 118 _tEN='' 119 _tEC='\c' 120 fi 121 eval 'putsnonl () { echo ${_tEN} "$*${_tEC}"; }' 122 eval 'puts () { echo "$*"; }' 123 fi 124} 125 126# The += form is much, much faster and less prone to errors. 127test_append () { 128 shhasappend=0 129 (eval 'x=a;x+=b; test z$x = zab') 2>/dev/null 130 if [ $? -eq 0 ]; then 131 shhasappend=1 132 eval 'doappend () { eval $1+=\$2; }' 133 else 134 eval 'doappend () { eval $1=\$${1}\$2; }' 135 fi 136} 137 138test_readraw () { 139 # $ cat tt 140 # a \\ b 141 # $ read tdat < tt 142 # $ echo "$tdat" 143 # a \ b # should be: a \ b 144 # $ printf "%s\n" "$tdat" 145 # a \\ b # should be: a \ b 146 147 shreqreadraw=0 148 # unixware 7.14 compiles and runs this code ok, but it's shell gets 149 # completely wacked out later. So run it in a subshell. 150 # (similar to mandriva 2011 problem with read < file) 151 ( 152 rrv='aa\\\\bb' 153 read rrx << _HERE_ 154$rrv 155_HERE_ 156 ( 157 eval "read -r rry <<_HERE_ 158$rrv 159_HERE_" 160 ) 2>/dev/null 161 yrc=$? 162 if [ $yrc -eq 0 ]; then 163 read -r rry << _HERE_ 164$rrv 165_HERE_ 166 if [ "${rrx}" != 'aa\\bb' -a "${rry}" = 'aa\\\\bb' ]; then 167 shreqreadraw=1 168 fi 169 fi 170 exit $shreqreadraw 171 ) 172 shreqreadraw=$? 173} 174 175# use the faster method $((expr)) if possible. 176test_math () { 177 shhasmath=0 178 shhasmatherr=none 179 (eval 'x=1;y=$(($x+1)); test z$y = z2') 2>/dev/null 180 rc=$? 181 if [ $rc -eq 0 ]; then 182 shhasmath=1 183 shhasmatherr="" 184 eval 'domath () { mthvar=$1; mthval=\$\(\($2\)\); eval $mthvar=$mthval; }' 185 fi 186 if [ $shhasmath -eq 0 ]; then 187 eval 'domath () { mthvar=$1; mthval=`expr $2`; eval $mthvar=$mthval; }' 188 fi 189} 190 191# use the faster shell built-in if possible. 192test_upper () { 193 shhasupper=0 194 (eval 'typeset -u xuvar;xuvar=x;test z$xuvar = zX') 2>/dev/null 195 if [ $? -eq 0 ]; then 196 shhasupper=1 197 eval 'toupper () { ucvar=$1; typeset -u ucval; eval "ucval=\${$ucvar};$ucvar=\$ucval"; }' 198 else 199 eval 'toupper () { ucvar=$1; cmd="$ucvar=\`echo \${$ucvar} | tr \"[a-z]\" \"[A-Z]\"\`"; eval "$cmd"; }' 200 fi 201} 202 203# use the faster shell built-in if possible. 204test_lower () { 205 shhaslower=0 206 (eval 'typeset -l xuvar;xuvar=X;test z$xuvar = zx') 2>/dev/null 207 if [ $? -eq 0 ]; then 208 shhaslower=1 209 eval 'tolower () { lcvar=$1; typeset -l lcval; eval "lcval=\${$lcvar};$lcvar=\$lcval"; }' 210 else 211 eval 'tolower () { lcvar=$1; cmd="$lcvar=\`echo \${$lcvar} | tr \"[A-Z]\" \"[a-z]\"\`"; eval "$cmd"; }' 212 fi 213} 214 215testshcapability () { 216 test_echo 217 test_append 218 test_readraw 219 test_math 220 test_upper 221 test_lower 222} 223 224getshelltype () { 225 if [ "$1" != "" ]; then 226 trs=$1 227 shift 228 fi 229 gstecho=F 230 if [ "$1" = echo ]; then 231 gstecho=T 232 fi 233 234 baseshell=${_shell:-sh} # unknown or old 235 shell=${_shell:-sh} # unknown or old 236 if [ "$trs" != "" ]; then 237 dispshell=`echo $trs | sed -e 's,.*/,,'` 238 else 239 dispshell=$shell 240 fi 241 ( eval 'echo ${.sh.version}' ) >/dev/null 2>&1 242 if [ $? -eq 0 ]; then 243 eval 'KSH_VERSION=${.sh.version}' 244 fi 245 if [ "$KSH_VERSION" != "" ]; then 246 shell=ksh 247 baseshell=ksh 248 shvers=$KSH_VERSION 249 case $KSH_VERSION in 250 *PD*) 251 shell=pdksh 252 ;; 253 *93*) 254 shell=ksh93 255 ;; 256 *88*) 257 shell=ksh88 258 ;; 259 *MIRBSD*) 260 shell=mksh 261 ;; 262 esac 263 elif [ "$BASH_VERSION" != "" ]; then 264 shvers=$BASH_VERSION 265 ver=`echo $BASH_VERSION | sed 's/\..*//'` 266 shell=bash${ver} 267 baseshell=bash 268 elif [ "$ZSH_VERSION" != "" ]; then 269 shvers=$ZSH_VERSION 270 shell=zsh 271 baseshell=zsh 272 elif [ "$POSH_VERSION" != "" ]; then 273 shvers=$POSH_VERSION 274 shell=posh 275 baseshell=posh 276 elif [ "$YASH_VERSION" != "" ]; then 277 shvers=$YASH_VERSION 278 shell=yash 279 baseshell=yash 280 elif [ "$OIL_VERSION" != "" ]; then 281 shvers=$OIL_VERSION 282 shell=osh 283 baseshell=osh 284 fi 285 286 if [ $dispshell = sh -a $dispshell != $shell ]; then 287 dispshell="$dispshell-$shell" 288 elif [ $dispshell = $baseshell ]; then 289 dispshell=$shell 290 fi 291 # can try --version, but don't really know the path 292 # of the shell running us; can't depend on $SHELL. 293 # and it only works for bash and some versions of ksh. 294 if [ $gstecho = T ]; then 295 echo $dispshell $shvers 296 fi 297} 298 299doshelltest () { 300 # force shell type. 301 if [ "$_MKCONFIG_SHELL" != "" ]; then 302 if [ "$SHELL" != "$_MKCONFIG_SHELL" ]; then 303 SHELL="$_MKCONFIG_SHELL" 304 export SHELL 305 loc=`pwd` 306 s=$1 307 shift 308 exec $SHELL $dstscript $s -d $loc $@ 309 fi 310 fi 311 312 getshelltype # for display of error below 313 chkshell "" $shell 314 if [ $? -ne 0 ]; then 315 echo "The shell in use ($dispshell) does not have the correct functionality:" >&2 316 echo $chkmsg >&2 317 echo "Please try another shell. 318_MKCONFIG_SHELL can be set to the path of another shell 319to override /bin/sh." >&2 320 exit 1 321 fi 322 testshcapability 323} 324 325locatecmd () { 326 lvar=$1 327 ltcmd=$2 328 329 getpaths 330 331 lcmd="" 332 for p in $_pthlist; do 333 if [ -x "$p/$ltcmd" ]; then 334 lcmd="$p/$ltcmd" 335 break 336 fi 337 done 338 eval $lvar=$lcmd 339} 340 341mkverscomp () { 342 v=$1 343 344 # put a 1 in front to avoid any octal constant issue. 345 echo $v | $awkcmd -F. '{ printf("1%03d%03d%03d\n", $1,$2,$3); }' 346} 347 348# rc = 0 : same version 349# rc = 1 : smaller version 350# rc = 2 : greater version 351versioncompare () { 352 v1=`mkverscomp $1` 353 v2=`mkverscomp $2` 354 355 rc=0 356 if [ $v1 -lt $v2 ]; then 357 rc=1 358 fi 359 if [ $v1 -gt $v2 ]; then 360 rc=2 361 fi 362 return $rc 363} 364 365# function to make sure the shell has 366# some basic capabilities w/o weirdness. 367chkshell () { 368 doecho=F 369 if [ "$1" = "echo" ]; then 370 doecho=T 371 fi 372 shellpath=$2 373 374 grc=0 375 376 case $shellpath in 377 *yash) 378 # reject older versions of yash 379 # I do not know in what version the quoting/backquoting issues 380 # got fixed. 381 locateawkcmd 382 versioncompare $YASH_VERSION 2.48 383 rc=$? 384 if [ $rc -eq 1 ]; then 385 chkmsg="${chkmsg} 386 older versions of yash are not supported" 387 grc=1 388 fi 389 ;; 390 esac 391 392 chkmsg="" 393 # test to make sure the set command works properly 394 # some shells output xyzzy=abc def 395 # some shells output xyzzy='abc def' 396 # some shells output xyzzy=$'abc def' (ok; handled in mkconfig.sh) 397 # yash does this correctly, but had quoting/backquote issues in older versions. 398 ( 399 cmd='xyzzy="abc def"; val=`set | grep "^xyzzy"`; test "$val" = "xyzzy=abc def"' 400 eval $cmd 2>/dev/null 401 if [ $? -eq 0 ]; then 402 exit 0 403 fi 404 cmd="xyzzy=\"abc def\"; val=\`set | grep \"^xyzzy\"\`; test \"\$val\" = \"xyzzy='abc def'\" -o \"\$val\" = \"xyzzy=\\$'abc def'\"" 405 eval $cmd 2>/dev/null 406 rc=$? 407 exit $rc 408 ) 409 rc=$? 410 if [ $rc -ne 0 ]; then 411 grc=$rc 412 chkmsg="${chkmsg} 413 'set' output not x=a b or x='a b' or x=\$'a b'." 414 fi 415 416 # test to make sure the 'set -f' command is supported. 417 ( 418 cmd='set -f' 419 eval $cmd 2>/dev/null 420 rc=$? 421 if [ $rc -eq 0 ]; then 422 exit 0 423 fi 424 exit $rc 425 ) 426 rc=$? 427 if [ $rc -ne 0 ]; then 428 grc=$rc 429 chkmsg="${chkmsg} 430 'set -f' not supported" 431 fi 432 433 if [ $doecho = "T" ]; then 434 echo $chkmsg 435 fi 436 437 return $grc 438} 439 440getpaths () { 441 if [ "$_pthlist" != "" ]; then 442 return 443 fi 444 445 systype=`uname -s` 446 tpthlist=`echo $PATH | sed 's/:/ /g'` 447 448 # cygwin's /bin and /usr/bin are both mounted on same spot 449 case ${systype} in 450 CYGWIN*) 451 d=/bin 452 tpthlist=`echo $tpthlist | sed -e "s,^$d ,," -e "s, $d,,"` 453 ;; 454 esac 455 456 # remove symlinks 457 for d in $tpthlist; do 458 if [ ! -d $d ]; then 459 tpthlist=`echo $tpthlist | sed -e "s,^$d ,," -e "s, $d,,"` 460 else 461 if [ -h $d ]; then 462 tpthlist=`echo $tpthlist | sed -e "s,^$d ,," -e "s, $d,,"` 463 # make sure path symlink is pointing to is in the list 464 npath=`ls -ld $d | sed 's/.*-> //'` 465 tpthlist="$tpthlist $npath" 466 fi 467 fi 468 done 469 470 # remove dups 471 _pthlist="" 472 for d in $tpthlist; do 473 _pthlist="$_pthlist 474$d" 475 done 476 _pthlist=`echo $_pthlist | sort -u` 477} 478 479initifs () { 480 hasifs=0 481 if [ "$IFS" != "" ]; then 482 OIFS="$IFS" 483 hasifs=1 484 fi 485} 486 487setifs () { 488 # just newline for parsing include section 489 IFS=" 490" 491} 492 493resetifs () { 494 if [ $hasifs -eq 1 ]; then 495 IFS="$OIFS" 496 else 497 unset IFS 498 fi 499} 500 501boolclean () { 502 nm=$1 503 504 dosubst $nm '(' ' ( ' ')' ' ) ' 505 dosubst $nm ' not ' ' ! ' ' and ' ' -a ' ' or ' ' -o ' 506 dosubst $nm '!' ' ! ' '&&' ' -a ' '||' ' -o ' 507 dosubst $nm ' \+' ' ' '^ *' '' ' *$' '' 508} 509 510locateawkcmd () { 511 locatecmd awkcmd awk 512 locatecmd nawkcmd nawk 513 locatecmd gawkcmd gawk 514 locatecmd mawkcmd mawk 515 if [ "$nawkcmd" != "" ]; then 516 awkcmd=$nawkcmd 517 fi 518 if [ "$mawkcmd" != "" ]; then 519 awkcmd=$mawkcmd 520 fi 521 if [ "$gawkcmd" != "" ]; then 522 awkcmd=$gawkcmd 523 fi 524} 525 526locatepkgconfigcmd () { 527 locatecmd pkgconfigcmd pkg-config 528} 529 530