mirror of
https://github.com/gbdev/rgbds.git
synced 2026-10-06 04:05:38 +00:00
Merge branch 'master' into features-1.1.0
This commit is contained in:
commit
ad4e399018
26 files changed
+235
-197
No files matched your search
@@ -87,13 +87,13 @@ jobs:
|
||||
if-no-files-found: error
|
||||
|
||||
linux:
|
||||
runs-on: ubuntu-22.04 # Oldest supported, for best glibc compatibility.
|
||||
runs-on: ubuntu-24.04 # Oldest supported, for best glibc compatibility.
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v7
|
||||
- name: Install deps
|
||||
run: |
|
||||
./.github/scripts/install-deps.sh ubuntu-22.04
|
||||
./.github/scripts/install-deps.sh ubuntu-24.04
|
||||
- name: Build binaries
|
||||
run: |
|
||||
make -k -j "$(getconf _NPROCESSORS_ONLN)" WARNFLAGS="-Werror -Wall -Wextra -pedantic -static" PKG_CONFIG="pkg-config --static" Q=
|
||||
|
||||
@@ -40,15 +40,15 @@ jobs:
|
||||
unix:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-22.04, macos-15-intel, macos-26]
|
||||
os: [ubuntu-24.04, ubuntu-26.04-arm, macos-15-intel, macos-26]
|
||||
cxx: [g++, clang++]
|
||||
buildsys: [make, cmake]
|
||||
exclude: # Don't use `g++` on macOS; it's just an alias to `clang++`.
|
||||
- { os: macos-15-intel, cxx: g++ }
|
||||
- { os: macos-26, cxx: g++ }
|
||||
include: # Use `g++-10`, the earliest GCC version we support, on the earliest Ubuntu runner.
|
||||
- { os: ubuntu-22.04, cxx: g++-10, buildsys: make }
|
||||
- { os: ubuntu-22.04, cxx: g++-10, buildsys: cmake }
|
||||
- { os: ubuntu-24.04, cxx: g++-10, buildsys: make }
|
||||
- { os: ubuntu-24.04, cxx: g++-10, buildsys: cmake }
|
||||
fail-fast: false
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
@@ -102,8 +103,7 @@ void sect_RelBytes(uint32_t n, std::vector<Expression> const &exprs);
|
||||
void sect_RelWord(Expression const &expr, uint32_t pcShift);
|
||||
void sect_RelLong(Expression const &expr, uint32_t pcShift);
|
||||
void sect_PCRelByte(Expression const &expr, uint32_t pcShift);
|
||||
bool sect_BinaryFile(std::string const &name, uint32_t startPos);
|
||||
bool sect_BinaryFileSlice(std::string const &name, uint32_t startPos, uint32_t length);
|
||||
bool sect_BinaryFile(std::string const &name, uint32_t startPos, std::optional<uint32_t> length);
|
||||
|
||||
void sect_EndSection();
|
||||
void sect_PushSection();
|
||||
|
||||
+1
-1
@@ -47,7 +47,7 @@ public:
|
||||
}
|
||||
std::streambuf *operator->() { return &**this; }
|
||||
|
||||
char const *c_str(std::string const &path) const {
|
||||
char const *display_name(std::string const &path) const {
|
||||
return std::holds_alternative<std::filebuf>(_file) ? path.c_str()
|
||||
: std::get<std::streambuf *>(_file) == std::cin.rdbuf() ? "<stdin>"
|
||||
: "<stdout>";
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <streambuf>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "gfx/rgba.hpp"
|
||||
@@ -17,7 +18,11 @@ struct Png {
|
||||
bool isIndexed = false;
|
||||
|
||||
Png() {}
|
||||
Png(std::string const &path);
|
||||
Png(char const *filename, std::streambuf &file);
|
||||
|
||||
private:
|
||||
void initialize(char const *filename, std::streambuf &file);
|
||||
};
|
||||
|
||||
#endif // RGBDS_GFX_PNG_HPP
|
||||
@@ -53,6 +53,12 @@
|
||||
#define O_TEXT 0 // Assume that it's not defined either
|
||||
#endif // _MSC_VER
|
||||
|
||||
// MSVC doesn't have POSIX `ftruncate`, use a suitable replacement
|
||||
#if defined(_MSC_VER)
|
||||
#include <io.h> // IWYU pragma: export
|
||||
#define ftruncate _chsize_s
|
||||
#endif
|
||||
|
||||
// Windows has stdin and stdout open as text by default, which we may not want
|
||||
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||
#include <io.h> // IWYU pragma: export
|
||||
|
||||
+3
-3
@@ -1048,17 +1048,17 @@ include:
|
||||
|
||||
incbin:
|
||||
POP_INCBIN string {
|
||||
if (sect_BinaryFile($2, 0)) {
|
||||
if (sect_BinaryFile($2, 0, std::nullopt)) {
|
||||
YYACCEPT;
|
||||
}
|
||||
}
|
||||
| POP_INCBIN string COMMA uconst {
|
||||
if (sect_BinaryFile($2, $4)) {
|
||||
if (sect_BinaryFile($2, $4, std::nullopt)) {
|
||||
YYACCEPT;
|
||||
}
|
||||
}
|
||||
| POP_INCBIN string COMMA uconst COMMA uconst {
|
||||
if (sect_BinaryFileSlice($2, $4, $6)) {
|
||||
if (sect_BinaryFile($2, $4, $6)) {
|
||||
YYACCEPT;
|
||||
}
|
||||
}
|
||||
|
||||
+32
-78
@@ -998,10 +998,13 @@ void sect_PCRelByte(Expression const &expr, uint32_t pcShift) {
|
||||
}
|
||||
}
|
||||
|
||||
bool sect_BinaryFile(std::string const &name, uint32_t startPos) {
|
||||
bool sect_BinaryFile(std::string const &name, uint32_t startPos, std::optional<uint32_t> length) {
|
||||
if (!requireCodeSection()) {
|
||||
return false;
|
||||
}
|
||||
if (length.has_value() && *length == 0) { // Don't even bother with 0-byte slices
|
||||
return false;
|
||||
}
|
||||
|
||||
FILE *file = nullptr;
|
||||
if (std::optional<std::string> fullPath = fstk_FindFile(name); fullPath) {
|
||||
@@ -1022,6 +1025,16 @@ bool sect_BinaryFile(std::string const &name, uint32_t startPos) {
|
||||
*fileSize
|
||||
);
|
||||
return false;
|
||||
} else if (length.has_value() && *length > *fileSize - startPos) {
|
||||
error(
|
||||
"Specified range in `INCBIN` file \"%s\" is out of bounds (%" PRIu32 " + %" PRIu32
|
||||
" > %" PRIu64 ")",
|
||||
name.c_str(),
|
||||
startPos,
|
||||
*length,
|
||||
*fileSize
|
||||
);
|
||||
return false;
|
||||
}
|
||||
// The file is seekable; skip to the specified start position
|
||||
fseek(file, startPos, SEEK_SET);
|
||||
@@ -1044,9 +1057,27 @@ bool sect_BinaryFile(std::string const &name, uint32_t startPos) {
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
if (length.has_value()) {
|
||||
uint32_t remaining = *length;
|
||||
for (; remaining; --remaining) {
|
||||
if (int byte = fgetc(file); byte == EOF) {
|
||||
break; // LCOV_EXCL_LINE
|
||||
} else {
|
||||
writeByte(byte);
|
||||
}
|
||||
}
|
||||
if (remaining > 0 && !ferror(file)) {
|
||||
error(
|
||||
"Premature end of `INCBIN` file \"%s\" (%" PRId32 " bytes left to read)",
|
||||
name.c_str(),
|
||||
remaining
|
||||
);
|
||||
}
|
||||
} else {
|
||||
for (int byte; (byte = fgetc(file)) != EOF;) {
|
||||
writeByte(byte);
|
||||
}
|
||||
}
|
||||
|
||||
if (ferror(file)) {
|
||||
// LCOV_EXCL_START
|
||||
@@ -1056,83 +1087,6 @@ bool sect_BinaryFile(std::string const &name, uint32_t startPos) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool sect_BinaryFileSlice(std::string const &name, uint32_t startPos, uint32_t length) {
|
||||
if (!requireCodeSection()) {
|
||||
return false;
|
||||
}
|
||||
if (length == 0) { // Don't even bother with 0-byte slices
|
||||
return false;
|
||||
}
|
||||
|
||||
FILE *file = nullptr;
|
||||
if (std::optional<std::string> fullPath = fstk_FindFile(name); fullPath) {
|
||||
file = fopen(fullPath->c_str(), "rb");
|
||||
}
|
||||
if (!file) {
|
||||
return fstk_FileError(name, "`INCBIN`");
|
||||
}
|
||||
Defer closeFile{[&] { xfclose(file); }};
|
||||
|
||||
if (std::optional<uint64_t> fileSize = seekSize(file); fileSize.has_value()) {
|
||||
if (startPos > *fileSize) {
|
||||
error(
|
||||
"Specified start position (%" PRIu32 ") is greater than length of \"%s\" (%" PRIu64
|
||||
")",
|
||||
startPos,
|
||||
name.c_str(),
|
||||
*fileSize
|
||||
);
|
||||
return false;
|
||||
} else if (length > *fileSize - startPos) {
|
||||
error(
|
||||
"Specified range in `INCBIN` file \"%s\" is out of bounds (%" PRIu32 " + %" PRIu32
|
||||
" > %" PRIu64 ")",
|
||||
name.c_str(),
|
||||
startPos,
|
||||
length,
|
||||
*fileSize
|
||||
);
|
||||
return false;
|
||||
}
|
||||
// The file is seekable; skip to the specified start position
|
||||
fseek(file, startPos, SEEK_SET);
|
||||
} else {
|
||||
// LCOV_EXCL_START
|
||||
if (errno != ESPIPE) {
|
||||
error(
|
||||
"Error determining size of `INCBIN` file \"%s\": %s", name.c_str(), strerror(errno)
|
||||
);
|
||||
}
|
||||
// The file isn't seekable, so we'll just skip bytes one at a time
|
||||
while (startPos--) {
|
||||
if (fgetc(file) == EOF) {
|
||||
error(
|
||||
"Specified start position is greater than length of file \"%s\"", name.c_str()
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
while (length--) {
|
||||
if (int byte = fgetc(file); byte != EOF) {
|
||||
writeByte(byte);
|
||||
// LCOV_EXCL_START
|
||||
} else if (ferror(file)) {
|
||||
error("Error reading `INCBIN` file \"%s\": %s", name.c_str(), strerror(errno));
|
||||
} else {
|
||||
error(
|
||||
"Premature end of `INCBIN` file \"%s\" (%" PRId32 " bytes left to read)",
|
||||
name.c_str(),
|
||||
length + 1
|
||||
);
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void sect_PushSection() {
|
||||
sectionStack.push_front({
|
||||
.section = currentSection,
|
||||
|
||||
+19
-2
@@ -381,6 +381,24 @@ static void
|
||||
if (options.padValue == UNSPECIFIED) {
|
||||
rom0Len = headerSize;
|
||||
}
|
||||
} else if (output != STDOUT_FILENO) {
|
||||
// Truncate a pre-existing output file before writing to it
|
||||
if (ftruncate(output, 0) != 0) {
|
||||
// LCOV_EXCL_START
|
||||
int errnum = errno;
|
||||
if (errnum == EINVAL) {
|
||||
// We do not support FIFOs or symlinks
|
||||
if (struct stat stat; fstat(output, &stat) == 0 && !S_ISREG(stat.st_mode)) {
|
||||
error(
|
||||
"\"%s\" is not a regular file, and thus cannot be modified in-place", name
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
error("Failed to truncate \"%s\": %s", name, strerror(errnum));
|
||||
return;
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
}
|
||||
writeLen = writeBytes(output, rom0, rom0Len);
|
||||
|
||||
@@ -498,8 +516,7 @@ bool fix_ProcessFile(char const *name, char const *outputName) {
|
||||
error("Failed to open \"%s\" for reading+writing: %s", name, strerror(errno));
|
||||
} else {
|
||||
Defer closeInput{[&] { xclose(input); }};
|
||||
struct stat stat;
|
||||
if (fstat(input, &stat) == -1) {
|
||||
if (struct stat stat; fstat(input, &stat) == -1) {
|
||||
error("Failed to stat \"%s\": %s", name, strerror(errno)); // LCOV_EXCL_LINE
|
||||
} else if (!S_ISREG(stat.st_mode)) { // We do not support FIFOs or symlinks
|
||||
// LCOV_EXCL_START
|
||||
|
||||
+1
-10
@@ -5,7 +5,6 @@
|
||||
#include "gfx/main.hpp"
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <ios>
|
||||
#include <optional>
|
||||
#include <png.h>
|
||||
#include <stdarg.h>
|
||||
@@ -19,7 +18,6 @@
|
||||
|
||||
#include "cli.hpp"
|
||||
#include "diagnostics.hpp"
|
||||
#include "file.hpp"
|
||||
#include "helpers.hpp"
|
||||
#include "style.hpp" // style_Parse
|
||||
#include "usage.hpp"
|
||||
@@ -681,14 +679,7 @@ int main(int argc, char *argv[]) {
|
||||
bool useInputImage = !options.input.empty() && !localOptions.reverse;
|
||||
Png png;
|
||||
if (useInputImage) {
|
||||
if (File image;
|
||||
image.open(options.input, std::ios_base::in | std::ios_base::binary) == nullptr) {
|
||||
fatal(
|
||||
"Failed to open PNG image (\"%s\"): %s", image.c_str(options.input), strerror(errno)
|
||||
);
|
||||
} else {
|
||||
png = Png(image.c_str(options.input), *image);
|
||||
}
|
||||
png = Png(options.input);
|
||||
}
|
||||
|
||||
// Execute deferred pal spec parsing, now that all other params are known.
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "diagnostics.hpp"
|
||||
#include "file.hpp"
|
||||
#include "helpers.hpp"
|
||||
#include "verbosity.hpp"
|
||||
|
||||
@@ -61,7 +62,19 @@ static void readData(png_structp png, png_bytep data, size_t length) {
|
||||
}
|
||||
}
|
||||
|
||||
Png::Png(std::string const &path) {
|
||||
if (File image; image.open(path, std::ios_base::in | std::ios_base::binary) == nullptr) {
|
||||
fatal("Failed to open PNG image (\"%s\"): %s", image.display_name(path), strerror(errno));
|
||||
} else {
|
||||
initialize(image.display_name(path), *image);
|
||||
}
|
||||
}
|
||||
|
||||
Png::Png(char const *filename, std::streambuf &file) {
|
||||
initialize(filename, file);
|
||||
}
|
||||
|
||||
void Png::initialize(char const *filename, std::streambuf &file) {
|
||||
Input input(filename, file);
|
||||
|
||||
verbosePrint(VERB_NOTICE, "Reading PNG file \"%s\"\n", input.filename);
|
||||
|
||||
+11
-7
@@ -491,7 +491,11 @@ static void outputPalettes(std::vector<Palette> const &palettes) {
|
||||
File output;
|
||||
if (!output.open(options.palettes, std::ios_base::out | std::ios_base::binary)) {
|
||||
// LCOV_EXCL_START
|
||||
fatal("Failed to create \"%s\": %s", output.c_str(options.palettes), strerror(errno));
|
||||
fatal(
|
||||
"Failed to create \"%s\": %s",
|
||||
output.display_name(options.palettes),
|
||||
strerror(errno)
|
||||
);
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
@@ -646,7 +650,7 @@ static void outputUnoptimizedTileData(
|
||||
File output;
|
||||
if (!output.open(options.output, std::ios_base::out | std::ios_base::binary)) {
|
||||
// LCOV_EXCL_START
|
||||
fatal("Failed to create \"%s\": %s", output.c_str(options.output), strerror(errno));
|
||||
fatal("Failed to create \"%s\": %s", output.display_name(options.output), strerror(errno));
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
@@ -699,7 +703,7 @@ static void outputUnoptimizedMaps(
|
||||
file.emplace();
|
||||
if (!file->open(path, std::ios_base::out | std::ios_base::binary)) {
|
||||
// LCOV_EXCL_START
|
||||
fatal("Failed to create \"%s\": %s", file->c_str(path), strerror(errno));
|
||||
fatal("Failed to create \"%s\": %s", file->display_name(path), strerror(errno));
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
}
|
||||
@@ -873,7 +877,7 @@ static void outputTileData(UniqueTiles const &tiles) {
|
||||
File output;
|
||||
if (!output.open(options.output, std::ios_base::out | std::ios_base::binary)) {
|
||||
// LCOV_EXCL_START
|
||||
fatal("Failed to create \"%s\": %s", output.c_str(options.output), strerror(errno));
|
||||
fatal("Failed to create \"%s\": %s", output.display_name(options.output), strerror(errno));
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
@@ -913,7 +917,7 @@ static void outputTilemap(std::vector<AttrmapEntry> const &attrmap) {
|
||||
File output;
|
||||
if (!output.open(options.tilemap, std::ios_base::out | std::ios_base::binary)) {
|
||||
// LCOV_EXCL_START
|
||||
fatal("Failed to create \"%s\": %s", output.c_str(options.tilemap), strerror(errno));
|
||||
fatal("Failed to create \"%s\": %s", output.display_name(options.tilemap), strerror(errno));
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
@@ -929,7 +933,7 @@ static void
|
||||
File output;
|
||||
if (!output.open(options.attrmap, std::ios_base::out | std::ios_base::binary)) {
|
||||
// LCOV_EXCL_START
|
||||
fatal("Failed to create \"%s\": %s", output.c_str(options.attrmap), strerror(errno));
|
||||
fatal("Failed to create \"%s\": %s", output.display_name(options.attrmap), strerror(errno));
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
@@ -950,7 +954,7 @@ static void
|
||||
File output;
|
||||
if (!output.open(options.palmap, std::ios_base::out | std::ios_base::binary)) {
|
||||
// LCOV_EXCL_START
|
||||
fatal("Failed to create \"%s\": %s", output.c_str(options.palmap), strerror(errno));
|
||||
fatal("Failed to create \"%s\": %s", output.display_name(options.palmap), strerror(errno));
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
|
||||
+15
-19
@@ -31,7 +31,7 @@
|
||||
static std::vector<uint8_t> readInto(std::string const &path) {
|
||||
File file;
|
||||
if (!file.open(path, std::ios::in | std::ios::binary)) {
|
||||
fatal("Failed to open \"%s\": %s", file.c_str(path), strerror(errno));
|
||||
fatal("Failed to open \"%s\": %s", file.display_name(path), strerror(errno));
|
||||
}
|
||||
std::vector<uint8_t> data(128 * 16); // Begin with some room pre-allocated
|
||||
|
||||
@@ -87,7 +87,7 @@ static void flushPng(png_structp png) {
|
||||
}
|
||||
|
||||
static void printColor(std::optional<Rgba> const &color) {
|
||||
if (color) {
|
||||
if (color.has_value()) {
|
||||
fprintf(stderr, "#%08x", color->toCSS());
|
||||
} else {
|
||||
fputs("<none> ", stderr);
|
||||
@@ -207,7 +207,9 @@ void reverse() {
|
||||
if (!options.palettes.empty()) {
|
||||
File file;
|
||||
if (!file.open(options.palettes, std::ios::in | std::ios::binary)) {
|
||||
fatal("Failed to open \"%s\": %s", file.c_str(options.palettes), strerror(errno));
|
||||
fatal(
|
||||
"Failed to open \"%s\": %s", file.display_name(options.palettes), strerror(errno)
|
||||
);
|
||||
}
|
||||
|
||||
palettes.clear();
|
||||
@@ -478,12 +480,12 @@ void reverse() {
|
||||
File pngFile;
|
||||
if (!pngFile.open(options.input, std::ios::out | std::ios::binary)) {
|
||||
// LCOV_EXCL_START
|
||||
fatal("Failed to create \"%s\": %s", pngFile.c_str(options.input), strerror(errno));
|
||||
fatal("Failed to create \"%s\": %s", pngFile.display_name(options.input), strerror(errno));
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
png_structp png = png_create_write_struct(
|
||||
PNG_LIBPNG_VER_STRING,
|
||||
const_cast<char *>(pngFile.c_str(options.input)),
|
||||
const_cast<char *>(pngFile.display_name(options.input)),
|
||||
pngError,
|
||||
pngWarning
|
||||
);
|
||||
@@ -533,22 +535,16 @@ void reverse() {
|
||||
png_color pngPalette[4] = {};
|
||||
png_byte pngTrans[4] = {};
|
||||
int nbPngColors = 0, nbPngTrans = 0;
|
||||
for (auto const &color : palettes[0]) {
|
||||
if (color.has_value()) {
|
||||
pngPalette[nbPngColors].red = color->red;
|
||||
pngPalette[nbPngColors].green = color->green;
|
||||
pngPalette[nbPngColors].blue = color->blue;
|
||||
pngTrans[nbPngColors] = color->alpha;
|
||||
if (color->alpha < 255) {
|
||||
for (auto const &slot : palettes[0]) {
|
||||
Rgba color = slot.has_value() ? *slot : Rgba(255, 255, 255, 255);
|
||||
pngPalette[nbPngColors].red = color.red;
|
||||
pngPalette[nbPngColors].green = color.green;
|
||||
pngPalette[nbPngColors].blue = color.blue;
|
||||
pngTrans[nbPngColors] = color.alpha;
|
||||
++nbPngColors;
|
||||
if (color.alpha < 255) {
|
||||
nbPngTrans = nbPngColors;
|
||||
}
|
||||
} else {
|
||||
pngPalette[nbPngColors].red = 255;
|
||||
pngPalette[nbPngColors].green = 255;
|
||||
pngPalette[nbPngColors].blue = 255;
|
||||
pngTrans[nbPngColors] = 255;
|
||||
}
|
||||
++nbPngColors;
|
||||
}
|
||||
png_set_PLTE(png, pngInfo, pngPalette, nbPngColors);
|
||||
if (nbPngTrans > 0) {
|
||||
|
||||
@@ -13,12 +13,10 @@ MACRO test_mod
|
||||
def x = \1 ; dividend
|
||||
def y = \2 ; divisor
|
||||
shift 2
|
||||
def q = x / y ; quotient
|
||||
def r = x % y ; remainder
|
||||
; identity laws
|
||||
test (V (q * y + r)) == (V x)
|
||||
test (V (x + y) % y) == (V r)
|
||||
test (V (x - y) % y) == (V r)
|
||||
test (V x) / y * y + (V x) % y == (V x)
|
||||
test (V (x + y)) % y == (V x) % y
|
||||
test (V (x - y)) % y == (V x) % y
|
||||
ENDM
|
||||
|
||||
MACRO test_each_mod
|
||||
|
||||
+53
-14
@@ -35,6 +35,13 @@ rescolors="$(tput op)"
|
||||
|
||||
RGBFIX="$src/../../rgbfix"
|
||||
|
||||
startTest () {
|
||||
(( tests++ ))
|
||||
if [[ $progress -ne 0 ]]; then
|
||||
echo "${bold}${green}$1...${rescolors}${resbold}"
|
||||
fi
|
||||
}
|
||||
|
||||
tryDiff () {
|
||||
if ! diff -au --strip-trailing-cr "$1" "$2"; then
|
||||
echo "${bold}${red}${3:-$1} mismatch!${rescolors}${resbold}"
|
||||
@@ -44,7 +51,7 @@ tryDiff () {
|
||||
|
||||
tryCmp () {
|
||||
if ! cmp "$1" "$2"; then
|
||||
"$src/../../gbdiff.bash" "$1" "$2"
|
||||
"$src/../../contrib/gbdiff.bash" "$1" "$2" | head
|
||||
echo "${bold}${red}${3:-$1} mismatch!${rescolors}${resbold}"
|
||||
false
|
||||
fi
|
||||
@@ -61,11 +68,7 @@ runTest () {
|
||||
fi
|
||||
|
||||
for variant in '' ' piped' ' output'; do
|
||||
(( tests++ ))
|
||||
our_rc=0
|
||||
if [[ $progress -ne 0 ]]; then
|
||||
echo "${bold}${green}$1${variant}...${rescolors}${resbold}"
|
||||
fi
|
||||
startTest "$1${variant}"
|
||||
if [[ -r "$2/$1.bin" ]]; then
|
||||
desired_input="$2/$1.bin"
|
||||
else
|
||||
@@ -96,7 +99,7 @@ runTest () {
|
||||
desired_errname=/dev/null
|
||||
fi
|
||||
sed -e "s/$subst/<filename>/g" -e "s#$src_subst##g" out.out | tryDiff "$desired_outname" - "$1.out${variant}"
|
||||
(( our_rc = our_rc || $? ))
|
||||
our_rc=$?
|
||||
sed -e "s/$subst/<filename>/g" -e "s#$src_subst##g" out.err | tryDiff "$desired_errname" - "$1.err${variant}"
|
||||
(( our_rc = our_rc || $? ))
|
||||
|
||||
@@ -116,11 +119,36 @@ runTest () {
|
||||
runSpecialTest () {
|
||||
name="$1"
|
||||
shift
|
||||
echo "${bold}${green}${name}...${rescolors}${resbold}"
|
||||
startTest "$name"
|
||||
|
||||
eval "$RGBFIX" "$@" -o out.gb '>out.out' '2>out.err'
|
||||
tryDiff out.out /dev/null "${name}.out"
|
||||
our_rc=$?
|
||||
tryDiff out.err /dev/null "${name}.err"
|
||||
(( our_rc = our_rc || $? ))
|
||||
tryCmp input.gb out.gb "${name}.gb"
|
||||
(( our_rc = our_rc || $? ))
|
||||
|
||||
(( rc = rc || our_rc ))
|
||||
if [[ $our_rc -ne 0 ]]; then
|
||||
(( failed++ ))
|
||||
fi
|
||||
}
|
||||
|
||||
runTestExpectingFailure () {
|
||||
name="$1"
|
||||
shift
|
||||
startTest "$name"
|
||||
|
||||
eval "$RGBFIX" "$@" '2>out.err'
|
||||
rc=$((rc || $? != 1))
|
||||
our_rc=$(($? != 1))
|
||||
tryDiff "$src/${name}.err" out.err "${name}.err"
|
||||
rc=$((rc || $?))
|
||||
our_rc=$((our_rc || $?))
|
||||
|
||||
rc=$((rc || our_rc))
|
||||
if [[ $our_rc -ne 0 ]]; then
|
||||
(( failed++ ))
|
||||
fi
|
||||
}
|
||||
|
||||
rm -f padding*_* # Delete padding test cases generated but not deleted (e.g. interrupted)
|
||||
@@ -130,14 +158,24 @@ for i in "$src"/*.flags; do
|
||||
runTest "$(basename "$i" .flags)" "$src"
|
||||
done
|
||||
|
||||
# Check that RGBFIX truncates a pre-existing output file
|
||||
dd if=/dev/zero of=input.gb bs=1 count=336 >/dev/null 2>&1
|
||||
dd if=/dev/zero of=out.gb bs=1 count=16384 >/dev/null 2>&1
|
||||
runSpecialTest pre-existing-output input.gb
|
||||
|
||||
# Check that RGBFIX handles an output file identical to the input file
|
||||
dd if=/dev/zero of=input.gb bs=1 count=336 >/dev/null 2>&1
|
||||
cp input.gb out.gb
|
||||
runSpecialTest equivalent-output out.gb
|
||||
|
||||
# Check that RGBFIX errors out when inputting a non-existent file
|
||||
runSpecialTest no-exist no-exist
|
||||
runTestExpectingFailure no-exist no-exist
|
||||
|
||||
# Check that RGBFIX errors out when not inputting any file
|
||||
runSpecialTest no-input
|
||||
runTestExpectingFailure no-input
|
||||
|
||||
# Check that RGBFIX errors out when inputting multiple files with an output file
|
||||
runSpecialTest multiple-to-one one two three -o multiple-to-one
|
||||
runTestExpectingFailure multiple-to-one one two three -o multiple-to-one
|
||||
|
||||
# Check the result with all different padding bytes
|
||||
echo "${bold}Checking padding...${resbold}"
|
||||
@@ -149,7 +187,8 @@ for (( i=0; i < 10; ++i )); do
|
||||
echo "$padding..."
|
||||
for suffix in '' -large -larger; do
|
||||
cat <<<"-p $padding" >padding$suffix.flags
|
||||
tr '\377' \\$((padding / 64))$(((padding / 8) % 8))$((padding % 8)) <"$src/padding$suffix.gb" >padding$suffix.gb # OK because $FF bytes are only used for padding
|
||||
# `tr`ing &377 aka $FF is OK because $FF bytes are only used for padding
|
||||
tr '\377' \\$((padding / 64))$(((padding / 8) % 8))$((padding % 8)) <"$src/padding$suffix.gb" >padding$suffix.gb
|
||||
runTest padding${suffix} .
|
||||
done
|
||||
done
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
-C
|
||||
-m
|
||||
-t reverse_curve.tilemap
|
||||
-a reverse_curve.attrmap
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
? @L������円G|C<#
|
||||
Binary file not shown.
@@ -0,0 +1,4 @@
|
||||
-m
|
||||
-t reverse_no_curve.tilemap
|
||||
-a reverse_no_curve.attrmap
|
||||
-p reverse_no_curve.pal
|
||||
Binary file not shown.
Binary file not shown.
@@ -466,7 +466,7 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
auto cgbColor = [](Rgba const &rgba) {
|
||||
auto field = [](uint16_t component, uint8_t shift) {
|
||||
return (component & 0x1F) << shift;
|
||||
return (component >> 3) << shift;
|
||||
};
|
||||
return rgba.isTransparent()
|
||||
? Rgba::transparent
|
||||
|
||||
+11
-5
@@ -89,20 +89,26 @@ for f in *.png; do
|
||||
done
|
||||
|
||||
newTest "$RGBGFX" $flags "$f"
|
||||
test_rc=0
|
||||
if [[ -e "${f%.png}.err" ]]; then
|
||||
runTest 2>"$errtmp"
|
||||
diff -au --strip-trailing-cr "${f%.png}.err" "$errtmp" || failTest
|
||||
diff -au --strip-trailing-cr "${f%.png}.err" "$errtmp" || test_rc=$?
|
||||
else
|
||||
runTest && checkOutput "${f%.png}" || failTest $?
|
||||
runTest || test_rc=$?
|
||||
fi
|
||||
checkOutput "${f%.png}" || test_rc=$?
|
||||
(( test_rc )) && failTest $test_rc
|
||||
|
||||
newTest "$RGBGFX" $flags - "<$f"
|
||||
test_rc=0
|
||||
if [[ -e "${f%.png}.err" ]]; then
|
||||
runTest 2>"$errtmp"
|
||||
diff -au --strip-trailing-cr "${f%.png}.err" <(sed "s#<stdin>#${f//#/\\#}#g" "$errtmp") || failTest
|
||||
diff -au --strip-trailing-cr "${f%.png}.err" <(sed "s#<stdin>#${f//#/\\#}#g" "$errtmp") || test_rc=$?
|
||||
else
|
||||
runTest && checkOutput "${f%.png}" || failTest $?
|
||||
runTest || test_rc=$?
|
||||
fi
|
||||
checkOutput "${f%.png}" || test_rc=$?
|
||||
(( test_rc )) && failTest $test_rc
|
||||
done
|
||||
|
||||
for f in *.[12]bpp; do
|
||||
@@ -122,7 +128,7 @@ for f in *.[12]bpp; do
|
||||
if [[ -e "${f%.[12]bpp}.err" ]]; then
|
||||
newTest "$RGBGFX $flags -o $f -r 1 result.png"
|
||||
runTest 2>"$errtmp"
|
||||
diff -au --strip-trailing-cr "${f%.[12]bpp}.err" <(sed "s#<stdin>#${f//#/\\#}#g" "$errtmp") || failTest
|
||||
diff -au --strip-trailing-cr "${f%.[12]bpp}.err" <(sed "s#<stdin>#${f//#/\\#}#g" "$errtmp") || failTest $?
|
||||
else
|
||||
newTest "$RGBGFX $flags -o $f -r 1 result.png && $RGBGFX $flags -o result.2bpp result.png"
|
||||
runTest && tryCmp "$f" result.2bpp || failTest $?
|
||||
|
||||
+45
-20
@@ -14,9 +14,10 @@ gbtemp2="$(mktemp)"
|
||||
outtemp="$(mktemp)"
|
||||
outtemp2="$(mktemp)"
|
||||
outtemp3="$(mktemp)"
|
||||
errtemp="$(mktemp)"
|
||||
|
||||
# shellcheck disable=SC2064 # (Immediate expansion is the desired behavior.)
|
||||
trap "rm -f ${otemp@Q} ${gbtemp@Q} ${gbtemp2@Q} ${outtemp@Q} ${outtemp2@Q} ${outtemp3@Q}" EXIT
|
||||
trap "rm -f ${otemp@Q} ${gbtemp@Q} ${gbtemp2@Q} ${outtemp@Q} ${outtemp2@Q} ${outtemp3@Q} ${errtemp@Q}" EXIT
|
||||
|
||||
tests=0
|
||||
failed=0
|
||||
@@ -92,31 +93,39 @@ for i in *.asm; do
|
||||
continue
|
||||
fi
|
||||
|
||||
|
||||
RGBLINKFLAGS=()
|
||||
if [ -f "${test}.flags" ]; then
|
||||
RGBLINKFLAGS+=("@${test}.flags")
|
||||
fi
|
||||
|
||||
ran_test=false
|
||||
|
||||
# Some tests have variants depending on flags
|
||||
ran_flag=false
|
||||
for flag in '-d' '-t' '-w'; do
|
||||
if [ -f "${test}-no${flag}.out" ]; then
|
||||
continueTest "-no${flag}"
|
||||
rgblinkQuiet "${RGBLINKFLAGS[@]}" -o "$gbtemp" "$otemp" 2>"$outtemp"
|
||||
tryDiff "${test}-no${flag}.out" "$outtemp"
|
||||
bin=${test}-no${flag}.out.bin
|
||||
if [ -f "$bin" ]; then
|
||||
tryCmpRom "$bin"
|
||||
fi
|
||||
evaluateTest
|
||||
ran_flag=true
|
||||
ran_test=true
|
||||
fi
|
||||
if [ -f "${test}${flag}.out" ]; then
|
||||
continueTest "$flag"
|
||||
rgblinkQuiet "${RGBLINKFLAGS[@]}" ${flag} -o "$gbtemp" "$otemp" 2>"$outtemp"
|
||||
tryDiff "${test}${flag}.out" "$outtemp"
|
||||
bin=${test}${flag}.out.bin
|
||||
if [ -f "$bin" ]; then
|
||||
tryCmpRom "$bin"
|
||||
fi
|
||||
evaluateTest
|
||||
ran_flag=true
|
||||
ran_test=true
|
||||
fi
|
||||
done
|
||||
if "$ran_flag"; then
|
||||
if "$ran_test"; then
|
||||
continue
|
||||
fi
|
||||
|
||||
@@ -127,10 +136,14 @@ for i in *.asm; do
|
||||
continueTest "${script#${test}}"
|
||||
rgblinkQuiet "${RGBLINKFLAGS[@]}" -l "$script" -o "$gbtemp" "$otemp" 2>"$outtemp"
|
||||
tryDiff "${script%.link}.out" "$outtemp"
|
||||
bin=${script%.link}.out.bin
|
||||
if [ -f "$bin" ]; then
|
||||
tryCmpRom "$bin"
|
||||
fi
|
||||
evaluateTest
|
||||
ran_flag=true
|
||||
ran_test=true
|
||||
done
|
||||
if "$ran_flag"; then
|
||||
if "$ran_test"; then
|
||||
continue
|
||||
fi
|
||||
|
||||
@@ -195,7 +208,8 @@ test="fragment-literals"
|
||||
startTest
|
||||
"$RGBASM" -o "$otemp" "$test"/a.asm
|
||||
continueTest
|
||||
rgblinkQuiet -o "$gbtemp" -m "$outtemp" -n "$outtemp2" "$otemp"
|
||||
rgblinkQuiet -o "$gbtemp" -m "$outtemp" -n "$outtemp2" "$otemp" 2>"$errtemp"
|
||||
tryDiff /dev/null "$errtemp"
|
||||
tryCmpRom "$test"/ref.out.bin
|
||||
tryDiff "$test"/ref.out.map "$outtemp"
|
||||
tryDiff "$test"/ref.out.sym "$outtemp2"
|
||||
@@ -206,7 +220,8 @@ startTest
|
||||
"$RGBASM" -o "$otemp" "$test"/a.asm
|
||||
"$RGBASM" -o "$outtemp" "$test"/b.asm
|
||||
continueTest
|
||||
rgblinkQuiet -o "$gbtemp" -n "$outtemp2" "$otemp" "$outtemp"
|
||||
rgblinkQuiet -o "$gbtemp" -n "$outtemp2" "$otemp" "$outtemp" 2>"$errtemp"
|
||||
tryDiff /dev/null "$errtemp"
|
||||
tryCmpRom "$test"/ref.out.bin
|
||||
tryDiff "$test"/ref.out.sym "$outtemp2"
|
||||
evaluateTest
|
||||
@@ -227,8 +242,10 @@ startTest
|
||||
"$RGBASM" -o "$otemp" "$test"/a.asm
|
||||
"$RGBASM" -o "$outtemp" "$test"/b.asm
|
||||
continueTest
|
||||
rgblinkQuiet -o "$gbtemp" "$otemp"
|
||||
rgblinkQuiet -o "$gbtemp2" "$outtemp"
|
||||
rgblinkQuiet -o "$gbtemp" "$otemp" 2>"$errtemp"
|
||||
tryDiff /dev/null "$errtemp"
|
||||
rgblinkQuiet -o "$gbtemp2" "$outtemp" 2>"$errtemp"
|
||||
tryDiff /dev/null "$errtemp"
|
||||
tryCmp "$gbtemp" "$gbtemp2"
|
||||
evaluateTest
|
||||
|
||||
@@ -236,7 +253,8 @@ test="load-fragment/base"
|
||||
startTest
|
||||
"$RGBASM" -o "$otemp" "$test"/a.asm
|
||||
continueTest
|
||||
rgblinkQuiet -o "$gbtemp" -n "$outtemp" "$otemp"
|
||||
rgblinkQuiet -o "$gbtemp" -n "$outtemp" "$otemp" 2>"$errtemp"
|
||||
tryDiff /dev/null "$errtemp"
|
||||
tryCmpRom "$test"/ref.out.bin
|
||||
tryDiff "$test"/ref.out.sym "$outtemp"
|
||||
evaluateTest
|
||||
@@ -246,7 +264,8 @@ startTest
|
||||
"$RGBASM" -o "$otemp" "$test"/a.asm
|
||||
"$RGBASM" -o "$gbtemp2" "$test"/b.asm
|
||||
continueTest
|
||||
rgblinkQuiet -o "$gbtemp" "$otemp" "$gbtemp2"
|
||||
rgblinkQuiet -o "$gbtemp" "$otemp" "$gbtemp2" 2>"$errtemp"
|
||||
tryDiff /dev/null "$errtemp"
|
||||
tryCmpRom "$test"/ref.out.bin
|
||||
evaluateTest
|
||||
|
||||
@@ -256,7 +275,8 @@ startTest
|
||||
"$RGBASM" -o "$outtemp" "$test"/b.asm
|
||||
"$RGBASM" -o "$outtemp2" "$test"/c.asm
|
||||
continueTest
|
||||
rgblinkQuiet -o "$gbtemp" -m "$outtemp3" -n "$gbtemp2" "$otemp" "$outtemp" "$outtemp2"
|
||||
rgblinkQuiet -o "$gbtemp" -m "$outtemp3" -n "$gbtemp2" "$otemp" "$outtemp" "$outtemp2" 2>"$errtemp"
|
||||
tryDiff /dev/null "$errtemp"
|
||||
tryCmpRom "$test"/ref.out.bin
|
||||
tryDiff "$test"/ref.out.map "$outtemp3"
|
||||
tryDiff "$test"/ref.out.sym "$gbtemp2"
|
||||
@@ -387,7 +407,8 @@ startTest
|
||||
"$RGBASM" -o "$otemp" "$test"/a.asm
|
||||
"$RGBASM" -o "$gbtemp2" "$test"/b.asm
|
||||
continueTest
|
||||
rgblinkQuiet -o "$gbtemp" "$otemp" "$gbtemp2"
|
||||
rgblinkQuiet -o "$gbtemp" "$otemp" "$gbtemp2" 2>"$errtemp"
|
||||
tryDiff /dev/null "$errtemp"
|
||||
tryCmpRom "$test"/ref.out.bin
|
||||
evaluateTest
|
||||
|
||||
@@ -404,7 +425,8 @@ startTest
|
||||
"$RGBASM" -o "$otemp" "$test"/a.asm
|
||||
"$RGBASM" -o "$gbtemp2" "$test"/b.asm
|
||||
continueTest
|
||||
rgblinkQuiet -o "$gbtemp" "$otemp" "$gbtemp2"
|
||||
rgblinkQuiet -o "$gbtemp" "$otemp" "$gbtemp2" 2>"$errtemp"
|
||||
tryDiff /dev/null "$errtemp"
|
||||
tryCmpRom "$test"/ref.out.bin
|
||||
evaluateTest
|
||||
|
||||
@@ -413,7 +435,8 @@ startTest
|
||||
"$RGBASM" -o "$otemp" "$test"/a.asm
|
||||
"$RGBASM" -o "$gbtemp2" "$test"/b.asm
|
||||
continueTest
|
||||
rgblinkQuiet -o "$gbtemp" "$otemp" "$gbtemp2"
|
||||
rgblinkQuiet -o "$gbtemp" "$otemp" "$gbtemp2" 2>"$errtemp"
|
||||
tryDiff /dev/null "$errtemp"
|
||||
tryCmpRom "$test"/ref.out.bin
|
||||
evaluateTest
|
||||
|
||||
@@ -440,7 +463,8 @@ startTest
|
||||
"$RGBASM" -o "$otemp" "$test"/a.asm
|
||||
"$RGBASM" -o "$gbtemp2" "$test"/b.asm
|
||||
continueTest
|
||||
rgblinkQuiet -o "$gbtemp" -l "$test"/script.link "$otemp" "$gbtemp2"
|
||||
rgblinkQuiet -o "$gbtemp" -l "$test"/script.link "$otemp" "$gbtemp2" 2>"$errtemp"
|
||||
tryDiff /dev/null "$errtemp"
|
||||
tryCmpRom "$test"/ref.out.bin
|
||||
evaluateTest
|
||||
|
||||
@@ -449,7 +473,8 @@ startTest
|
||||
"$RGBASM" -o "$otemp" "$test"/a.asm
|
||||
"$RGBASM" -o "$gbtemp2" "$test"/b.asm
|
||||
continueTest
|
||||
rgblinkQuiet -o "$gbtemp" -l "$test"/script.link "$otemp" "$gbtemp2"
|
||||
rgblinkQuiet -o "$gbtemp" -l "$test"/script.link "$otemp" "$gbtemp2" 2>"$errtemp"
|
||||
tryDiff /dev/null "$errtemp"
|
||||
tryCmpRom "$test"/ref.out.bin
|
||||
evaluateTest
|
||||
|
||||
|
||||
+3
-25
@@ -18,8 +18,6 @@ Options:
|
||||
--only-free skip tests that build nonfree codebases
|
||||
--jobs <n> build external codebases with `make -j<n>`
|
||||
--os <os> skip tests known to fail on <os> (e.g. `macos-14`)
|
||||
--installed-rgbds use the system installed RGBDS
|
||||
(only compatible with external codebases)
|
||||
EOF
|
||||
}
|
||||
|
||||
@@ -28,8 +26,7 @@ EOF
|
||||
nonfree=true
|
||||
internal=true
|
||||
external=true
|
||||
installedrgbds=false
|
||||
make_jobs=
|
||||
make_args=()
|
||||
osname=
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
@@ -46,12 +43,9 @@ while [[ $# -gt 0 ]]; do
|
||||
--only-free)
|
||||
nonfree=false
|
||||
;;
|
||||
--installed-rgbds)
|
||||
installedrgbds=true
|
||||
;;
|
||||
--jobs)
|
||||
shift
|
||||
make_jobs="-j$1"
|
||||
make_args+=(-j "$1")
|
||||
;;
|
||||
--os)
|
||||
shift
|
||||
@@ -73,27 +67,11 @@ if ! "$internal" && ! "$external"; then
|
||||
false
|
||||
fi
|
||||
|
||||
if "$internal" && "$installedrgbds"; then
|
||||
echo "Please specify --only-external with --installed-rgbds"
|
||||
echo "(internal tests don't support running with system-installed RGBDS)"
|
||||
false
|
||||
fi
|
||||
|
||||
# Refuse to run if RGBDS isn't available
|
||||
if "$installedrgbds"; then
|
||||
is_installed() {
|
||||
command -v "$1" >/dev/null 2>&1
|
||||
}
|
||||
if ! (is_installed rgbasm && is_installed rgblink && is_installed rgbfix && is_installed rgbgfx); then
|
||||
echo "Please install RGBDS before running the tests"
|
||||
false
|
||||
fi
|
||||
else
|
||||
if [[ ! ( -x ../rgbasm && -x ../rgblink && -x ../rgbfix && -x ../rgbgfx ) ]]; then
|
||||
echo "Please build RGBDS before running the tests"
|
||||
false
|
||||
fi
|
||||
fi
|
||||
|
||||
# Tests included with the repository
|
||||
if "$internal"; then
|
||||
@@ -128,6 +106,6 @@ for cfg in *.cfg; do (
|
||||
|
||||
# Run nonfree tests only if they are opted into.
|
||||
if ! "$EXT_TEST_IS_NONFREE" || "$nonfree"; then
|
||||
./test.sh "$test_name" "$make_jobs"
|
||||
./test.sh "$test_name" "${make_args[@]}"
|
||||
fi
|
||||
); done
|
||||
Reference in new issue
Block a user