diff --git a/src/asm/output.cpp b/src/asm/output.cpp index 70a251c2..d92e6ef7 100644 --- a/src/asm/output.cpp +++ b/src/asm/output.cpp @@ -490,12 +490,14 @@ static bool dumpMacros(FILE *file) { } void out_WriteState(std::string name, std::vector const &features) { + // State files may include macro bodies, which may contain arbitrary characters, + // so output as binary to preserve them. FILE *file; if (name != "-") { - file = fopen(name.c_str(), "w"); + file = fopen(name.c_str(), "wb"); } else { name = ""; - file = fdopen(STDOUT_FILENO, "w"); + file = fdopen(STDOUT_FILENO, "wb"); } if (!file) err("Failed to open state file '%s'", name.c_str()); diff --git a/test/asm/state-file/a.asm b/test/asm/state-file/a.asm new file mode 100644 index 00000000..b8e47b31 --- /dev/null +++ b/test/asm/state-file/a.asm @@ -0,0 +1,26 @@ +OPT Wno-unmapped-char + +DEF constant EQU 1 +DEF variable = 2 +DEF string EQUS "hello!" +CHARMAP "c", 4 +MACRO polo + db 5 +ENDM + +def variable += 1 + +def con2 equ -1 +def var2 = variable**2 +def str2 equs strcat("{string}", "\0\n\t\r") +charmap "c2", 10, -11, 987654321 + +PURGE polo +MACRO mac2 + !?@#;^& +ENDM + +newcharmap map2, main +charmap "\0\n\t\r", "\t", "\r", "\0", "\n" + +REDEF string EQUS "goodbye~" diff --git a/test/asm/state-file/a.dump.asm b/test/asm/state-file/a.dump.asm new file mode 100644 index 00000000..d3205863 --- /dev/null +++ b/test/asm/state-file/a.dump.asm @@ -0,0 +1,27 @@ +; File generated by rgbasm + +; Numeric constants +def constant equ $1 +def con2 equ $ffffffff + +; Variables +def variable = $3 +def var2 = $9 + +; String constants +def string equs "goodbye~" +def str2 equs "hello!\0\n\t\r" + +; Character maps +newcharmap main +charmap "c", $4 +charmap "c2", $a, $fffffff5, $3ade68b1 +newcharmap map2 +charmap "c", $4 +charmap "c2", $a, $fffffff5, $3ade68b1 +charmap "\0\n\t\r", $9, $d, $0, $a + +; Macros +macro mac2 + !?@#;^& +endm diff --git a/test/asm/test.sh b/test/asm/test.sh index c12246d4..5bf64923 100755 --- a/test/asm/test.sh +++ b/test/asm/test.sh @@ -129,6 +129,40 @@ for i in *.asm; do done done +# These tests do their own thing + +i="state-file" +if which cygpath &>/dev/null; then + # MinGW translates path names before passing them as command-line arguments, + # but does not do so when they are prefixed, so we have to do it ourselves. + RGBASMFLAGS="-Weverything -s all:$(cygpath -w "$o")" +else + RGBASMFLAGS="-Weverything -s all:$o" +fi +for variant in '' '.pipe'; do + (( tests++ )) + echo "${bold}${green}${i%.asm}${variant}...${rescolors}${resbold}" + if [ -z "$variant" ]; then + "$RGBASM" $RGBASMFLAGS "$i"/a.asm >"$output" 2>"$errput" + else + # shellcheck disable=SC2002 + cat "$i"/a.asm | "$RGBASM" $RGBASMFLAGS - >"$output" 2>"$errput" + fi + + tryDiff /dev/null "$output" out + our_rc=$? + tryDiff /dev/null "$errput" err + (( our_rc = our_rc || $? )) + tryDiff "$i"/a.dump.asm "$o" err + (( our_rc = our_rc || $? )) + + (( rc = rc || our_rc )) + if [[ $our_rc -ne 0 ]]; then + (( failed++ )) + break + fi +done + if [[ "$failed" -eq 0 ]]; then echo "${bold}${green}All ${tests} tests passed!${rescolors}${resbold}" else