# Sourced by the scripts in scripts/ (and tools/) so every one of them finds # toolchains the same way: from the environment ./install.sh generates. A script calls joeyNeed for each tool it uses, and gets a clear # "install this" message (exit 2, which the gate runners treat as SKIP) # instead of failing halfway through with a missing binary. JOEY_REPO="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" if [ -f "$JOEY_REPO/toolchains/env.sh" ]; then # shellcheck source=/dev/null source "$JOEY_REPO/toolchains/env.sh" fi # joeyNeed VAR INSTALL-TARGET -- exit 2 unless VAR names an existing path. joeyNeed() { local var="$1" local target="$2" if [ -z "${!var:-}" ] || [ ! -e "${!var}" ]; then echo "$(basename "$0"): $var is not available; run: ./install.sh install $target" >&2 exit 2 fi } # joeyNeedFile PATH INSTALL-TARGET -- exit 2 unless PATH exists. joeyNeedFile() { if [ ! -e "$1" ]; then echo "$(basename "$0"): $1 is missing; run: ./install.sh install $2" >&2 exit 2 fi } # DOSBox Staging must never read or write the user's own DOSBox setup, even # ~/.config/dosbox (it creates that tree even with --noprimaryconf). Launch # it as # XDG_CONFIG_HOME="$work/xdg" "$DOSBOX" "${JOEY_DOSBOX_ISOLATE[@]}" ... JOEY_DOSBOX_ISOLATE=(--noprimaryconf --nolocalconf) # joeyExampleProgram NAME PORT -- the built program for an example name. A # program that ships in its own folder with its DATA (Space Taxi on every # port but the IIgs) is found inside that folder. When nothing is built yet # it prints the flat path, so the caller's "not built" message names it. joeyExampleProgram() { local name="$1" local bin="$JOEY_REPO/build/$2/bin" local up="${name^^}" local ext="" local candidate [ "$up" = "SPACETAXI" ] && up=STAXI case "$2" in iigs) printf '%s\n' "$bin/$up" return 0 ;; amiga) # Mixed-case names, and Space Taxi is called Taxi there. up="${name,,}" case "$up" in staxi|spacetaxi) up=taxi ;; esac up="${up^}" ;; atarist) ext=".PRG" ;; dos) ext=".EXE" ;; x68000) ext=".X" ;; *) echo "$(basename "$0"): unknown port '$2' (iigs, amiga, atarist, dos or x68000)" >&2 return 2 ;; esac for candidate in "$bin/$up/$up$ext" "$bin/$up$ext"; do if [ -f "$candidate" ]; then printf '%s\n' "$candidate" return 0 fi done # A mixed-case Amiga name (SerTest) is not derivable from the example # name, so take the file in any case. candidate="$(find "$bin" -maxdepth 1 -type f -iname "$up$ext" -print -quit 2>/dev/null)" if [ -n "$candidate" ]; then printf '%s\n' "$candidate" return 0 fi printf '%s\n' "$bin/$up$ext" } # joeyFindWindow DISPLAY PID -- print the X window owned by process PID. # More robust than matching titles, which differ between emulator builds. joeyFindWindow() { local win for win in $(DISPLAY="$1" xdotool search --name -- "." 2>/dev/null); do if [ "$(DISPLAY="$1" xdotool getwindowpid "$win" 2>/dev/null)" = "$2" ]; then printf '%s\n' "$win" return 0 fi done return 1 } # joeyAlive PID -- PID is running. A zombie (exited, not yet reaped) is not, # although `kill -0` still succeeds on it. joeyAlive() { local stat stat="$(ps -o stat= -p "$1" 2>/dev/null)" || return 1 [[ "$stat" != Z* ]] } # joeyStop PID... -- stop emulator processes and make sure they are gone. # Hatari, MAME and DOSBox Staging ignore or are slow to act on SIGTERM; a # plain `kill` left them running (and burning CPU) after their script had # finished, so escalate to SIGKILL. Only ever pass PIDs this script started. joeyStop() { local pid local tick for pid in "$@"; do [ -n "$pid" ] || continue kill "$pid" 2>/dev/null || continue for tick in 1 2 3 4 5 6 7 8 9 10; do joeyAlive "$pid" || break sleep 0.2 done kill -9 "$pid" 2>/dev/null || true # Reap it when it is this shell's child (a no-op otherwise), so no # zombie outlives the script where nothing else would reap it. wait "$pid" 2>/dev/null || true done }