#!/usr/bin/env bash # Embed the CWSDPMI DPMI server into a DJGPP-built DOS executable so # the resulting .EXE is self-contained and does not require a separate # CWSDPMI.EXE on the target machine. Run as a post-link step from the # DOS Makefile. # # Usage: embed-dpmi.sh program.EXE # # Mechanism: DJGPP .EXE files are COFF binaries prefixed with a small # MZ stub. Stripping the stub via exe2coff leaves a pure COFF image. # CWSDSTUB.EXE is a larger MZ stub that contains a full DPMI host; # concatenating CWSDSTUB.EXE with the COFF image produces a new .EXE # with the DPMI server built in. # # Requires $DOS_EXE2COFF and $DOS_CWSDSTUB (exported by make from the # installer's toolchains/config.mk; toolchains/env.sh for a shell). set -euo pipefail if [[ $# -ne 1 ]]; then echo "usage: $0 program.EXE" >&2 exit 2 fi exe=$1 for v in DOS_EXE2COFF DOS_CWSDSTUB; do if [[ -z "${!v:-}" ]]; then echo "$v not set; run ./install.sh install toolchain:dos" >&2 exit 1 fi done if [[ ! -x $DOS_EXE2COFF ]]; then echo "exe2coff not executable: $DOS_EXE2COFF" >&2 exit 1 fi if [[ ! -f $DOS_CWSDSTUB ]]; then echo "CWSDSTUB.EXE not found: $DOS_CWSDSTUB" >&2 exit 1 fi if [[ ! -f $exe ]]; then echo "executable not found: $exe" >&2 exit 1 fi coff=${exe%.*} coff_tmp=${coff}.coff.tmp trap 'rm -f "$coff_tmp" "$coff"' EXIT # djgpp-gcc on a case-sensitive host writes its output to both case # variants (e.g. PATTERN.EXE and PATTERN.exe) as distinct files. # Remove the lowercase sibling so DOSBox's case-folded lookup cannot # pick up the pre-embed copy after we rewrite the uppercase one. lower_exe=${coff}.exe if [[ $exe != "$lower_exe" && -f $lower_exe ]]; then rm -f "$lower_exe" fi "$DOS_EXE2COFF" "$exe" if [[ ! -f $coff ]]; then echo "exe2coff did not produce expected output: $coff" >&2 exit 1 fi cat "$DOS_CWSDSTUB" "$coff" > "$coff_tmp" mv "$coff_tmp" "$exe" trap - EXIT rm -f "$coff"