#!/bin/sh
# Copyright (C) 2020-2023 Francois Gouget
#
# Installs the packages needed for Wine development.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
name0=`basename "$0"`


error()
{
    echo "$name0:error:" "$@" >&2
}

warning()
{
    echo "$name0:warning:" "$@" >&2
}

dry_run()
{
    local rc
    echo "$@"

    # This assumes that the command does not need quoting
    [ -n "$opt_cmd_log" ] && echo "$@" >>"$opt_cmd_log"

    [ "$opt_dry_run" = "1" ] && return 0
    "$@"
    rc=$?
    [ $rc -ne 0 ] && echo "$1 -> rc=$rc"
    return $rc
}


#####
#
# Generic helpers
#
#####

pkginstall=""
pkgbroken=""
pkgmissing=""
pkgworkaround=""

wt_get_bad_pkgs()
{
    local pkgre="$1"
    echo "$pkgbroken $pkgmissing" | tr ' ' '\n' | sort -u | grep -E "^$pkgre" | tr '\n' ' '
}

wt_remove_bad_pkg()
{
    local pkg="$1"
    pkgbroken=`echo "$pkgbroken " | sed -e "s/ $pkg / /g"`
    pkgmissing=`echo "$pkgmissing " | sed -e "s/ $pkg / /g"`
}

wt_explain_bad_pkgs()
{
    local pkg
    local rc=1
    for pkg in $*
    do
        if echo " $pkgmissing $pkgbroken " | grep -q " $pkg "
        then
            wt_remove_bad_pkg "$pkg"
            rc=0
        fi
    done
    return $rc
}

wt_pretty_list()
{
    echo "$@" | tr ' ' '\n' | sort -u | tr '\n' ' ' | sed -e 's/^ //' -e 's/ $//'
}

wt_libdirs=""
wt_create_so_warn=1

# wt_create_so <sodev> <solib>
#
# Creates the <sodev>.so symlink pointing to the <solib>.so.<ver> library.
# If <solib> is omitted it is assumed to be identical to <sodev>.
# wt_create_so() also handles cases where the library is in /lib* rather than
# /usr/lib*.
#
# Returns 0 if the symlink was already present, 1 if it was successfully
# created, 2 if it could not be created.
wt_create_so()
{
    local libdir rc sover usrlibdir
    local sodev="$1"
    local solib="$2"
    [ -n "$solib" ] || solib="$sodev"
    if [ -z "$wt_libdirs" ]
    then
        error "the per-distribution code must set \$wt_libdirs"
        exit 1
    fi

    rc=0
    for libdir in $wt_libdirs
    do
        usrlibdir="/usr$libdir"
        if [ ! -f "$usrlibdir/$sodev.so" ]
        then
            sover=`cd "$usrlibdir" 2>/dev/null && ls "$solib.so".[0-9]* 2>/dev/null | head -n1`
            if [ ! -f "$usrlibdir/$sover" ]
            then
                # We want the full path in this case
                sover=`ls "$libdir/$solib.so".[0-9]* 2>/dev/null | head -n1`
                [ -f "$sover" ] || sover=""
            fi

            if [ -z "$sover" ]
            then
                error "could not find the ...$libdir/$sodev.so symlink target"
                rc=2
            # Use -f because $sodev.so may be a broken symlink
            elif ! dry_run ln -s -f "$sover" "$usrlibdir/$sodev.so"
            then
                error "could not create the ...$libdir/$sodev.so symlink"
                rc=2
            elif [ $rc -eq 0 ]
            then
                rc=1
            fi
        fi
    done
    if [ $rc -eq 2 -a -n "$wt_create_so_warn" ]
    then
        wt_create_so_warn=
        warning "The symlink creation will fail if the non-dev package is not installed."
        [ "$opt_dry_run" = "1" ] && warning "This is particularly likely with --dry-run."
    fi
    return $rc
}

# wt_create_sos <pkgdevre> <sodev1> ...
#
# Create the development library symlinks in the <sodev1> ... list using
# wt_create_so(). If they all succeeded, remove the packages matching the
# <pkgdevre> regular expression from the broken and missing packages lists.
wt_create_sos()
{
    local bad_pkgs lib success
    local pkgre="$1"
    shift

    fixed=""
    for lib in "$@"
    do
        wt_create_so "$lib"
        # Only mark a package as fixed if no error occurred and at least one
        # symlink was provided (if no symlink was provided the package is
        # presumably bad for other reasons).
        rc=$?
        [ $rc -eq 2 ] && fixed=0
        [ $rc -eq 1 -a -z "$fixed" ] && fixed=1
    done
    if [ "$fixed" = "1" ]
    then
        bad_pkgs=`wt_get_bad_pkgs "$pkgre"`
        for pkg in $bad_pkgs
        do
            wt_remove_bad_pkg "$pkg"
        done
        pkgworkaround="$pkgworkaround $bad_pkgs"
    fi
}


#####
#
# Debian
#
#####

#
# Debian: Package helpers
#

# apt_check <action> <pkg> <egrep-args>
#
# Checks that the information about <pkg> matches the specified <egrep-args>.
# With the 'show' <action> this can be used to verify that the package actually
# exists, has the expected version, etc.
apt_check()
{
    local action="$1"
    local pkg="$2"
    shift 2
    [ "$action" = "show" ] && action="show --no-all-versions"
    LANG= apt-cache $action "$pkg" 2>/dev/null | grep -E -q "$@"
}

# apt_addsection <landmark> <section> <packages>
#
# Checks if the <landmark> package is available and returns immediately if it
# is. Otherwise asks whether <section> should be added to the apt sources.
# If --yes was given or the user agrees the section is added but
# 'apt-get update' is not called.
#
# Returns 0 if a section was added, non-zero otherwise.
apt_addsection()
{
    local a pkg
    local landmark="$1"
    local section="$2"
    local packages="$3"

    # Can the section even be added?
    command -v apt-add-repository >/dev/null 2>&1 || return 1

    # Does it need to be added?
    pkg=`echo "$landmark" | sed -e "s/:.*//g"`
    apt_check show "$landmark" "Package: $pkg" && return 1

    echo
    echo "********************"
    echo
    echo "The $section section is needed for $packages."
    echo
    echo -n "Do you want to add it? [Y/n] "
    if [ -n "$opt_yes" ]
    then
        echo "yes"
        a="y"
    else
        read a
    fi
    [ -z "$a" -o "$a" = "y" -o "$a" = "Y" ] || return 1

    dry_run apt-add-repository "$section"
}

# apt_pkg [--test] <pkg1> ...
#
# If <pkg1> exists, schedule it for installation and return success.
# Otherwise try again with the next package in the list.
#
# If none of the packages exist and --test was not specified, add them all
# to the missing packages list and return failure.
apt_pkg()
{
    local pkg pkgarch
    local test=
    if [ "$1" = "--test" ]
    then
        test=1
        shift
    fi

    echo -n "Checking $*..."
    for pkgarch in $*
    do
        pkg=`echo "$pkgarch" | sed -e "s/:.*//g"`
        if apt_check show "$pkgarch" "Package: $pkg"
        then
            echo " yes"
            pkginstall="$pkginstall $pkgarch"
            return 0
        fi
    done
    echo " missing"
    [ -z "$test" ] && pkgmissing="$pkgmissing "`echo "$@" | sed -e 's/ /|/g'`
    return 1
}

# apt_is_installed <pkg1> ...
#
# Returns success if the specified packages are all installed.
apt_is_installed()
{
    dpkg -l "$@" >/dev/null 2>&1
}

# apt_multi [--test|--if-0 <rc>|--if-not-0 <rc>] <pkg1> ...
#
# Schedules installation of both the 32- and 64-bit versions of the package
# if possible. Otherwise installs the 64-bit version and marks the 32-bit one
# as broken.
#
# Specifically, if --if-0 (resp. --if-not-0) is specified and <rc> is not 0
# (resp. is 0), assume the package does not support multiarch.
#
# If <pkg1> exists:
# - If it supports multiarch schedule the installation of both 32- and 64-bit
#   versions and return 0 (success).
# - If it is architecture neutral schedule installation and return success.
# - Otherwise schedule installation of the 64-bit package, mark the 32-bit
#   version as broken and return 1 (failure).
#
# If <pkg1> does not exist, try again with the next package in the list.
# If none of the packages exists and --test was not specified, add them all
# to the missing packages list and return 2 (failure).
apt_multi()
{
    local pkg
    local test=
    local not_multi=
    if [ "$1" = "--test" ]
    then
        test=1
        shift
    elif [ "$1" = "--if-0" ]
    then
        [ "$2" = "0" ] || not_multi=1
        shift 2
    elif [ "$1" = "--if-not-0" ]
    then
        [ "$2" != "0" ] || not_multi=1
        shift 2
    fi

    for pkg in $*
    do
        echo -n "Checking multiarch $pkg..."
        if [ -z "$not_multi" ] &&
               # Check that both architectures are present
               apt_check show "$pkg:amd64" "Multi-Arch: same" &&
               apt_check show "$pkg:i386" "Multi-Arch: same"
        then
            echo " i386 amd64"
            pkginstall="$pkginstall $pkg:i386 $pkg:amd64"
            return 0
        elif apt_check show "$pkg" "Architecture: all"
        then
            echo " all"
            pkginstall="$pkginstall $pkg"
            return 0
        elif apt_check show "$pkg" "Package: $pkg"
        then
            echo " broken"
            pkginstall="$pkginstall $pkg"
            [ -z "$test" ] && pkgbroken="$pkgbroken $pkg:i386"
            return 1
        fi
        echo " missing"
    done
    [ -z "$test" ] && pkgmissing="$pkgmissing "`echo "$@" | sed -e 's/ /|/g'`
    return 2
}

# apt_blacklist <canary> <versionre> <pkgdev> <pkglibs>
#
# This is meant to deal with cases where multiarch support in <pkgdev> is
# broken by the <canary> package in a hard to detect way.
#
# Checks the version of the <canary> package and if it matches the <versionre>
# regular expression, installs the native <pkgdev> package and the 32-bit
# <pkglibs> package and returns failure.
# Otherwise invokes apt_multi() on <pkgdev> || <pkglibs> and returns success.
apt_blacklist()
{
    local canary="$1"
    local versionre="$2"
    local pkgdev="$3"
    local pkglibs="$4"

    if apt_check show "$canary" "Version: $versionre"
    then
        warning "Bad version for $canary, not using multiarch for $pkgdev"
        apt_pkg "$pkgdev"
        apt_pkg "$pkglibs:i386"
        pkgbroken="$pkgbroken $pkgdev:i386"
        return 1
    fi
    apt_multi "$pkgdev" || apt_multi "$pkglibs"
    return 0
}

apt_install()
{
    if [ -z "$opt_dry_run" ]
    then
        echo -n "Waiting for the dpkg lock"
        while fuser /var/lib/dpkg/lock /var/lib/dpkg/lock-frontend \
                    /var/run/unattended-upgrades.lock >/dev/null 2>&1
        do
            echo -n "."
            sleep 1
        done
        echo " done"
    fi
    dry_run apt-get install $opt_yes `wt_pretty_list "$pkginstall"` || exit 1
    echo
}

# apt_dev_workaround <pkg>
#
# For some packages we need more than just the links created by wt_create_sos.
# For those apt_dev_workaround manually extracts the package files and copies
# the architecture-specific headers, pkg-config files, and libraries.
apt_dev_workaround()
{
    local pkg="$1"
    local dir file

    mkdir pkgextract
    cd pkgextract
    apt-get download "$pkg:i386"
    dpkg -x "$pkg"*.deb .
    find usr/lib/i386-linux-gnu/ \( -type f -o -type l \) | \
        while read file
        do
            dir=$(dirname "/$file")
            [ -d "$dir" ] || dry_run mkdir -p "$dir" || exit 1
            dry_run mv "$file" "/$file" || exit 1
        done
    rc=$?
    cd ..
    rm -rf pkgextract
    if [ $rc -eq 0 ]
    then
        wt_remove_bad_pkg "$pkg:i386"
    fi
    return $rc
}


#
# Debian: Base Wine dependencies
#

apt_init()
{
    if [ `dpkg --print-architecture` != "amd64" ]
    then
        error "expected a 64-bit Debian distribution"
        exit 1
    fi
    if [ "$opt_packages" = "1" ]
    then
        dry_run dpkg --add-architecture i386
        dry_run apt-get update
    fi
    wt_libdirs="/lib/i386-linux-gnu /lib/x86_64-linux-gnu"
}

apt_wine()
{
    local ver

    # Tools
    apt_pkg   bison
    apt_pkg   flex
    apt_pkg   gcc
    apt_pkg   gcc-mingw-w64
    apt_pkg   gcc-multilib
    apt_pkg   gettext
    apt_pkg   git

    # Pop! OS 22.04 managed to break multiarch support in libc6-dev!!!
    LANG= apt-get install --dry-run linux-libc-dev:i386 linux-libc-dev:amd64 >"$TMPDIR/$name0.$$" 2>&1
    if [ $? -ne 0 ]
    then
        ver=`sed -e 's/^.*but \(5\..*\) is to be installed$/\1/' -e t -e d "$TMPDIR/$name0.$$" | head -n 1`
        warning "Force installing version $ver of linux-libc-dev"
        pkginstall="$pkginstall --allow-downgrades linux-libc-dev:i386=$ver linux-libc-dev:amd64=$ver"
    fi
    rm "$TMPDIR/$name0.$$"

    apt_multi libasound2-dev
    apt_multi libcapi20-dev
    apt_multi libdbus-1-dev
    apt_multi libfaudio-dev # Not used since Wine d8be85863fed (2021-10-21)

    # The FontConfig development package can only be installed if the FreeType
    # one supports multiarch
    apt_multi libfreetype6
    apt_multi libfreetype-dev libfreetype6-dev
    apt_multi --if-0 $? libfontconfig-dev libfontconfig1-dev || apt_multi libfontconfig1

    apt_multi libegl-dev
    apt_multi libgl-dev libgl1-mesa-dev
    apt_multi libglu1-mesa-dev # Not used since Wine ec55b1c271ae (2020-11-12)

    # The GPhoto2 development package can only be installed if the Exif
    # one supports multiarch
    apt_multi --test libexif-dev
    apt_multi --if-0 $? libgphoto2-dev || apt_multi libgphoto2-6

    apt_multi libgsm1-dev # Not used since Wine 0e7fd41af953 (2021-10-20)

    # The GnuTLS development package can only be installed if the idn2 one
    # one supports multiarch
    apt_multi --test libidn2-dev libidn2-0-dev
    apt_multi --if-0 $? libgnutls28-dev || apt_multi libgnutls30

    apt_multi libjpeg62-turbo-dev libjpeg-turbo8-dev # Not used since Wine a6ac035a7454 (2021-10-19)
    apt_multi libjxr-dev # Not used since Wine eb0180e7b4df (2021-10-21)

    if grep -i ubuntu /etc/os-release >/dev/null
    then
        # krb5-multidev multiarch support is broken on Ubuntu,
        # including for version 1.20.1-2.
        apt_blacklist krb5-multidev "(1.19.2-.ubuntu|1.20-.ubuntu|1.20.1-[123])" libkrb5-dev libkrb5-3
    else
        # krb5-multidev multiarch support works on Debian,
        # including for version 1.20.1-2.
        apt_multi libkrb5-dev
    fi

    apt_multi liblcms2-dev # Not used since Wine 5c4c272a2606 (2021-10-19)
    apt_multi libldap-dev libldap2-dev
    apt_multi libmpg123-dev # Not used since Wine 5329da61ac51 (2021-10-21)
    apt_multi libncurses-dev libncurses5-dev # Not used since Wine 26c715f85b49 (2020-09-22)

    # The GStreamer development package can only be installed if the liborc
    # one supports multiarch
    apt_multi --test liborc-0.4-dev
    apt_multi --if-0 $? libgstreamer-plugins-base1.0-dev
    if [ $? -ne 0 ]
    then
        apt_multi libgstreamer-plugins-base1.0-0
        apt_multi libgstreamer1.0-dev
    fi

    apt_multi libopenal-dev
    apt_multi libosmesa6-dev
    apt_multi libpcap0.8-dev || apt_multi libpcap0.8

    # On Debian Testing this version has a conflicting man page (bug 1064636)
    apt_blacklist libpcsclite-dev 2.0.1-1.b1 libpcsclite-dev libpcsclite1

    apt_multi libpng-dev libpng12-dev # Not used since Wine c3d8a29a0499 (2021-10-18)

    # The PulseAudio development package can only be installed if the Glib2
    # one supports multiarch
    apt_multi --test libglib2.0-dev
    apt_multi --if-0 $? libpulse-dev || apt_multi libpulse0

    # On Debian 9 libsane-dev claims to support multiarch but is broken
    apt_blacklist libsane-dev 1.0.25-4.1 libsane-dev libsane

    apt_pkg libsasl2-dev # One arch is sufficient for Wine

    # On Ubuntu 18.04 libsdl2-dev depends on libmirclient-dev which breaks
    # without warning in a multiarch configuration!
    apt_blacklist libmirclient-dev 0.31.1-0ubuntu1 libsdl2-dev libsdl2-2.0-0

    # The CUPS development package can only be installed if the libtiff and
    # libcupsimage ones support multiarch
    rc=0
    apt_multi libtiff-dev libtiff5-dev || rc=1 # Not used since Wine d36615ee5232 (2021-10-19)
    apt_multi --test libcupsimage2-dev libcupsimage-dev || rc=1
    apt_multi --if-0 $rc libcups2-dev || apt_multi libcups2

    apt_multi libudev-dev
    apt_pkg   libunwind-dev # Wine only needs the 64-bit library
    apt_multi libusb-1.0-0-dev
    apt_multi libv4l-dev

    # vkd3d is not used since Wine 24432a24d5e9 (2022-03-03)
    # Before 1.2 vkd3d is missing libvkd3d-shader1 which is required for Wine.
    if apt_pkg libvkd3d-shader1
    then
        # Multiarch support is broken in early versions (see bug 983776)
        apt_blacklist libvkd3d-dev '1.2-[1-5]$' libvkd3d-dev libvkd3d1
    fi

    apt_multi libvulkan-dev

    apt_multi libwayland-dev

    apt_multi libx11-dev
    apt_multi libxcb1-dev
    apt_multi libxcomposite-dev
    apt_multi libxcursor-dev
    apt_multi libxi-dev
    apt_multi libxinerama-dev
    apt_multi libxkbcommon-dev
    apt_multi libxkbregistry-dev

    # The XML and XSLT development packages can only be installed if the ICU
    # one supports multiarch
    apt_multi --test libicu-dev; rc=$?
    apt_multi --if-0 $rc libxml2-dev || apt_multi libxml2 # Not used since Wine bca1b7f2faeb (2021-10-20)
    apt_multi --if-0 $rc libxslt1-dev || apt_multi libxslt1.1 # Not used since Wine bca1b7f2faeb (2021-10-20)

    apt_multi  libxrandr-dev
    apt_multi  libxrender-dev
    apt_multi  libxxf86vm-dev
    apt_pkg    make
    apt_multi  ocl-icd-opencl-dev
    apt_multi  oss4-dev
    apt_pkg    prelink # Not used since Wine 4a0f3fbcb587 (2023-02-27)

    # For libnetapi (see bug 961867)
    apt_check depends samba-libs:i386 -E 'Depends: python3?-talloc:i386'
    apt_multi --if-not-0 $? samba-dev

    apt_multi unixodbc-dev || apt_multi libodbc1
}

apt_wine_extra()
{
    apt_pkg autoconf
    apt_multi libgettextpo-dev # To let wrc rebuild PO files
    apt_pkg libxml-libxml-perl # For make_opengl
    apt_pkg python3   # For make_vulkan
    apt_pkg unzip     # For make_unicode
    apt_pkg wget      # For make_unicode, make_opengl
}

apt_wine_tests()
{
    local pkg
    apt_addsection ttf-mscorefonts-installer contrib "the Microsoft TrueType fonts packages" &&
        dry_run apt-get update

    # GStreamer plugins for the quartz (winegstreamer) tests
    apt_multi gstreamer1.0-libav

    apt_multi --test libmjpegutils-2.1-0
    apt_multi --if-0 $? gstreamer1.0-plugins-bad

    apt_multi gstreamer1.0-plugins-base
    apt_multi gstreamer1.0-plugins-good

    apt_multi --test libsidplay1v5
    apt_multi --if-0 $? gstreamer1.0-plugins-ugly

    apt_multi libnss-mdns
    # For each 64-bit libnss module, its 32-bit equivalent is needed too for
    # the 32-bit tests:
    for pkg in $(dpkg -l libnss-*:amd64 | sed -e 's/^.* \([a-zA-Z0-9-]*\):amd64.*$/\1/' -e t -e d)
    do
        apt_multi $pkg
    done

    # The MIDI tests have to go through ALSA which needs the PulseAudio plugin
    apt_multi libasound2-plugins

    apt_pkg ttf-mscorefonts-installer
    apt_pkg winbind   # For ntlm_auth
}

apt_wine_locales()
{
    # Install fonts for the locale tests
    # Use Debian's task-* packages, which includes the task-<locale>* ones
    # that install the fonts relevant to that locale.
    # Also install the fonts for mlterm, the multi-lingual terminal emulator.
    local tasks="$(apt-cache search '^task-' | cut -f1 -d' ')"
    local font_pkg=""
    local extra_pkg=""
    for font_pkg in $(LANG= apt-cache depends $tasks mlterm | sed -e 's/^ *Recommends: fonts-/fonts-/' -e t -e d | sort -u)
    do
        apt_pkg "$font_pkg"
        case "$font_pkg" in
        fonts-noto*)
            # Avoid the fonts-noto-*-extra packages as they cause excessive
            # Wine slowdowns (see bug 51367).
            for extra_pkg in $(LANG= apt-cache depends "$font_pkg" | sed -e 's/^ *Recommends: \(fonts-noto.*-extra\)$/\1/' -e t -e d | sort -u)
            do
                if dpkg -l "$extra_pkg" | grep -E -q '^[^hrp]n'
                then
                    apt-mark hold "$extra_pkg"
                fi
            done
            ;;
        esac
    done
    # Needed for gdi32:font in the Chinese locale
    apt_pkg fonts-arphic-uming
}

apt_wt_daily()
{
    apt_pkg ntfs-3g
    apt_pkg time
}

apt_tb_wine()
{
    apt_pkg genisoimage
    apt_pkg upx-ucl
}

apt_workarounds()
{
    local xsltconfig

    if [ "$opt_wine" = "1" ]
    then
        # Work around the missing or broken multiarch support where possible

        # Needed for all Debian versions so far
        if apt_is_installed libvkd3d1:i386
        then
            wt_create_sos libvkd3d-dev libvkd3d libvkd3d-shader libvkd3d-utils
        fi

        # Needed for Debian 10
        wt_create_sos libsdl2-dev libSDL2-2.0 # Broken up to 2.0.9
        wt_create_so libSDL2 libSDL2-2.0

        # Needed for Ubuntu 18.04
        wt_create_sos libcups2-dev libcups
        wt_create_sos libfontconfig1-dev libfontconfig
        wt_create_sos libfreetype6-dev libfreetype
        wt_create_sos libgnutls28-dev libgnutls
        wt_create_sos libpcap0.8-dev libpcap
        wt_create_sos libpcsclite-dev libpcsclite
        wt_create_sos libtiff-dev libtiff
        if ! apt_is_installed libgstreamer-plugins-base1.0-dev:i386
        then
            apt_dev_workaround libgstreamer-plugins-base1.0-dev
        fi

        wt_create_sos libgstreamer-plugins-base1.0-dev libgstaudio-1.0 libgstbase-1.0 libgstreamer-1.0 libgstvideo-1.0

        # Ubuntu 18.04 is missing libxslt/xsltconfig.h
        xsltconfig="libxslt/xsltconfig.h"
        if [ -f "/usr/include/x86_64-linux-gnu/$xsltconfig" -a \
             ! -f "/usr/include/i386-linux-gnu/$xsltconfig" -a \
             ! -f "/usr/include/$xsltconfig" -a \
             -d "/usr/include/libxslt" ]
        then
            dry_run ln -s "../x86_64-linux-gnu/$xsltconfig" "/usr/include/$xsltconfig"
        elif [ -f "/usr/include/x86_64-linux-gnu/$xsltconfig" -a \
               -f "/usr/include/i386-linux-gnu/$xsltconfig" -a \
               -h "/usr/include/$xsltconfig" ]
        then
            echo "Removing the obsolete /usr/include/$xsltconfig symlink (was for libxslt1-dev)"
            dry_run rm "/usr/include/$xsltconfig"
        fi

        # Needed for Debian 9
        wt_create_sos libgphoto2-dev libgphoto2 libgphoto2_port
        wt_create_sos libjpeg62-turbo-dev libjpeg
        wt_create_sos libkrb5-dev libcom_err libgssapi_krb5 libk5crypto libkrb5
        wt_create_sos libpulse-dev libpulse
        wt_create_sos libsane-dev libsane
        wt_create_sos libxml2-dev libxml2
        wt_create_sos libxslt1-dev libxslt
        wt_create_sos unixodbc-dev libodbc
    fi
}

apt_epilogue()
{
    if wt_explain_bad_pkgs "libfaudio-dev"
    then
        echo "* Wine does not use the distribution's FAudio development packages since"
        echo "  2021-10 so feel free to ignore this issue. For older versions, FAudio is only"
        echo "  available on distributions derived from Debian 11+."
        echo
    fi
    if wt_explain_bad_pkgs "libfaudio-dev:i386"
    then
        echo "* Wine does not use the distribution's FAudio development packages since"
        echo "  2021-10 so feel free to ignore this issue. For older versions, the"
        echo "  32-bit libfaudio-dev package is missing."
        echo
    fi
    if wt_explain_bad_pkgs "libgstreamer-plugins-base1.0-dev"
    then
        echo "* GStreamer has different header files for 32- and 64-bit. Unfortunately"
        echo "  libgstreamer-plugins-base1.0-dev:i386 cannot be installed because some of its"
        echo "  dependencies do not support multiarch. But this issue has been fixed in"
        echo "  Debian 10 which may provide a viable workaround."
        echo
    fi
    if apt_check show "libpcap0.8" "Version: 1\\.[2-9]"
    then
        echo "* libpcap is likely too old and missing pcap_init(), making it unusable."
        echo
    fi
    if wt_explain_bad_pkgs "libxkbregistry-dev"
    then
        echo "* libxkbregistry is not available on Debian 10 and older so Wayland is not supported."
        echo
    fi
    if wt_explain_bad_pkgs "prelink"
    then
        echo "* Wine does not use prelink since 2023-02 so feel free to ignore this issue."
        echo
    fi
    if wt_explain_bad_pkgs "ttf-mscorefonts-installer"
    then
        echo "* ttf-mscorefonts-installer is in the contrib section of the repository. You"
        echo "  may need to update /etc/apt/sources.list (man sources.list)."
        echo
    fi
    if wt_explain_bad_pkgs "oss4-dev"
    then
        echo "* OSS4 is no longer available in Debian but is obsolete anyway."
        echo "  If really required, it is available in the Debian multimedia repository:"
        echo "  deb-multimedia.org."
        echo
    fi
    if wt_explain_bad_pkgs "samba-dev:i386"
    then
        echo "* samba-dev ostensibly supports multiarch but the 32-bit version depends"
        echo "  on python:i386 through python-talloc and samba-libs. Similarly the 64-bit"
        echo "  version depends on python:amd64 thus breaking multiarch support."
        echo "  https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=961867"
        echo
    fi
    if wt_explain_bad_pkgs "libvkd3d-shader1"
    then
        echo "* Wine does not use the distribution's vkd3d development packages since 2022-03"
        echo "  so feel free to ignore this issue. For older versions, Wine needs a"
        echo "  vkd3d >= 1.2 package (see experimental?)."
        echo
    elif wt_explain_bad_pkgs "libvkd3d-dev:i386"
    then
        echo "* Wine does not use the distribution's vkd3d development packages since 2022-03"
        echo "  so feel free to ignore this issue. Should you want to install libvkd3d-dev"
        echo "  anyway, note that 1.2-* claims to support multiarch but some versions ship a"
        echo "  conflicting file (vkd3d-compiler)."
        echo "  https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=983776"
        echo
    fi
    if wt_explain_bad_pkgs "libvkd3d1:i386"
    then
        echo "* Wine does not use the distribution's vkd3d development packages since 2022-03"
        echo "  so feel free to ignore this issue. For older versions the 32-bit libvkd3d1"
        echo "  package is missing."
        echo
    fi
}


#####
#
# Zypper package manager (openSUSE, etc.)
#
#####

#
# zypper: Package helpers
#

zypper_retry_lock()
{
    local msg="$1"
    shift
    [ -n "$msg" ] && echo -n "$msg " >&3
    locked="Waiting for lock."
    while zypper "$@" 2>/dev/null; [ $? -eq 7 ]
    do
        echo -n "$locked" >&3
        locked="."
        sleep 1
    done
    [ -n "$msg" -o "$locked" = "." ] && echo " done" >&3
}

zypper_packages=""

zypper_get_packages()
{
    if [ -z "$zypper_packages" ]
    then
        zypper_packages=`zypper_retry_lock "Grabbing the available package list..." --non-interactive packages 3>&2 | sed -e '0,/\+----/ d' | cut -d'|' -f3 | sort -u`
        if [ -z "$zypper_packages" ]
        then
            error "'zypper packages' did not return the list of available packages"
            exit 1
        fi
    fi
}

zypper_newrepos=""

# zypper_addrepo <landmark> <project> <packages>
#
# Checks if the <landmark> package is available and returns immediately if it
# is. Otherwise builds the OBS repository URL from the <project> string and
# asks whether it should be added. If --yes was given or the user agrees the
# repository is added but 'zypper refresh' is not called.
#
# Returns 0 if the repository is available, non-zero otherwise.
zypper_addrepo()
{
    local a distname url
    local landmark="$1"
    local project="$2"
    local packages="$3"

    repo_alias=$(echo $project | sed -e 's/:/_/g')
    if zypper repos 2>/dev/null | grep -q "$repo_alias"
    then
        zypper_newrepos="$zypper_newrepos $repo_alias"
        return 0
    fi
    [ -n "$opt_norepo" ] && return 1

    zypper_get_packages
    if [ -n "$landmark" ]
    then
        case "$zypper_packages" in
        *" $landmark "*) return 1 ;;
        esac
    fi

    distname=`zypper targetos | sed -e 's/^Distribution Label: //' -e 's/-x86_64$//' -e 's/[ -]/_/g'`
    # zypper targetos is broken on openSUSE Leap 15.3+
    [ -n "$distname" ] || distname=`zypper --terse targetos --label | grep labelLong | sed -e 's/labelLong[ \t]*//' -e 's/ /_/g'`
    url="https://download.opensuse.org/repositories/$project/$distname/$project.repo"
    echo
    echo "********************"
    echo
    echo "The OBS repository below is needed for $packages."
    echo "$url"
    echo
    echo -n "Do you want to add it? [Y/n] "
    if [ -n "$opt_yes" ]
    then
        echo "yes"
        a="y"
    else
        read a
    fi
    [ -z "$a" -o "$a" = "y" -o "$a" = "Y" ] || return 1

    options="--refresh"
    if [ -n "$opt_yes" ]
    then
        # Disable GPG checks to avoid the new GPG key question during refresh.
        # Also disable auto-refresh to limit future usage.
        options="--no-gpgcheck"
    fi
    preopt=""
    [ -n "$opt_yes" ] && preopt="--non-interactive"
    dry_run zypper $preopt addrepo $options "$url"
    [ $? -ne 0 ] && return 1

    zypper_newrepos="$zypper_newrepos $repo_alias"
    return 0
}

# zypper_check <action> <pkg> <egrep-args>
#
# Checks that the information about <pkg> matches the specified <egrep-args>.
# With the 'info' <action> this can be used to verify that the package actually
# exists, has the expected version, etc.
zypper_check()
{
    local action="$1"
    local pkg="$2"
    shift 2
    LANG= zypper --non-interactive $action "$pkg" 2>/dev/null | grep -E -q "$@"
}

# zypper_pkg <pkg1> ...
#
# If <pkg1> exists, schedule it for installation and return success.
# Otherwise try again with the next package in the list.
#
# If none of the packages exists, add them all to the missing packages list
# and return failure.
zypper_pkg()
{
    local pkg

    zypper_get_packages
    for pkg in $*
    do
        echo -n "Checking $pkg..."
        case "$zypper_packages" in
        *" $pkg "*)
             echo " yes"
             pkginstall="$pkginstall $pkg"
             return 0
             ;;
        esac
        # zypper_get_packages() does not know about virtual packages so fall
        # back to a slower 'zypper install' dry-run.
        if zypper --non-interactive install --dry-run "$pkg" >/dev/null 2>&1
        then
            echo " yes"
            # Add the virtual package to $zypper_packages in case it is
            # queried again. Note: ensure it is enclosed in spaces.
            zypper_packages="$zypper_packages$pkg "
            pkginstall="$pkginstall $pkg"
            return 0
        fi

        echo " no"
    done
    pkgmissing="$pkgmissing "`echo "$@" | sed -e 's/ /|/g'`
    return 1
}

# zypper_multi <pkg1> ...
#
# Iterates over the package list until it finds a package that exists and
# schedules both its 32- and 64-bit versions for installation using
# zypper_pkg().
#
# If both 32- and 64-bit versions were found return 0 (success).
# If only the 64-bit version was found return 1 (failure).
# If no matching package was found return 2 (failure).
zypper_multi()
{
    local pkg rc multi_missing
    local saved_pkgmissing="$pkgmissing"
    for pkg in $*
    do
        rc=0
        zypper_pkg "$pkg" || rc=1
        zypper_pkg "$pkg-32bit" || rc=$((rc + 1))
        [ $rc -lt 2 ] && return $rc
        pkgmissing="$saved_pkgmissing"
        multi_missing="$multi_missing $pkg $pkg-32bit"
    done
    pkgmissing="$pkgmissing $multi_missing"
    return 2
}

zypper_install()
{
    local pkg oldpkginstall

    dry_run zypper_retry_lock "" --non-interactive needs-rebooting 3>&1 >/dev/null 2>&1

    # Try to detect and avoid package conflicts
    oldpkginstall=
    while [ "$oldpkginstall" != "$pkginstall" ]
    do
        oldpkginstall="$pkginstall"
        zypper --non-interactive install --dry-run $pkginstall >"$TMPDIR/$name0.$$" 2>&1

        for pkg in `sed -e 's/^ *Solution [0-9]*: do not install \(.*\)-[^-]*-[^-]*$/\1/' -e t -e d "$TMPDIR/$name0.$$"`
        do
            warning "Blacklisting $pkg because it causes conflicts"
            pkginstall=`echo "$pkginstall " | sed -e "s/ $pkg / /g"`
            pkgbroken="$pkgbroken $pkg"
        done
    done
    rm "$TMPDIR/$name0.$$"

    dry_run zypper install $opt_yes `wt_pretty_list $pkginstall` || exit 1
    echo
}

# zypper_is_installed <pkg1> ...
#
# Returns success if the specified packages are all installed.
zypper_is_installed()
{
    rpm -q "$@" >/dev/null 2>&1
}

# zypper_create_links <pc1> ...
#
# Provide a 32-bit file for missing -dev-32bit packages by symlinking it to the
# 64-bit one on the assumption they should be identical. This obviously can
# only work some some files like headers and pkgconfig files and only in some
# cases.
# Updating the broken and missing packages lists is left to the caller and will
# typically be taken care of by a subsequent wt_create_sos() call.
zypper_create_links()
{
    local file rc

    rc=0
    for file in "$@"
    do
        [ -f "/usr/lib/$file" ] && continue
        if [ ! -f "/usr/lib64/$file" ]
        then
            error "could not find the /usr/lib64/$file symlink target"
            rc=1
        elif [ ! -d `dirname "/usr/lib/$file"` ] &&
             ! dry_run mkdir -p `dirname "/usr/lib/$file"`
        then
            error "could not create the /usr/lib/$file parent directory"
            rc=1
        elif ! dry_run ln -s -f "/usr/lib64/$file" "/usr/lib/$file"
        then
            error "could not create the /usr/lib/$file symlink"
            rc=1
        fi
    done
    return $rc
}

# zypper_create_pcs <pc1> ...
#
# A thin wrapper around zypper_create_links() to simplify providing missing
# pkgconfig files.
zypper_create_pcs()
{
    local lib rc

    rc=0
    for lib in "$@"
    do
        zypper_create_links "pkgconfig/$lib.pc" || rc=1
    done
    return $rc
}


#
# zypper: Wine dependencies
#

zypper_init()
{
    local refresh
    if [ `arch` != "x86_64" ]
    then
        error "expected a 64-bit openSUSE distribution"
        exit 1
    fi

    wt_libdirs="/lib /lib64"
}

zypper_wine()
{
    refresh=
    zypper_addrepo mingw32-cross-gcc windows:mingw:win32 "the win32 MinGW cross-compiler" && refresh=1
    zypper_addrepo mingw64-cross-gcc windows:mingw:win64 "the win64 MinGW cross-compiler" && refresh=1
    if [ -n "$refresh" ]
    then
        dry_run zypper refresh
        # Force reloading the package list
        zypper_packages=""
    fi

    # Tools
    zypper_pkg   bison
    zypper_pkg   flex
    zypper_multi gcc
    zypper_pkg   gettext-runtime
    zypper_pkg   git
    zypper_pkg   make
    zypper_pkg   mingw32-cross-gcc
    zypper_pkg   mingw64-cross-gcc
    zypper_pkg   prelink # Not used since Wine 4a0f3fbcb587 (2023-02-27)

    # Libraries
    zypper_multi alsa-devel
    zypper_multi libcapi20-devel capi4linux-devel

    zypper_multi cups-devel
    # Missing dependencies in -devel-32bit on openSUSE Tumbleweed
    zypper_multi libcups2
    zypper_multi libnettle-devel

    zypper_multi cyrus-sasl-devel
    zypper_multi dbus-1-devel

    zypper_multi FAudio-devel # Not used since Wine d8be85863fed (2021-10-21)
    # Missing dependencies in -devel-32bit from Emulators:Wine (bug 1172309)
    zypper_multi libFAudio0

    zypper_multi fontconfig-devel
    # Missing dependencies in -devel-32bit on openSUSE Leap 15.1 (bug 1172301)
    zypper_multi fontconfig

    zypper_multi freetype2-devel
    # Missing dependency in -devel-32bit on openSUSE Tumbleweed
    zypper_multi libbz2-devel

    zypper_multi glibc-devel
    zypper_multi glu-devel # Not used since Wine ec55b1c271ae (2020-11-12)

    # Missing -devel-32bit package in openSUSE Leap 15.1 (bug 1172304)
    zypper_multi gstreamer-devel
    # Installing the 32-bit glib2-devel allows working around the missing
    # gstreamer-devel-32bit package. It also compensates for the missing
    # dependency in that package.
    zypper_multi glib2-devel
    # gstreamer-devel-32bit also needs the 32-bit xxx.pc files for these
    zypper_multi libelf-devel
    zypper_multi libzstd-devel
    zypper_multi xz-devel
    if zypper_check "info --requires" "glib2-devel" "pkgconfig[(]libpcre[)]"
    then
        # openSUSE Leap 15.4 case
        zypper_multi libdw-devel || zypper_multi libdw1
        zypper_multi libunwind-devel || zypper_multi libunwind
        zypper_multi orc || zypper_multi liborc-0_4-0
        zypper_multi pcre-devel || zypper_multi libpcre1
    else
        # openSUSE Tumbleweed case
        zypper_multi pcre2-devel || zypper_multi libpcre2-8-0
    fi
    zypper_multi gstreamer-plugins-base-devel

    zypper_multi jxrlib-devel # Not used since Wine eb0180e7b4df (2021-10-21)
    # Missing dependencies in -devel-32bit on openSUSE Tumbleweed (bug 1183053)
    zypper_multi libjpegxr0
    # Missing -32bit package in openSUSE Tumbleweed (bug 1183052)
    zypper_multi libjxrglue0

    zypper_multi krb5-devel
    # Missing dependency in -devel-32bit in openSUSE Leap 15.1 (bug 1172301)
    zypper_multi libcom_err-devel

    zypper_multi libgnutls-devel

    zypper_multi libgphoto2-devel
    # Missing dependencies in -devel-32bit in openSUSE Leap 15.1 (bug 1172301)
    zypper_multi libgphoto2-6
    zypper_multi libexif-devel

    zypper_multi libgsm-devel # Not used since Wine 0e7fd41af953 (2021-10-20)
    zypper_multi libjpeg8-devel # Not used since Wine a6ac035a7454 (2021-10-19)
    zypper_multi liblcms2-devel # Not used since Wine 5c4c272a2606 (2021-10-19)

    zypper_multi libnetapi-devel
    # Workaround the missing -devel-32bit package in openSUSE Leap 15.1 (bug 1172307)
    zypper_multi libnetapi0

    zypper_multi libOSMesa-devel
    zypper_multi libpcap-devel
    zypper_multi libpng16-compat-devel # Not used since Wine c3d8a29a0499 (2021-10-18)

    zypper_multi libpulse-devel
    # Missing dependency in -devel-32bit in openSUSE Leap 15.1 (bug 1172301)
    zypper_multi libpulse0

    zypper_multi libSDL2-devel
    zypper_multi libtiff-devel # Not used since Wine d36615ee5232 (2021-10-19)

    zypper_pkg   libunwind-devel # Wine only needs the 64-bit library

    zypper_multi libudev-devel systemd-devel || zypper_multi libudev1
    zypper_multi libusb-1_0-devel

    zypper_multi libv4l-devel
    # Missing dependency in -devel-32bit in openSUSE Leap 15.1 (bug 1172301)
    zypper_multi libv4l2-0

    zypper_multi libX11-devel
    zypper_multi libXcomposite-devel
    zypper_multi libXcursor-devel
    zypper_multi libXext-devel
    zypper_multi libXfixes-devel
    zypper_multi libXi-devel
    zypper_multi libXinerama-devel

    zypper_multi libxkbcommon-devel
    # Missing *-32bit packages in openSUSE Leap (bug 1218639)
    # and -devel-32bit package in Tumbleweed (bug 1218640)
    zypper_multi libxkbregistry-devel
    zypper_multi libxkbregistry0

    zypper_multi libXxf86vm-devel
    zypper_multi libxml2-devel # Not used since Wine bca1b7f2faeb (2021-10-20)
    zypper_multi libXrandr-devel
    zypper_multi libXrender-devel
    zypper_multi libxslt-devel # Not used since Wine bca1b7f2faeb (2021-10-20)

    zypper_multi Mesa-libGL-devel
    # Missing dependency in -devel-32bit in openSUSE Leap 15.1 (bug 1172302)
    zypper_multi Mesa-libGL1

    zypper_multi mpg123-devel # Not used since Wine 5329da61ac51 (2021-10-21)
    zypper_multi ncurses-devel # Not used since Wine 26c715f85b49 (2020-09-22)

    zypper_pkg   opencl-headers
    # Missing -32bit packages in openSUSE Leap 15.1 (bug 1172303)
    zypper_multi ocl-icd-devel
    zypper_multi libOpenCL1 # For the epilogue diagnostic

    zypper_multi openal-soft-devel
    # Missing dependency in -devel-32bit in openSUSE Leap 15.1 (bug 1172301)
    zypper_multi libopenal1

    zypper_multi openldap2-devel

    # Missing -32bit packages in openSUSE Leap but unused by Wine so far
    zypper_multi pcsc-lite-devel || zypper_multi libpcsclite1

    zypper_multi sane-backends-devel
    # Missing dependency in -devel-32bit in openSUSE Leap 15.1 (bug 1172301)
    # and in Tumbleweed. Also the libsane.so.* librares moved from
    # sane-backends in Leap 15.x to libsane1 in Tumbleweed.
    zypper_multi libsane1 sane-backends

    # unixODBC-devel-32bit only contains the pkg-config files (so no headers
    # and .so symlinks) but it is still needed.
    zypper_multi unixODBC-devel
    zypper_multi unixODBC

    # vkd3d is not used since Wine 24432a24d5e9 (2022-03-03)
    zypper_multi vkd3d-devel
    # Missing dependencies in -devel-32bit from home:dimesio (bug 1172310)
    zypper_multi libvkd3d1

    zypper_multi vulkan-devel
    # Missing dependency in -devel-32bit in openSUSE Leap 15.1 (bug 1172301)
    zypper_multi libvulkan1

    zypper_multi wayland-devel
    # Missing dependency in -devel-32bit in openSUSE Tumbleweed
    zypper_multi libffi-devel

    zypper_multi zlib-devel # Not used since Wine 7f726ddd89be (2021-10-18)
}

zypper_wine_extra()
{
    zypper_pkg autoconf
    zypper_pkg gettext-tools # To let wrc rebuild PO files
    zypper_pkg perl-XML-LibXML # For make_opengl
    zypper_pkg python3   # For make_vulkan
    zypper_pkg unzip     # For make_unicode
    zypper_pkg wget      # For make_unicode, make_opengl
}

zypper_wine_tests()
{
    zypper_pkg fetchmsttfonts

    # GStreamer plugins for the quartz (winegstreamer) tests
    zypper_multi gstreamer-plugins-bad
    zypper_multi gstreamer-plugins-base
    zypper_multi gstreamer-plugins-good
    zypper_multi gstreamer-plugins-libav
    zypper_multi gstreamer-plugins-ugly

    # The MIDI tests have to go through ALSA which needs the PulseAudio plugin
    zypper_multi alsa-plugins-pulse

    zypper_pkg samba-winbind   # For ntlm_auth
}

zypper_wine_locales()
{
    # Install fonts for the locale tests (mirrored from the Debian list)
    zypper_pkg baekmuk-ttf-fonts
    zypper_pkg dejavu-fonts
    zypper_pkg khmeros-fonts
    zypper_pkg noto-sans-fonts
    zypper_pkg noto-coloremoji-fonts
}

zypper_wt_daily()
{
    zypper_pkg ntfs-3g
    zypper_pkg time
}

zypper_tb_wine()
{
    true # upx-ucl is not available
}

zypper_workarounds()
{
    if [ "$opt_wine" = "1" ]
    then
        # Work around the missing 32-bit development packages where possible

        # Needed for openSUSE Leap 15.1
        wt_create_sos gstreamer-devel-32bit libgstbase-1.0 libgstreamer-1.0
        wt_create_sos libnetapi-devel-32bit libnetapi
        wt_create_sos Mesa-libGL-devel-32bit libGL
        wt_create_sos ocl-icd-devel-32bit libOpenCL
        wt_create_sos vulkan-devel-32bit libvulkan

        # Needed for openSUSE Leap 15.4
        zypper_create_links "dbus-1.0/include/dbus/dbus-arch-deps.h"
        wt_create_sos "(libudev|systemd)-devel-32bit" libudev
        wt_create_sos pcsc-lite-devel-32bit libpcsclite

        # Needed for GStreamer on openSUSE Leap 15.4
        zypper_create_pcs libdw && wt_create_sos libdw-devel-32bit libdw
        zypper_create_pcs libffi && wt_create_sos libffi-devel-32bit libffi
        if zypper_is_installed pcre-devel
        then
            # autoconf mostly needs the pkgconfig workaround
            zypper_create_pcs libpcre && wt_create_sos pcre-devel-32bit libpcre
        fi
        zypper_create_pcs libunwind && wt_create_sos libunwind-devel-32bit libunwind
        zypper_create_pcs orc-0.4 && wt_create_sos orc-32bit liborc-0.4

        # Needed for GStreamer on openSUSE Tumbleweed
        if zypper_is_installed pcre2-devel
        then
            # GStreamer needs this one through GLib2
            # and autoconf mostly needs the pkgconfig workaround
            zypper_create_pcs libpcre2-8 && wt_create_sos pcre2-devel-32bit libpcre2-8
        fi

        # Needed for Wayland on openSUSE Tumbleweed
        if zypper_is_installed libxkbregistry0-32bit &&
           zypper_is_installed libxkbregistry-devel
        then
            zypper_create_pcs xkbregistry && wt_create_sos libxkbregistry-devel-32bit libxkbregistry
        fi
    fi
}

zypper_epilogue()
{
    if wt_explain_bad_pkgs "capi4linux-devel" "capi4linux-devel-32bit" "libcapi20-devel" "libcapi20-devel-32bit"
    then
        echo "* openSUSE Leap 15.3+ is missing all support for libcapi20. This only impacts"
        echo "  the rare Windows applications that would use ISDN phone lines."
        echo "  https://bugzilla.opensuse.org/show_bug.cgi?id=1191039"
        echo "  https://wiki.winehq.org/Building_Wine#Satisfying_Build_Dependencies"
        echo
    fi
    if wt_explain_bad_pkgs "FAudio-devel"
    then
        echo "* Wine does not use the distribution's FAudio development packages since 2021-10. For older versions, FAudio-devel is available through the Emulators:Wine project on the OBS."
        echo "  https://build.opensuse.org/project/show/Emulators:Wine"
        echo
    fi
    if wt_explain_bad_pkgs "gstreamer-devel-32bit"
    then
        echo "* GStreamer has different header files for 32- and 64-bit. Unfortunately"
        echo "  gstreamer-devel-32bit is missing which means there is no easy workaround."
        echo "  But you can check these two pages for more information on how to manually"
        echo "  overcome this hurdle:"
        echo "  https://bugzilla.opensuse.org/show_bug.cgi?id=973217"
        echo "  https://wiki.winehq.org/OpenSUSE#Build_Tools_and_Dependencies"
        echo
    fi
    if wt_explain_bad_pkgs "jxrlib-devel-32bit" "libjpegxr0-32bit" "libjxrglue0-32bit"
    then
        echo "* Wine does not use the distribution's jxrlib packages since 2021-10 so feel free"
        echo "  to ignore this issue. For older versions, both jxrlib-devel-32bit and"
        echo "  jxrlib-32bit are missing so there is no 32-bit support at all for JPEG XR"
        echo "  images. Try a newer distributution release."
        echo
    fi
    if [ "$opt_wine" = "1" -a "$opt_packages" = "1" ]
    then
        echo "* OSS4 is known not to be available but is obsolete anyway."
        echo "  https://wiki.winehq.org/Building_Wine#Satisfying_Build_Dependencies"
        echo
    fi
    if wt_explain_bad_pkgs "mingw32-cross-gcc"
    then
        echo "* The MinGW compiler is available through the windows:mingw:win32 projects"
        echo "  on the OBS."
        echo "  https://build.opensuse.org/project/show/windows:mingw:win32"
        echo
    fi
    if wt_explain_bad_pkgs "mingw64-cross-gcc"
    then
        echo "* The MinGW compiler is available through the windows:mingw:win64 projects"
        echo "  on the OBS."
        echo "  https://build.opensuse.org/project/show/windows:mingw:win64"
        echo
    fi
    if wt_explain_bad_pkgs "prelink"
    then
        echo "* Wine does not use prelink since 2023-02 so feel free to ignore this issue."
        echo "  For older versions, it may be possible to use the RHEL prelink package."
        echo "  https://software.opensuse.org/package/prelink"
        echo
    fi
    if wt_explain_bad_pkgs "vkd3d-devel" "vkd3d-devel-32bit" "libvkd3d1" "libvkd3d1-32bit"
    then
        echo "* Wine does not use the distribution's vkd3d development packages since 2022-03"
        echo "  so feel free to ignore this issue. For older versions vkd3d is only available"
        echo "  through the home:dimesio project on the OBS."
        echo "  https://build.opensuse.org/project/show/home:dimesio"
        echo
    fi
    if [ -n "$opt_yes" -a -n "$zypper_newrepos" ]
    then
        echo "* Because of the --yes option the GPG checks had to be disabled for the"
        echo "  new repositories below. You may want to remove them or manually reenable"
        echo "  GPG checking and auto-refresh."
        for repo in $zypper_newrepos
        do
            echo "    zypper modifyrepo --gpgcheck --refresh $repo"
        done
        echo
    fi
}


#####
#
# Command line processing
#
#####

wt_parse_cmdline()
{
    local arg
    local usage=""
    while [ $# -gt 0 ]
    do
        arg="$1"
        shift
        case "$arg" in
        --wine)       opt_wine="1" ;;
        --no-wine)    opt_wine="0" ;;
        --extra)      opt_wine_extra="1" ;;
        --no-extra)   opt_wine_extra="0" ;;
        --tests)      opt_wine_tests="1" ;;
        --no-tests)   opt_wine_tests="0" ;;
        --locales)    opt_wine_locales="1" ;;
        --no-locales) opt_wine_locales="0" ;;
        --wt-daily)   opt_wt_daily="1" ;;
        --no-wt-daily) opt_wt_daily="0" ;;
        --tb-wine)    opt_tb_wine="1" ;;
        --no-tb-wine) opt_tb_wine="0" ;;
        --all)        opt_wine="1"
                      opt_wine_extra="1"
                      opt_wine_tests="1"
                      opt_wine_locales="1"
                      opt_wt_daily="1"
                      opt_tb_wine="1"
                      ;;
        --no-repo)    opt_norepo="0" ;;
        --packages)   opt_packages="1" ;;
        --workarounds) opt_workarounds="1" ;;
        --yes)        opt_yes="-y";;
        --dry-run)    opt_dry_run="1" ;;
        --cmd-log)
            if [ -n "$opt_cmd_log" ]
            then
                error "--cmd-log can only be specified once"
                usage=2 # but continue processing options
            fi
            if [ $# -eq 0 ]
            then
                error "missing value for --cmd-log"
                usage=2
            else
                opt_cmd_log="$1"
                shift
            fi
            ;;
        --help|-h|-?)
            usage=0
            break
            ;;
        *)
            error "unknown option '$arg'"
            usage=2
            break
            ;;
        esac
    done

    if [ -z "$usage" ]
    then
        if [ -z "$opt_wine$opt_wine_extra$opt_wine_tests$opt_locales$opt_wt_daily$opt_tb_wine" ]
        then
            opt_wine="1"
            opt_wine_extra="1"
        fi
        if [ -z "$opt_packages$opt_workarounds" ]
        then
            opt_packages="1"
            opt_workarounds="1"
        fi
    fi

    if [ "$usage" = "0" ]
    then
        echo "Usage: $name0 [--no-wine] [--no-extra] [--tests] [--locales] [--wt-daily] [--tb-wine] [--no-repo] [--packages] [--workarounds] [--yes] [--cmd-log SCRIPT] [--dry-run] [--help]"
        echo

        echo "Installs the packages needed to build the 32- and 64-bit versions of Wine. When possible applies workarounds if installing both the 32- and 64-bit development packages is impossible. Can also install some extra packages needed by the tests and the wt-daily scripts."
        echo
        echo "Default options:"
        echo "  --wine --extra --no-tests --no-locales --no-wt-daily --no-tb-wine --packages --workarounds"
        echo "Tested on:"
        echo "  Debian 9 & 10, Linux Mint 19.03, Ubuntu 18.04 & 19.10."
        echo "  openSUSE Leap 15.1, Tumbleweed (2020-05)."
        echo

        echo "Where:"
        echo "  --no-wine    Do not install the packages needed to compile Wine."
        echo "  --no-extra   Only install the packages needed to compile Wine, not those"
        echo "               needed to regenerate part of its source (autoconf, etc)."
        echo "  --tests      Install some packages needed to run the Wine tests."
        echo "  --locales    Install packages needed to test Wine in most locales."
        echo "  --wt-daily   Install the packages needed for the wt-daily scripts."
        echo "  --tb-wine    Install the packages needed for the TestBot's wine VMs."
        echo "  --all        Same as --wine --extra --tests --locales --wt-daily --tb-wine."
        echo "  --no-repo    Don't add extra package repositories."
        echo "  --packages   Install the packages."
        echo "  --workarounds Apply workarounds for packages that don't support multiarch so"
        echo "               that both the 32- and 64-bit versions of Wine can be built."
        echo "  --yes        Answer yes to all package installation prompts."
        echo "  --cmd-log SCRIPT Saves all commands being run to the specified shell script."
        echo "  --dry-run    Only show which actions would be taken."
        echo "  --help, -h   Shows this help message."
        exit 0
    elif [ -n "$usage" ]
    then
        error "try '$name0 --help' for more information"
        exit $usage
    fi
}

wt_build_cmdargs()
{
    # Rebuild a cleaner, more explicit command line for --cmd-log
    wt_cmdargs=""
    [ "$opt_wine" = "1" ] && wt_cmdargs="$wt_cmdargs --wine"
    [ "$opt_wine_extra" = "1" ] && wt_cmdargs="$wt_cmdargs --extra"
    [ "$opt_wine_tests" = "1" ] && wt_cmdargs="$wt_cmdargs --tests"
    [ "$opt_wine_locales" = "1" ] && wt_cmdargs="$wt_cmdargs --locales"
    [ "$opt_wt_daily" = "1" ] && wt_cmdargs="$wt_cmdargs --wt-daily"
    [ "$opt_tb_wine" = "1" ] && wt_cmdargs="$wt_cmdargs --tb-wine"
    [ "$opt_norepo" = "1" ] && wt_cmdargs="$wt_cmdargs --no-repo"
    [ "$opt_packages" = "1" ] && wt_cmdargs="$wt_cmdargs --packages"
    [ "$opt_workarounds" = "1" ] && wt_cmdargs="$wt_cmdargs --workarounds"
    [ "$opt_yes" = "1" ] && wt_cmdargs="$wt_cmdargs --yes"
    [ "$opt_dry_run" = "1" ] && wt_cmdargs="$wt_cmdargs --dry-run"
}


#####
#
# Package installation
#
#####

wt_init()
{
    [ -n "$TMPDIR" ] || TMPDIR="/tmp"
    if [ -x "/usr/bin/apt-cache" -a -x "/usr/bin/apt-get" ]
    then
        wt_platform="apt"
    elif [ -x "/usr/bin/zypper" ]
    then
        wt_platform="zypper"
    else
        error "this Linux distribution is not supported."
        exit 1
    fi
    ${wt_platform}_init
    if [ -n "$opt_cmd_log" ]
    then
        (
            echo "#!/bin/sh"
            echo "# Generated by $name0$wt_cmdargs"
            . /etc/os-release
            echo "# For the '$wt_platform' platform on $PRETTY_NAME"
            echo "# These commands may not be applicable to any other platform."
            if [ "$opt_dry_run" = "1" ]
            then
                echo "# *** WARNING ***"
                echo "# In --dry-run mode the workarounds will likely be incorrect or incomplete."
            fi
            echo "set -x"
            echo
        ) >"$opt_cmd_log"
        if [ $? -ne 0 ]
        then
            error "could not generate the --cmd-log script"
            exit 1
        fi
        chmod +x "$opt_cmd_log"
    fi
}

wt_pre_install()
{
    if [ "$opt_packages" = "1" ]
    then
        [ "$opt_wine" = "1" ] && ${wt_platform}_wine
        [ "$opt_wine_extra" = "1" ] && ${wt_platform}_wine_extra
        [ "$opt_wine_tests" = "1" ] && ${wt_platform}_wine_tests
        [ "$opt_wine_locales" = "1" ] && ${wt_platform}_wine_locales
        [ "$opt_wt_daily" = "1" ] && ${wt_platform}_wt_daily
        [ "$opt_tb_wine" = "1" ] && ${wt_platform}_tb_wine
    fi
}

wt_install()
{
    [ "$opt_packages" = "1" ] && ${wt_platform}_install
}

wt_post_install()
{
    [ "$opt_workarounds" = "1" ] && ${wt_platform}_workarounds
}

wt_epilogue()
{
    echo
    ${wt_platform}_epilogue

    pkgworkaround=`wt_pretty_list "$pkgworkaround"`
    if [ -n "$pkgworkaround" ]
    then
        echo "* Workarounds were successfully applied for the following broken or missing"
        echo "  packages."
        echo "  $pkgworkaround"
        echo
    fi

    pkgbroken=`wt_pretty_list "$pkgbroken"`
    if [ -n "$pkgbroken" ]
    then
        echo "* Could not install the following packages because they do not support"
        echo "  multiarch."
        echo "  $pkgbroken"
        echo
    fi

    pkgmissing=`wt_pretty_list "$pkgmissing"`
    if [ -n "$pkgmissing" ]
    then
        echo "* Could not install the following packages because they are not available."
        echo "  $pkgmissing"
        echo
    fi
}


#####
#
# Main
#
#####

if [ -z "$WT_INSTALL_DEV_LIB" ]
then
    opt_wine=""
    opt_wine_extra=""
    opt_wine_tests=""
    opt_wine_locales=""
    opt_wt_daily=""
    opt_tb_wine=""
    opt_norepo=""
    opt_packages=""
    opt_workarounds=""
    opt_yes=""
    opt_dry_run=""
    opt_cmd_log=""
    wt_parse_cmdline "$@"
    wt_build_cmdargs
    wt_init
    wt_pre_install
    wt_install
    wt_post_install
    wt_epilogue
fi