#!/bin/bash # Version 1.1 #Copied from https://github.com/noabody/unibuild/blob/master/data/wstart # WINEARCH win32/win64 not as good as binary wine/wine64" # WINEDEBUG="-all" not as good as dev/null # complex command line builder to simplify command objects # vars bin, pfx set to wine binary, prefix dirs initially # menus will dynamically set bin pfx to specific targets # menu shows gui based 32/64-bit pe header exe via pev # var 'x' for unified cross-functionality # ${@:2} skips 'wstart' and 1st arg # manjaro 21.2.1 #sudo pacman -S bash binutils findutils gendesk grep icoutils pcre2 perl yay winetricks; yay -S pev # wnbin needs wine dir with: bin lib lib64 share # manjaro default path is /usr # can symlink various wnbin="$HOME/.local/opt" #mkdir "$HOME"/.local/opt #ln -sf /usr "$HOME"/.local/opt/wine #ln -sf /usr/share/steam/compatibilitytools.d/proton-ge-custom/files "$HOME"/.local/opt/proton wnbin="/usr" # top level wine dir, symlink into "$HOME/.local/opt" to flatten paths wnpfx="$HOME" # top level wine prefix dir pntop="$HOME/.steam" # top level linux steam dir pnapp="$pntop/steam/steamapps" # steamapps subdir pnbin="$pnapp/common" # proton subdir normally under top/app pnpfx="$pnapp/compatdata" # proton prefix subdir normally under top/app pnpge="$pntop/root/compatibilitytools.d" # proton ge progs="drive_c/Program Files" # Program Files standard subdir stcmn="Steam/steamapps/common" # windows steam client subdir under progs desk="$HOME/Desktop" # desktop entry folder icon="applications-other" # default icon temp="$HOME/Downloads" # temp folder clprm=("${@:2}") # store cmdline args minus first option x="$(echo "$1" | grep -Pio '(?<=-)[wp]')" # 1st letter of 1st cmd line arg determines wine/proton if [[ -n "$x" ]]; then xarg="$(echo "$1" | perl -pe 's/-[wp]/-x/gi')" else xarg="$(echo "$1" | perl -pe 's/-x+/-/gi')" fi # drop 1st letter x or change to it xcmd=() i_mnus=() myprnt=() i_syms=() pmenu=("Command Prompt/wineconsole.exe" "Control Panel/control.exe" "Registry Editor/regedit.exe" "Task Manager/taskmgr.exe" "Windows Explorer/explorer.exe" "Wine Configuration/winecfg.exe") # scalable built-in programs menu unset WINEARCH WINEDLLPATH WINEPREFIX STEAM_COMPAT_CLIENT_INSTALL_PATH STEAM_COMPAT_DATA_PATH # prevent shell inheritance of env vars we use w_menu () { PS3="Please enter your choice: " select answer in "${i_mnus[@]}"; do for item in "${i_mnus[@]}"; do if [[ $item == "$answer" ]]; then break 2 fi done done # repeating menu requires valid selection from array if [[ "$answer" = "quit" ]]; then # pop quit from end of array for menu option exit else xmrtn="$answer" fi unset i_mnus clear } # Path ordering: wine64 x64/x32 or wine32 x32 then standard # Order critical to proper operation xn64 () { xstrt="wine64" xnldl="$xnbin/lib64:$xnbin/lib" xndll="$xnbin/lib64/wine:$xnbin/lib/wine" } xn32 () { xstrt="wine" xnldl="$xnbin/lib" xndll="$xnbin/lib/wine" } xnint () { if [[ "$x" = "p" ]]; then xnbin="$pnbin" xnpfx="$pnpfx" dpth=(4 3) else xnbin="$wnbin" xnpfx="$wnpfx" dpth=(3 2) fi } xnexe () { # menu installed wine/proton or exit readarray -t i_mnus < <(find -L "$xnbin" -maxdepth "${dpth[0]}" -type f -iname 'wine' ! \( -ipath '*/sbin*' \) 2>/dev/null | perl -pe "s|\Q$xnbin\E/(.*)[/]*bin/wine|\1| ; s|/$||" | sort ; echo "quit") if [[ ${#i_mnus[@]} -gt 2 ]]; then clear w_menu xnbin="$(realpath "$xnbin/$xmrtn")" unset xmrtn elif [[ ${#i_mnus[@]} -eq 2 ]]; then xnbin="$(realpath "$xnbin/${i_mnus[0]}")" else echo "No installed Wine/Proton found." exit 1 fi } xndef () { # create default prefix cross-function if [[ "$x" = "p" ]]; then if [[ ! -d "$xnpfx/0" ]]; then # always create default 0 prefix xnpfx="$xnpfx/0" echo "Creating default prefix: $xnpfx" mkdir -p "$xnpfx" STEAM_COMPAT_DATA_PATH="$xnpfx" "${xnbin%/*}/proton" run > /dev/null 2>&1 & xnpfx="$xnpfx/pfx" fi else if [[ ! -d "$xnpfx/.wine" ]]; then # always create default wine prefix xnpfx="$xnpfx/.wine" echo "Creating default prefix: $xnpfx" WINEPREFIX="$xnpfx" "$xnbin"/bin/winecfg > /dev/null 2>&1 & if [[ -d "$HOME/.wine" && "$HOME/.wine" != "$xnpfx" ]]; then rm -rf "$HOME"/.wine ln -sf "$xnpfx" "$HOME"/.wine fi fi fi } xnpre () { # menu wine/proton prefix readarray -t i_mnus < <(find "$xnpfx" -maxdepth "${dpth[1]}" -type f -iname 'system.reg' 2>/dev/null | perl -pe "s|\Q$xnpfx\E/(.*)/system.reg|\1|" | sort ; echo "quit") # use perl escaped Q/E to preserve special characters in path variable if [[ ${#i_mnus[@]} -gt 2 ]]; then # display menu with min two options plus quit # guard proton cross-function if [[ "$x" = "p" ]]; then # shellcheck disable=SC2044 for value in $(find "$xnpfx" -maxdepth 1 -type d -ipath '*/[0-9]*' -printf "${xnpfx///compatdata}/appmanifest_%P.acf\n" 2>/dev/null); do test -f "$value" && myprnt+=("$(grep -Pio '^\s+\"(appid|name)\"\s+\"(.*)\"' "$value" | perl -pe 's/.*appid.+?\"(.*)\"\v|.*name.+?\"(.*)\"/\1 \2/')") done if [[ ${#myprnt[@]} -gt 0 ]]; then printf '%s\n' "${myprnt[@]}" | sort fi # correlate appmanifest to proton prefix and list before menu unset myprnt fi w_menu xnpfx="$xnpfx/$xmrtn" unset xmrtn elif [[ ${#i_mnus[@]} -eq 2 ]]; then # don't menu if only one option plus quit xnpfx="$xnpfx/${i_mnus[0]}" fi if [[ -d "$xnpfx/$progs (x86)" ]]; then xn64 else xn32 fi } xnenv () { # core env vars allow proper targetting of wine/proton xpath="$xnbin/bin:$PATH" xcmd=(env PATH="$xpath" WINEDLLPATH="$xndll" LD_LIBRARY_PATH="$xnldl" WINEPREFIX="$xnpfx") # guard proton cross-function which adds on to core env vars if [[ "$x" = "p" ]]; then xcmd+=(STEAM_COMPAT_DATA_PATH="${xnpfx///pfx}" STEAM_COMPAT_CLIENT_INSTALL_PATH="$pntop") fi } xnldr () { # loader default to proton as applicable, otherwise wine if [[ "$x" = "p" ]]; then read -r -p 'wine loader? [y/N] ' chse if [[ "$chse" =~ ^([yY][eE][sS]|[yY])+$ ]]; then xcmd+=("$xstrt") else xcmd+=("${xnbin%/*}/proton" "run") fi else xcmd+=("$xstrt") fi } xnset () { # set cross-fuction xnint # wine/proton menu xnexe # create default prefix as required xndef # wine/proton prefix xnpre # wine/proton env vars xnenv } xlnch () { # cross-function command line launcher if [[ -z "$dbg" ]]; then ("${xcmd[@]}" > /dev/null 2>&1 &) else echo "${xcmd[@]}" if [[ "$dbg" = "1" ]]; then ("${xcmd[@]}" &) elif [[ "$dbg" = "2" ]]; then (WINEDEBUG="warn+all" "${xcmd[@]}" &) fi fi # prepend cmd with dbg=1 to see command and default debug output # dbg=2 to see command and all debug output, dbg=? for command only } allexe () { # unfiltered list of exe in specified path if [[ -n "$(stat --file-system --format=%T "$(stat --format=%m "$pedir" 2>/dev/null)" 2>/dev/null | grep -Pio 'fuse')" ]]; then readarray -t i_mnus < <(find "$pedir" -maxdepth 7 -type f -regextype posix-extended -iname '*.exe' 2>/dev/null | perl -pe "s|\Q$pedir\E/(.*)|\1|" | sort ; echo "quit") # skip exe validity tests if file is on network drive else readarray -t i_mnus < <(env pedir="$pedir" find "$pedir" -maxdepth 7 -type f -regextype posix-extended -iname '*.exe' -exec sh -c '(readpe -h optional "$1" 2>/dev/null | grep -Piq '0x2.*gui') && (wrestool "$1" 2>/dev/null | grep -Piq 'type=icon') && echo "$1" 2>/dev/null | perl -pe "s|\Q$pedir\E/(.*)|\1|"' -- {} \; 2>/dev/null | sort ; echo "quit") # perform exe validity tests if file is on local drive fi } fewexe () { # filtered list of exe in standard paths readarray -t i_mnus < <(env pedir="$pedir" find "$pedir" -maxdepth 7 -type f -regextype posix-extended ! \( -ipath '*cache*' -o -ipath '*/microsoft*' -o -ipath '*/windows*' -o -ipath '*/temp*' \) ! \( -iregex '.*(capture|clokspl|helper|iexplore|install|internal|kernel|[^ ]launcher|legacypm|overlay|proxy|redist|renderer|(crash|error)reporter|serv(er|ice)|setup|streaming|tutorial|unins|update).*' \) -iname '*.exe' -exec sh -c '(readpe -h optional "$1" 2>/dev/null | grep -Piq '0x2.*gui') && (wrestool "$1" 2>/dev/null | grep -Piq 'type=icon') && echo "$1" 2>/dev/null | perl -pe "s|\Q$pedir\E/(.*)|\1|"' -- {} \; 2>/dev/null | sort ; echo "quit") # valid exe will have gui and icon } alloth () { # unfiltered list of variable type in specified path readarray -t i_mnus < <(find "$pedir" -maxdepth 7 -type f -regextype posix-extended -iname "$xflt" 2>/dev/null | perl -pe "s|\Q$pedir\E/(.*)|\1|" | sort ; echo "quit") } fewoth () { # filtered list of variable type in standard paths readarray -t i_mnus < <(env pedir="$pedir" find "$pedir" -maxdepth 7 -type f -regextype posix-extended ! \( -ipath '*cache*' -o -ipath '*/microsoft*' -o -ipath '*/windows*' -o -ipath '*/temp*' \) ! \( -iregex '.*(capture|clokspl|helper|iexplore|install|internal|kernel|[^ ]launcher|legacypm|overlay|proxy|redist|renderer|(crash|error)reporter|serv(er|ice)|setup|streaming|tutorial|unins|update).*' \) -iname "$xflt" 2>/dev/null | perl -pe "s|\Q$pedir\E/(.*)|\1|" | sort ; echo "quit") } xbld () { # cross-function custom prefix builder pnpfx="$pnpfx/${clprm[0]}" wnpfx="$wnpfx/${clprm[0]}" xnint if [[ -z "${clprm[0]}" ]]; then echo "Wine/Proton prefix name required: (e.g. .wine, 0 )" elif [[ -d "$xnpfx" ]]; then echo "Wine/Proton Prefix exists: $xnpfx" else xnexe echo "Creating Wine/Proton Prefix: ${clprm[0]}" if [[ "$x" = "p" ]]; then xnenv mkdir -p "$xnpfx" xcmd+=(STEAM_COMPAT_DATA_PATH="$xnpfx" "${xnbin%/*}/proton" "run") else read -r -p '32-bit only? [y/N] ' chse if [[ "$chse" =~ ^([yY][eE][sS]|[yY])+$ ]]; then xn32 xnenv xcmd+=(WINEARCH="win32" "$xstrt" "winecfg.exe") else xn64 xnenv xcmd+=(WINEARCH="win64" "$xstrt" "winecfg.exe") fi fi xlnch fi } xpmn () { # use specified exe, menu specified folder, or menu system if [[ -f "${clprm[0]}" ]]; then # parse 1st cmdline arg, queue if valid file pedir="$(realpath "${clprm[0]}")" xmrtn="$(basename "$pedir")" pedir="$(dirname "$pedir")" else if [[ -d "${clprm[0]}" ]]; then # parse 1st cmdline arg, use as path if valid pedir="$(realpath "${clprm[0]}")" test -z "$xflt" && allexe || alloth else # if no cmdline path, use prefix drive_c pedir="$xnpfx/drive_c" test -z "$xflt" && fewexe || fewoth fi # create menu, from path, of file test ${#i_mnus[@]} -gt 1 && w_menu fi } xlyt() { # pe layout for launch # 64-bit prefix, 32-bit pe header, reset env to 32 if [[ -n "$(readpe -h optional "$pedir/$xmrtn" 2>/dev/null | grep -Pi 'magic number.*0x10b')" && -d "$xnpfx/$progs (x86)" ]]; then xn32 xnenv fi xnldr # if 1st arg is file/folder, skip it and run selection + remaining args if [[ -e "${clprm[0]}" ]];then xcmd+=("$pedir/$xmrtn" "${clprm[@]:1}") else xcmd+=("$pedir/$xmrtn" "${clprm[@]}") fi } xstm() { if [[ "$x" = "p" ]]; then sstrt="$(realpath "$(which steam)" 2>/dev/null)" else xnset sstrt="$(find "$xnpfx/drive_c" -maxdepth 3 -iname 'steam.exe' 2>/dev/null)" if [[ -f "$sstrt" ]]; then pnapp="$(dirname "$sstrt")/steamapps" xcmd+=("$xstrt") fi fi # find wine/proton steam binary path, normally subdir of program files if [[ -f "$sstrt" ]]; then test -d "$pnapp" && readarray -t i_mnus < <(find "$pnapp" -maxdepth 1 -type f -iname 'appmanifest_*.acf' -exec grep -Pio '^\s+\"(appid|name)\"\s+\"(.*)\"' "{}" \; 2>/dev/null | perl -pe 's/.*appid.+?\"(.*)\"\v|.*name.+?\"(.*)\"/\1 \2/' | sort ; echo -e "steam\nquit") # read appmanifests to create menu entries test ${#i_mnus[@]} -gt 2 && w_menu && xmrtn="$(expr "$xmrtn" : '\([0-9]*\)')" if [[ -n "$xmrtn" ]]; then # lauch selection with steam xcmd+=("$sstrt" "-no-browser" "-applaunch" "$xmrtn") xlnch else # launch steam was selected # minigamelist (short game list) for no-browser (disabled chrome) to save memory xcmd+=("$sstrt" "-no-browser" "steam://open/minigameslist") xlnch fi else echo -e "Steam not found." fi } xpge () { test -d "$pnpge" || mkdir -p "$pnpge" test -d "$pnbin" || mkdir -p "$pnbin" if [[ ! -d "$(dirname "$pnpge")" ]]; then echo -e "Could not create folder 'compatibilitytools.d/protonge' in:\n $(dirname "$pnpge")\n because that path does not exist.\nVerify script variable 'pnpge'" elif [[ ! -d "$pnbin" ]]; then echo -e "Could not create sym-link 'protonge' in:\n $pnbin\n because that path does not exist.\nVerify script variable 'pnbin'" else gedl="$(curl -sL https://api.github.com/repos/GloriousEggroll/proton-ge-custom/releases/latest | jq -r ".tag_name")" # gedl="$(gh release list -R GloriousEggroll/proton-ge-custom -L 1 | grep -Pio '^ge[^ ]+')" gever="$(echo "$gedl" | grep -Pio '(?<=ge-proton).*')" if [[ -f "$pnpge/protonge/version" ]]; then if [[ -z "$(grep -Pio "$gever" "$pnpge/protonge/version")" ]]; then echo -e "Available Proton GE $gever differs from installed, updating...\n" chse=y else echo -e "Available Proton GE $gever matches installed, nothing to do.\n" fi else echo -e "Proton GE not found, installing...\n" chse=y fi fi if [[ -n "$chse" ]]; then wget --progress=dot:giga "$(curl -s https://api.github.com/repos/GloriousEggroll/proton-ge-custom/releases/latest | grep browser_download_url | cut -d\" -f4 | grep .tar.gz)" -P "$temp"/ rm -rf "$pnpge/protonge" tar -xf "$temp/$gedl".tar.gz -C "$pnpge/" mv "$pnpge"/*roton* "$pnpge/protonge" rm -f "$temp/$gedl".tar.gz grep -Piq "$gever" "$pnpge/protonge/version" || perl -pi -e "s|(?<=ge-proton).*|$gever|gi" "$pnpge/protonge/version" test -h "$pnbin/protonge" || ln -sf "$pnpge/protonge" "$pnbin" fi } xwn () { export WINE_BRANCH=staging sudo mkdir -pm755 /etc/apt/keyrings && sudo curl -fsSL -o /etc/apt/keyrings/winehq-archive.key "https://dl.winehq.org/wine-builds/winehq.key" \ && sudo curl -fsSL -o "/etc/apt/sources.list.d/winehq-$(grep UBUNTU_CODENAME= /etc/os-release | cut -d= -f2 | tr -d '\"').sources" "https://dl.winehq.org/wine-builds/ubuntu/dists/$(grep UBUNTU_CODENAME= /etc/os-release | cut -d= -f2 | tr -d '\"')/winehq-$(grep UBUNTU_CODENAME= /etc/os-release | cut -d= -f2 | tr -d '\"').sources" \ && sudo apt-get update && sudo apt-get install --install-recommends -y winehq-${WINE_BRANCH} \ && sudo curl -fsSL -o /usr/bin/winetricks "https://raw.githubusercontent.com/Winetricks/winetricks/master/src/winetricks" \ && sudo chmod 755 /usr/bin/winetricks \ && sudo curl -fsSL -o /usr/share/bash-completion/completions/winetricks "https://raw.githubusercontent.com/Winetricks/winetricks/master/src/winetricks.bash-completion" } usage() { echo -e "\n$(basename $0): ERROR - $*" 1>&2 echo -e "\nusage: $(basename $0)\n [-?a,--?add] [-?b,--?bld] [-?c,--?cmd] [-?d,--?dsk]\n [-?i,--?inf] [-?k,--?kil] [-?o,--?ovr] [-?p,--?prg]\n [-?s,--?stm] [-?t,--?trk] [-?u,--?cut] [-?v,--?ver]\n\n[?] = (p)roton, (w)ine\n (add) exe path to reg, (bld) build prefix,\n (cmd) prog menu, (dsk) desktop, (inf) exe info,\n (kil) kill wine, (ovr) overrides, (prg) exe list,\n (stm) steam, (trk) winetricks, (cut) shortcut,\n (ver) wine version\n" 1>&2 } if [[ $# -lt 1 ]]; then usage "one option required!" else case $xarg in -xa|--xadd) # cross-fuction path add to registry based on exe xnint xnpre xpmn if [[ -n "$xmrtn" ]]; then ptadd="$(dirname "$pedir/$xmrtn")" ptadd="z:${ptadd////\\\\}" read -r -p 'prepend to system path? [y/N] ' chse clear if [[ "$chse" =~ ^([yY][eE][sS]|[yY])+$ ]]; then xnreg='System\\CurrentControlSet\\Control\\Session Manager\\Environment' xmrtn='system.reg' else xnreg='Environment' xmrtn='user.reg' fi if [[ -z "$(pcre2grep -Mio "\[\Q${xnreg,,}\E\](?s).+?\"PATH\"=str\(2\):\".+?(?=\[.+?\])(?-s)" "$xnpfx/$xmrtn")" ]]; then perl -0777 -pi -e "s|(\[\Q${xnreg,,}\E\](?s).+?#time=(?-s).*)(?s)(.+?)(?=\[.+?\])(?-s)|\\1\n\"PATH\"=str\(2\):\"${ptadd//\\/\\\\}\"\\2|gi" "$xnpfx/$xmrtn" echo -e "$( (echo "$xnreg" | grep -Pioq '\\Environment') && echo 'HKLM\\' || echo 'HKCU\\')$xnreg:\n\n $ptadd\n\nPATH created successfully\n" elif [[ -z "$(pcre2grep -Mio "\[\Q${xnreg,,}\E\](?s).+?\"PATH\"=str\(2\):\"(?-s).*\Q${ptadd,,}\E[\;\"](?s).+?(?=\[.+?\])(?-s)" "$xnpfx/$xmrtn")" ]]; then perl -0777 -pi -e "s|(\[\Q${xnreg,,}\E\](?s).+?\"PATH\"=str\(2\):\")(?-s)(.*)(?s)(.+?)(?=\[.+?\])(?-s)|\\1${ptadd//\\/\\\\}\;\\2\\3|gi" "$xnpfx/$xmrtn" echo -e "$( (echo "$xnreg" | grep -Pioq '\\Environment') && echo 'HKLM\\' || echo 'HKCU\\')$xnreg:\n\n $ptadd\n\nPATH added successfully\n" else echo -e "$( (echo "$xnreg" | grep -Pioq '\\Environment') && echo 'HKLM\\' || echo 'HKCU\\')$xnreg:\n\n $ptadd\n\nalready in PATH\n" fi # \Q \E adds \ to non alphanums but variable with \E ends \Q # lowercase ${var,,} to avoid since path/reg not case sensitive # linux path is case sensitive so user must not create duplicates fi ;; -xb|--xbld) # cross-function prefix builder xbld ;; -xc|--xcmd) # cross-function standard tools menu xnset readarray -t i_mnus < <(printf '%s\n' "${pmenu[@]}" | perl -pe 's|/.*||gi' ; echo "quit") w_menu xmrtn="$(printf '%s\n' "${pmenu[@]}" | grep -Pio "(?<=$xmrtn/).*")" xnldr if [[ -f "${clprm[0]}" ]];then pedir="$(realpath "${clprm[0]}")" cd "$(dirname "$pedir")" || exit xcmd+=("$xmrtn" "$pedir" "${clprm[@]:1}") else xcmd+=("$xmrtn" "${clprm[@]}") fi xlnch ;; -xd|--xdsk) # cross-function wine desktop xnset xnldr xcmd+=("explorer.exe" "/desktop=shell,1024x768" "explorer.exe") xlnch ;; -i|--install) # proton ge xpge xwn ;; -xi|--xinf) # cross-fuction program info if [[ ! -f "${clprm[0]}" && ! -d "${clprm[0]}" ]]; then # don't menu prefix on supplied file or folder xnint xnpre fi if [[ ! -f "${clprm[0]}" ]]; then # offer to menu dll if no file given read -r -p 'query dll? [y/N] ' chse if [[ "$chse" =~ ^([yY][eE][sS]|[yY])+$ ]]; then xflt="*.dll" fi fi xpmn IFS=$'\n' if [[ -n "$xmrtn" ]]; then if [[ $(readpe "$pedir/$xmrtn" 2>/dev/null) ]]; then # if file is PE print 32/64-bit and dll references myprnt+=("$(readpe -h optional "$pedir/$xmrtn" 2>/dev/null | grep -Piq 'PE32\+' && echo -e "FILE:\n$xmrtn\n \nPE HEADER:\n64-bit" || echo -e "FILE:\n$xmrtn\n \nPE HEADER:\n32-bit")") myprnt+=("$(echo -e ' \nVersion:' ; peres -v "$pedir/$xmrtn" 2>/dev/null | grep -Pio '(?<=Product Version:).*' | tr -d ' ')") # find dll references, filenames without spaces myprnt+=("$(echo -e ' \nREFERENCES:' ; strings "$pedir/$xmrtn" | grep -Pio '[^<>:"/\\|?*\s]+\.dll' | perl -pe 's|([^/]*\Z)|lc($1)|e' | sort -u ; echo ' ')") else myprnt+=("$(echo -e ' \nNot a 32/64-bit program, no information to provide\n ')") fi else myprnt+=("$(echo -e ' \nNo file found\n ')") fi printf '%s\n' "${myprnt[@]}" unset IFS myprnt ;; -xk|--xkil) # cross-function wine kill, must select same as running xnset xcmd+=("wineserver" "-k") xlnch ;; -xo|--xovr) # cross-function prefix override list xnint xnpre read -r -p 'per application? [y/N] ' chse clear IFS=$'\n' myprnt+=("$(echo -e "Prefix:\n$xnpfx\n ")") if [[ "$chse" =~ ^([yY][eE][sS]|[yY])+$ ]]; then # show existing per-application overrides myprnt+=("$(echo -e 'Per-application overrides:' ; pcre2grep -Mio '\[\Qsoftware\\wine\\appdefaults\\\E[^\\]+\Q\\dlloverrides\E\](?s).+?(?=\[.+?\])(?-s)' "$xnpfx/user.reg" | grep -Pio '(?<=appdefaults..).*(?=..dlloverrides)|\".*\"' && echo ' ' || echo -e 'None found\n ')") else # show existing prefix overrides myprnt+=("$(echo -e 'Global overrides:' ; pcre2grep -Mio '\[\Qsoftware\\wine\\dlloverrides\E\](?s).+?(?=\[.+?\])(?-s)' "$xnpfx/user.reg" | grep -Pio '\".*\"' && echo ' ' || echo -e 'None found\n ')") fi printf '%s\n' "${myprnt[@]}" unset IFS myprnt # A command like: # perl -pi -e 's/(\".*msvc.*\"=\")(.*),(.*)(")/\1\3,\2\4/g' user.reg # Swaps msvc entries (native,builtin) to (builtin,native) ;; -xr|--xrun) # cross-fuction run program - 1st arg valid file to run, folder to menu, # neither (sys menu), 2nd arg... passed to exe xnset xpmn if [[ -n "$xmrtn" ]]; then xlyt # change to exe dir before run cd "$(dirname "$pedir/$xmrtn")" || exit xlnch fi ;; -xs|--xstm) # cross-function steam launcher xstm ;; -xt|--xtrk) # cross-function winetricks xnset # winetricks for selected wine/proton prefix if [[ ${#clprm[@]} -gt 0 ]]; then xcmd+=("winetricks" "${clprm[@]}") dbg="1" # use args if supplied, otherwise gui else xcmd+=("winetricks" "--gui") # protontricks may work better fi xlnch ;; -xu|--xcut) # cross-function desktop shortcut if [[ -d "$desk" ]]; then xnset xpmn if [[ -n "$xmrtn" ]]; then xlyt # change to desktop dir before create icon cd "$desk" || exit read -r -e -p $'Shortcut Name?\x0a' -i "$(basename "${xmrtn/.*}")" chse # create desktop entry gendesk -f -n --name="$chse" --comment='created by wstart' --custom='Keywords=wine;proton;launcher;' --exec="bash -c 'cd \"$(dirname "$pedir/$xmrtn")\" ; $(printf '"%s" ' "${xcmd[@]}")'" --icon="$icon" --terminal=false --categories='Emulator;Game' --startupnotify=false --pkgname="$chse" chmod 755 "$chse".desktop fi else echo -e "Invalid desktop location: $desk\nPlease edit the script" fi ;; -xv|--xver) # cross-function wine version xnint xnexe xnenv xcmd+=("wine" "--version") ("${xcmd[@]}" &) ;; -h|--help) echo -e "\n General usage: netris-proton -w? args\n -w? options for wine and -p? for proton.\n Type wstart by itself for command list.\n\n Edit script path variables as needed.\n bash, find, gendesk, grep, readpe,\n strings, winetricks, wrestool,\n pcre2grep, peres, perl needed by\n certain items.\n" ;; -*|\*|*) # do_usage usage "invalid option $1" exit 1 ;; esac fi