Compare commits

..

32 Commits

Author SHA1 Message Date
Rangi
69a573923f Version 0.6.1 2022-12-02 22:48:37 -05:00
ISSOtm
7eb4ecea8b Remove use of std::filesystem
This appears to break compatibility with macOS 10.9
2022-12-03 01:51:14 +01:00
ISSOtm
599ce757a1 Force Windows builds to use our zlib and libpng
Otherwise we will have a few problems if, say, a system version was
detected and picked up instead of ours...
2022-12-03 00:58:50 +01:00
ISSOtm
75a07a90f8 Always initialise section->data to avoid an uninit read
The addition of SDCC objects required a change in the logic of
`mergeSections()` to dispatch based on `->data` instead of
`sect_HasData`, which implicitly assumes that `->data` is
always initialised (maybe NULL).
However, RGBDS sections did not do that!
2022-12-02 22:39:31 +01:00
ISSOtm
ec2d1312ef Remove auto parameter to -flto
Not all supported compilers support the argument;
the move was a bit premature.
2022-11-15 19:49:04 +01:00
ISSOtm
03b6dd9321 Only cache dependency directories instead of whole test/
Otherwise, changes made to the test suite are not picked up
2022-11-15 19:49:04 +01:00
ISSOtm
a16d3d6405 Fail RGBGFX test suite if support test programs fail to be built 2022-11-15 19:49:04 +01:00
ISSOtm
3e5cd8ce1a Use a special name for stdin/stdout in diagnostics 2022-11-15 19:49:04 +01:00
ISSOtm
6902387991 Allow rgbgfx - for stdin and stdout
Closes #1087
2022-11-15 19:49:04 +01:00
ISSOtm
62b4f2b264 Upgrade to checkout action v3
No code changes, just uses Node 16 instead of the
deprecated Node 12
2022-11-13 14:33:03 +01:00
Rangi
79748afdc4 Align the "; Next union/fragment" comments with their symbols 2022-11-06 23:55:15 +01:00
Rangi
32cb0558e4 Print "; Next union/fragment" between "pieces" in .map file
Resolves #1099
2022-11-06 23:55:15 +01:00
rlewicki
92b2ac3c8c Remove duplicated EMPTY label in case no bank memory is used 2022-11-03 19:54:21 +01:00
rlewicki
0e67298dff Fix indention when writing EMPTY label inside link output.c file 2022-11-03 19:54:21 +01:00
Robert Lewicki
f6d218ed36 Fix regression tests failing due to invalid cache being restored (#1104) 2022-11-01 14:27:40 +01:00
Robert Lewicki
1a9fc964df #1082 Add cache check for external repositories used during testing (#1100)
Co-authored-by: Rangi <35663410+Rangi42@users.noreply.github.com>
Co-authored-by: Eldred Habert <eldredhabert0@gmail.com>
2022-10-25 08:39:19 +02:00
ISSOtm
48248faab0 Suppress CMake project maintainer warnings in CI 2022-10-16 12:21:54 +02:00
ISSOtm
58181c2d73 Hoist common Windows dep grabbing code to a script
Function courtesy of @aaaaaa123456789
2022-10-16 12:21:54 +02:00
ISSOtm
0f86084e08 Rename actions folder as scripts
It's clearer this way.
2022-10-16 12:21:54 +02:00
ISSOtm
c8e602dec1 Mangle the name of absolute sections
They are unlikely to be unique across files, actually
2022-10-15 23:16:04 +02:00
ISSOtm
b168717e91 Update zlib to 1.2.13
1.2.12 is no longer provided by upstream anymore,
which fails Windows CI
2022-10-15 22:02:34 +02:00
ISSOtm
930c2ac328 Require Bison 3.0.0 in CMakeLists
We actually require that version, so be explicit about it
to provide better error messages.
2022-10-13 11:02:33 +02:00
ISSOtm
28737d5778 Enable GLIBCXX_ASSERTIONS in make develop
Not sure it's very portable, but this is only the dev config
2022-10-12 01:23:37 +02:00
ISSOtm
12ba057b4f Check that colour slot is non-empty before checking for gray-ness
This is otherwise UB, and trips a GLIBCXX assertion (when enabled).
2022-10-11 21:39:32 +02:00
ISSOtm
0e0876b17f Print addr ranges for empty blocks as well
Mirrors what sections do, for clarity & consistency
2022-10-07 16:04:02 +02:00
Eldred Habert
b28eea24fc Update .github/workflows/create-release-artifacts.yaml
Co-authored-by: Rangi <35663410+Rangi42@users.noreply.github.com>
2022-10-04 12:50:46 -04:00
ISSOtm
a1e59ddc3d Avoid -x c++ affecting ${PNGLDLIBS}
version.c doesn't link to anything from libpng, so it'll be fine
2022-10-04 12:50:46 -04:00
ISSOtm
3fbdba31bf Build macOS binaries as well for releases 2022-10-04 12:50:46 -04:00
ISSOtm
d90a7e4302 Terminate RGBGFX when opening a file fails
`std::filebuf::open`'s result must be checked, though that's not obvious.
2022-10-04 13:58:05 +02:00
ISSOtm
7377a14245 Improve RGBASM's "input files" error messages slightly 2022-10-03 17:17:19 +02:00
Eldred Habert
e2136d60b2 Print a more user-friendly error message for leftover diff marks (#1089) 2022-10-03 16:52:29 +02:00
ISSOtm
74e40654e6 Sync release docs CI workflow with master
We should look into reusable workflows, really.
https://docs.github.com/en/actions/using-workflows/reusing-workflows
2022-10-03 01:50:17 +02:00
28 changed files with 556 additions and 243 deletions

23
.github/scripts/get_win_deps.ps1 vendored Normal file
View File

@@ -0,0 +1,23 @@
function getlibrary ([string] $URI, [string] $filename, [string] $hash, [string] $destdir) {
$wc = New-Object Net.WebClient
[string] $downloadhash = $null
try {
$wc.DownloadFile($URI, $filename)
$downloadhash = $(Get-FileHash $filename -Algorithm SHA256).Hash
} catch {
Write-Host "${filename}: failed to download"
exit 1
}
if ($hash -ne $downloadhash) {
Write-Host "${filename}: SHA256 mismatch ($downloadhash)"
exit 1
}
Expand-Archive -DestinationPath $destdir $filename
}
getlibrary 'https://www.zlib.net/zlib1213.zip' 'zlib.zip' 'd233fca7cf68db4c16dc5287af61f3cd01ab62495224c66639ca3da537701e42' .
getlibrary 'https://download.sourceforge.net/libpng/lpng1637.zip' 'libpng.zip' '3b4b1cbd0bae6822f749d39b1ccadd6297f05e2b85a83dd2ce6ecd7d09eabdf2' .
getlibrary 'https://github.com/lexxmark/winflexbison/releases/download/v2.5.24/win_flex_bison-2.5.24.zip' 'winflexbison.zip' '39c6086ce211d5415500acc5ed2d8939861ca1696aee48909c7f6daf5122b505' install_dir
Move-Item zlib-1.2.13 zlib
Move-Item lpng1637 libpng

6
.github/scripts/install.sh vendored Executable file
View File

@@ -0,0 +1,6 @@
#!/bin/bash
install -d /usr/local/bin/ /usr/local/share/man/man1/ /usr/local/share/man/man5/ /usr/local/share/man/man7/
install -s -m 755 rgbasm rgblink rgbfix rgbgfx /usr/local/bin/
install -m 644 rgbasm.1 rgblink.1 rgbfix.1 rgbgfx.1 /usr/local/share/man/man1/
install -m 644 rgbds.5 rgbasm.5 rgblink.5 /usr/local/share/man/man5/
install -m 644 rgbds.7 gbz80.7 /usr/local/share/man/man7/

View File

@@ -9,7 +9,7 @@ arch="$1"
wget http://downloads.sourceforge.net/project/libpng/libpng16/$pngver/libpng-$pngver.tar.xz wget http://downloads.sourceforge.net/project/libpng/libpng16/$pngver/libpng-$pngver.tar.xz
wget http://downloads.sourceforge.net/project/apng/libpng/libpng16/libpng-$pngver-apng.patch.gz wget http://downloads.sourceforge.net/project/apng/libpng/libpng16/libpng-$pngver-apng.patch.gz
sha256sum -c .github/actions/mingw-w64-libpng-dev.sha256sums sha256sum -c .github/scripts/mingw-w64-libpng-dev.sha256sums
## Extract sources and patch them ## Extract sources and patch them

View File

@@ -7,77 +7,107 @@ on:
jobs: jobs:
windows: windows:
runs-on: windows-2022 runs-on: windows-2022
strategy:
matrix:
bits: [32, 64]
include:
- bits: 32
arch: x86
platform: Win32
- bits: 64
arch: x86_x64
platform: x64
fail-fast: false
steps:
- name: Get version from tag
shell: bash
run: | # Turn "vX.Y.Z" into "X.Y.Z"
VERSION="${{ github.ref_name }}"
echo "version=${VERSION#v}" >> $GITHUB_ENV
- uses: actions/checkout@v3
- name: Install deps
run: .github/scripts/get_win_deps.ps1
- uses: actions/cache@v3
id: cache
with:
path: |
zbuild
pngbuild
key: ${{ matrix.arch }}-${{ hashFiles('zlib/**', 'libpng/**') }}
- name: Build zlib
run: | # BUILD_SHARED_LIBS causes the output DLL to be correctly called `zlib1.dll`
cmake -S zlib -B zbuild -A ${{ matrix.platform }} -Wno-dev -DCMAKE_INSTALL_PREFIX=install_dir -DBUILD_SHARED_LIBS=ON
cmake --build zbuild --config Release -j
if: steps.cache.outputs.cache-hit != 'true'
- name: Install zlib
run: |
cmake --install zbuild
- name: Build libpng
shell: bash
run: |
cmake -S libpng -B pngbuild -A ${{ matrix.platform }} -Wno-dev -DCMAKE_INSTALL_PREFIX=install_dir -DPNG_SHARED=ON -DPNG_STATIC=OFF -DPNG_TESTS=OFF -DPNG_BUILD_ZLIB=ON -DZLIB_INCLUDE_DIR="$PWD"/install_dir/include -DZLIB_LIBRARY="$PWD"/install_dir/lib/zlib.lib
cmake --build pngbuild --config Release -j
if: steps.cache.outputs.cache-hit != 'true'
- name: Install libpng
run: |
cmake --install pngbuild
- name: Build Windows binaries
shell: bash
run: |
cmake -S . -B build -A ${{ matrix.platform }} -DCMAKE_INSTALL_PREFIX=install_dir -DCMAKE_BUILD_TYPE=Release -DZLIB_LIBRARY="$PWD"/install_dir/lib/zlib.lib -DZLIB_INCLUDE_DIR="$PWD"/install_dir/include -DPNG_LIBRARY="$PWD"/install_dir/lib/libpng16.lib -DPNG_INCLUDE_DIR="$PWD"/install_dir/include
cmake --build build --config Release -j --verbose
cmake --install build --verbose --prefix install_dir --strip
- name: Package binaries
run: |
Compress-Archive -LiteralPath @("install_dir/bin/rgbasm.exe", "install_dir/bin/rgblink.exe", "install_dir/bin/rgbfix.exe", "install_dir/bin/rgbgfx.exe", "install_dir/bin/zlib1.dll", "install_dir/bin/libpng16.dll") "rgbds-${{ env.version }}-win${{ matrix.bits }}.zip"
- name: Upload Windows binaries
uses: actions/upload-artifact@v3
with:
name: win${{ matrix.bits }}
path: rgbds-${{ env.version }}-win${{ matrix.bits }}.zip
macos:
runs-on: macos-12
steps: steps:
- uses: actions/checkout@v2
- name: Get version from tag - name: Get version from tag
shell: bash shell: bash
run: | # Turn "refs/tags/vX.Y.Z" into "X.Y.Z" run: | # Turn "refs/tags/vX.Y.Z" into "X.Y.Z"
VERSION="${{ github.ref }}" VERSION="${{ github.ref_name }}"
echo "version=${VERSION##*/v}" >> $GITHUB_ENV echo "version=${VERSION#v}" >> $GITHUB_ENV
- name: Get zlib, libpng and bison - uses: actions/checkout@v3
run: | # TODO: use an array - name: Install deps
$wc = New-Object System.Net.WebClient shell: bash
$wc.DownloadFile('https://www.zlib.net/zlib1212.zip', 'zlib.zip')
$hash = (Get-FileHash "zlib.zip" -Algorithm SHA256).Hash
if ($hash -ne '173e89893dcb8b4a150d7731cd72f0602f1d6b45e60e2a54efdf7f3fc3325fd7') {
Write-Host "zlib SHA256 mismatch! ($hash)"
exit 1
}
$wc.DownloadFile('https://download.sourceforge.net/libpng/lpng1637.zip', 'libpng.zip')
$hash = (Get-FileHash "libpng.zip" -Algorithm SHA256).Hash
if ($hash -ne '3b4b1cbd0bae6822f749d39b1ccadd6297f05e2b85a83dd2ce6ecd7d09eabdf2') {
Write-Host "libpng SHA256 mismatch! ($hash)"
exit 1
}
$wc.DownloadFile('https://github.com/lexxmark/winflexbison/releases/download/v2.5.24/win_flex_bison-2.5.24.zip', 'winflexbison.zip')
$hash = (Get-FileHash "winflexbison.zip" -Algorithm SHA256).Hash
if ($hash -ne '39c6086ce211d5415500acc5ed2d8939861ca1696aee48909c7f6daf5122b505') {
Write-Host "bison SHA256 mismatch! ($hash)"
}
Expand-Archive -DestinationPath . "zlib.zip"
Expand-Archive -DestinationPath . "libpng.zip"
Expand-Archive -DestinationPath install_dir "winflexbison.zip"
Move-Item zlib-1.2.12 zlib
Move-Item lpng1637 libpng
- name: Build 32-bit zlib
run: | # BUILD_SHARED_LIBS causes the output DLL to be correctly called `zlib1.dll`
cmake -S zlib -B zbuild32 -A Win32 -DCMAKE_INSTALL_PREFIX=install_dir -DBUILD_SHARED_LIBS=ON
cmake --build zbuild32 --config Release
cmake --install zbuild32
- name: Build 32-bit libpng
run: | run: |
cmake -S libpng -B pngbuild32 -A Win32 -DCMAKE_INSTALL_PREFIX=install_dir -DPNG_SHARED=ON -DPNG_STATIC=ON -DPNG_TESTS=OFF ./.github/scripts/install_deps.sh macos-latest
cmake --build pngbuild32 --config Release # We force linking libpng statically; the other libs are provided by macOS itself
cmake --install pngbuild32 - name: Build binaries
- name: Build 32-bit Windows binaries
run: | run: |
cmake -S . -B build32 -A Win32 -DCMAKE_INSTALL_PREFIX=install_dir -DCMAKE_BUILD_TYPE=Release export PATH="/usr/local/opt/bison/bin:$PATH"
cmake --build build32 --config Release make -j WARNFLAGS="-Wall -Wextra -mmacosx-version-min=10.9" PKG_CONFIG="pkg-config --static" PNGLDLIBS="$(pkg-config --static --libs-only-L libpng | cut -c 3-)/libpng.a $(pkg-config --static --libs-only-l libpng | sed s/-lpng[0-9]*//g)" Q=
cmake --install build32 - name: Package binaries
- name: Package 32-bit binaries
run: | run: |
Compress-Archive -LiteralPath @("install_dir/bin/rgbasm.exe", "install_dir/bin/rgblink.exe", "install_dir/bin/rgbfix.exe", "install_dir/bin/rgbgfx.exe", "install_dir/bin/zlib1.dll", "install_dir/bin/libpng16.dll") "rgbds-${{ env.version }}-win32.zip" zip --junk-paths rgbds-${{ env.version }}-macos-x86-64.zip rgb{asm,link,fix,gfx} man/* .github/scripts/install.sh
- name: Build 64-bit zlib - name: Upload macOS binaries
run: | # BUILD_SHARED_LIBS causes the output DLL to be correctly called `zlib1.dll` uses: actions/upload-artifact@v3
cmake -S zlib -B zbuild64 -A x64 -DCMAKE_INSTALL_PREFIX=install_dir -DBUILD_SHARED_LIBS=ON with:
cmake --build zbuild64 --config Release name: macos
cmake --install zbuild64 path: rgbds-${{ env.version }}-macos-x86-64.zip
- name: Build 64-bit libpng
run: | release:
cmake -S libpng -B pngbuild64 -A x64 -DCMAKE_INSTALL_PREFIX=install_dir -DPNG_SHARED=ON -DPNG_STATIC=ON -DPNG_TESTS=OFF runs-on: ubuntu-latest
cmake --build pngbuild64 --config Release needs: [windows, macos]
cmake --install pngbuild64 steps:
- name: Build 64-bit Windows binaries - name: Get version from tag
run: | shell: bash
cmake -S . -B build64 -A x64 -DCMAKE_INSTALL_PREFIX=install_dir -DCMAKE_BUILD_TYPE=Release run: | # Turn "refs/tags/vX.Y.Z" into "X.Y.Z"
cmake --build build64 --config Release VERSION="${{ github.ref_name }}"
cmake --install build64 echo "version=${VERSION#v}" >> $GITHUB_ENV
- name: Package 64-bit binaries - uses: actions/checkout@v3
run: |
Compress-Archive -LiteralPath @("install_dir/bin/rgbasm.exe", "install_dir/bin/rgblink.exe", "install_dir/bin/rgbfix.exe", "install_dir/bin/rgbgfx.exe", "install_dir/bin/zlib1.dll", "install_dir/bin/libpng16.dll") "rgbds-${{ env.version }}-win64.zip"
- name: Package sources - name: Package sources
run: | run: |
make dist make dist Q=
ls
- uses: actions/download-artifact@v3
- name: Release - name: Release
uses: softprops/action-gh-release@v1 uses: softprops/action-gh-release@v1
with: with:
@@ -88,8 +118,9 @@ jobs:
draft: true # Don't publish the release quite yet... draft: true # Don't publish the release quite yet...
prerelease: ${{ contains(github.ref, '-rc') }} prerelease: ${{ contains(github.ref, '-rc') }}
files: | files: |
rgbds-${{ env.version }}-win32.zip win32/rgbds-${{ env.version }}-win32.zip
rgbds-${{ env.version }}-win64.zip win64/rgbds-${{ env.version }}-win64.zip
macos/rgbds-${{ env.version }}-macos-x86-64.zip
rgbds-${{ env.version }}.tar.gz rgbds-${{ env.version }}.tar.gz
fail_on_unmatched_files: true fail_on_unmatched_files: true
env: env:

View File

@@ -10,11 +10,11 @@ jobs:
runs-on: ubuntu-22.04 runs-on: ubuntu-22.04
steps: steps:
- name: Checkout rgbds@release - name: Checkout rgbds@release
uses: actions/checkout@v2 uses: actions/checkout@v3
with: with:
path: rgbds path: rgbds
- name: Checkout rgbds-www@master - name: Checkout rgbds-www@master
uses: actions/checkout@v2 uses: actions/checkout@v3
with: with:
repository: ${{ github.repository_owner }}/rgbds-www repository: ${{ github.repository_owner }}/rgbds-www
path: rgbds-www path: rgbds-www
@@ -25,7 +25,7 @@ jobs:
- name: Update pages - name: Update pages
working-directory: rgbds/man working-directory: rgbds/man
run: | # The ref appears to be in the format "refs/tags/<version>", so strip that run: | # The ref appears to be in the format "refs/tags/<version>", so strip that
../../rgbds-www/.github/actions/get-pages.sh ${GITHUB_REF##*/} * ../../rgbds-www/maintainer/man_to_html.sh ${GITHUB_REF##*/} *
- name: Push new pages - name: Push new pages
working-directory: rgbds-www working-directory: rgbds-www
run: | run: |

View File

@@ -24,11 +24,11 @@ jobs:
fail-fast: false fail-fast: false
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- name: Install deps - name: Install deps
shell: bash shell: bash
run: | run: |
./.github/actions/install_deps.sh ${{ matrix.os }} ./.github/scripts/install_deps.sh ${{ matrix.os }}
# The `export` lines are to allow working on macOS... # The `export` lines are to allow working on macOS...
# Apple's base version is severely outdated, not even supporting -Wall, # Apple's base version is severely outdated, not even supporting -Wall,
# but it overrides Homebrew's version nonetheless... # but it overrides Homebrew's version nonetheless...
@@ -55,6 +55,25 @@ jobs:
with: with:
name: rgbds-canary-${{ matrix.os }}-${{ matrix.cc }}-${{ matrix.buildsys }} name: rgbds-canary-${{ matrix.os }}-${{ matrix.cc }}-${{ matrix.buildsys }}
path: bins path: bins
- name: Compute test dependency cache params
id: test-deps-cache-params
shell: bash
run: |
paths=$(test/fetch-test-deps.sh --get-paths)
hash=$(test/fetch-test-deps.sh --get-hash)
tee -a <<<"paths=\"${paths//,/\\n}\"" $GITHUB_OUTPUT
tee -a <<<"hash=${hash%-}" $GITHUB_OUTPUT
- name: Check test dependency repositories cache
id: test-deps-cache
uses: actions/cache@v3
with:
path: ${{ fromJSON(steps.test-deps-cache-params.outputs.paths) }}
key: ${{ matrix.os }}-${{ steps.test-deps-cache-params.outputs.hash }}
- if: steps.test-deps-cache.outputs.cache-hit != 'true'
name: Fetch test dependency repositories
continue-on-error: true
run: |
test/fetch-test-deps.sh
- name: Test - name: Test
shell: bash shell: bash
run: | run: |
@@ -75,32 +94,9 @@ jobs:
fail-fast: false fail-fast: false
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- name: Get zlib, libpng and bison - name: Install deps
run: | # TODO: use an array; remember to update the versions being downloaded, *and* the paths being extracted! (`Move-Item`) run: .github/scripts/get_win_deps.ps1
$wc = New-Object System.Net.WebClient
$wc.DownloadFile('https://www.zlib.net/zlib1212.zip', 'zlib.zip')
$hash = (Get-FileHash "zlib.zip" -Algorithm SHA256).Hash
if ($hash -ne '173e89893dcb8b4a150d7731cd72f0602f1d6b45e60e2a54efdf7f3fc3325fd7') {
Write-Host "zlib SHA256 mismatch! ($hash)"
exit 1
}
$wc.DownloadFile('https://download.sourceforge.net/libpng/lpng1637.zip', 'libpng.zip')
$hash = (Get-FileHash "libpng.zip" -Algorithm SHA256).Hash
if ($hash -ne '3b4b1cbd0bae6822f749d39b1ccadd6297f05e2b85a83dd2ce6ecd7d09eabdf2') {
Write-Host "libpng SHA256 mismatch! ($hash)"
exit 1
}
$wc.DownloadFile('https://github.com/lexxmark/winflexbison/releases/download/v2.5.24/win_flex_bison-2.5.24.zip', 'winflexbison.zip')
$hash = (Get-FileHash "winflexbison.zip" -Algorithm SHA256).Hash
if ($hash -ne '39c6086ce211d5415500acc5ed2d8939861ca1696aee48909c7f6daf5122b505') {
Write-Host "bison SHA256 mismatch! ($hash)"
}
Expand-Archive -DestinationPath . "zlib.zip"
Expand-Archive -DestinationPath . "libpng.zip"
Expand-Archive -DestinationPath install_dir "winflexbison.zip"
Move-Item zlib-1.2.12 zlib
Move-Item lpng1637 libpng
- uses: actions/cache@v3 - uses: actions/cache@v3
id: cache id: cache
with: with:
@@ -110,23 +106,25 @@ jobs:
key: ${{ matrix.arch }}-${{ hashFiles('zlib/**', 'libpng/**') }} key: ${{ matrix.arch }}-${{ hashFiles('zlib/**', 'libpng/**') }}
- name: Build zlib - name: Build zlib
run: | # BUILD_SHARED_LIBS causes the output DLL to be correctly called `zlib1.dll` run: | # BUILD_SHARED_LIBS causes the output DLL to be correctly called `zlib1.dll`
cmake -S zlib -B zbuild -A ${{ matrix.platform }} -DCMAKE_INSTALL_PREFIX=install_dir -DBUILD_SHARED_LIBS=ON cmake -S zlib -B zbuild -A ${{ matrix.platform }} -Wno-dev -DCMAKE_INSTALL_PREFIX=install_dir -DBUILD_SHARED_LIBS=ON
cmake --build zbuild --config Release -j cmake --build zbuild --config Release -j
if: steps.cache.outputs.cache-hit != 'true' if: steps.cache.outputs.cache-hit != 'true'
- name: Install zlib - name: Install zlib
run: | run: |
cmake --install zbuild cmake --install zbuild
- name: Build libpng - name: Build libpng
shell: bash
run: | run: |
cmake -S libpng -B pngbuild -A ${{ matrix.platform }} -DCMAKE_INSTALL_PREFIX=install_dir -DPNG_SHARED=ON -DPNG_STATIC=ON -DPNG_TESTS=OFF cmake -S libpng -B pngbuild -A ${{ matrix.platform }} -Wno-dev -DCMAKE_INSTALL_PREFIX=install_dir -DPNG_SHARED=ON -DPNG_STATIC=OFF -DPNG_TESTS=OFF -DPNG_BUILD_ZLIB=ON -DZLIB_INCLUDE_DIR="$PWD"/install_dir/include -DZLIB_LIBRARY="$PWD"/install_dir/lib/zlib.lib
cmake --build pngbuild --config Release -j cmake --build pngbuild --config Release -j
if: steps.cache.outputs.cache-hit != 'true' if: steps.cache.outputs.cache-hit != 'true'
- name: Install libpng - name: Install libpng
run: | run: |
cmake --install pngbuild cmake --install pngbuild
- name: Build Windows binaries - name: Build Windows binaries
shell: bash
run: | run: |
cmake -S . -B build -A ${{ matrix.platform }} -DCMAKE_INSTALL_PREFIX=install_dir -DCMAKE_BUILD_TYPE=Release cmake -S . -B build -A ${{ matrix.platform }} -DCMAKE_INSTALL_PREFIX=install_dir -DCMAKE_BUILD_TYPE=Release -DZLIB_LIBRARY="$PWD"/install_dir/lib/zlib.lib -DZLIB_INCLUDE_DIR="$PWD"/install_dir/include -DPNG_LIBRARY="$PWD"/install_dir/lib/libpng16.lib -DPNG_INCLUDE_DIR="$PWD"/install_dir/include
cmake --build build --config Release -j --verbose cmake --build build --config Release -j --verbose
cmake --install build --verbose --prefix install_dir cmake --install build --verbose --prefix install_dir
- name: Package binaries - name: Package binaries
@@ -139,6 +137,26 @@ jobs:
with: with:
name: rgbds-canary-win${{ matrix.bits }} name: rgbds-canary-win${{ matrix.bits }}
path: bins path: bins
- name: Compute test dependency cache params
id: test-deps-cache-params
shell: bash
run: |
paths=$(test/fetch-test-deps.sh --get-paths)
hash=$(test/fetch-test-deps.sh --get-hash)
tee -a <<<"paths=\"${paths//,/\\n}\"" $GITHUB_OUTPUT
tee -a <<<"hash=${hash%-}" $GITHUB_OUTPUT
- name: Check test dependency repositories cache
id: test-deps-cache
uses: actions/cache@v3
with:
path: ${{ fromJSON(steps.test-deps-cache-params.outputs.paths) }}
key: ${{ matrix.os }}-${{ matrix.bits }}-${{ steps.test-deps-cache-params.outputs.hash }}
- if: steps.test-deps-cache.outputs.cache-hit != 'true'
name: Fetch test dependency repositories
shell: bash
continue-on-error: true
run: |
test/fetch-test-deps.sh
- name: Test - name: Test
shell: bash shell: bash
run: | run: |
@@ -162,17 +180,17 @@ jobs:
env: env:
DIST_DIR: win${{ matrix.bits }} DIST_DIR: win${{ matrix.bits }}
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- name: Install deps - name: Install deps
shell: bash shell: bash
run: | run: |
./.github/actions/install_deps.sh ${{ matrix.os }} ./.github/scripts/install_deps.sh ${{ matrix.os }}
- name: Install MinGW - name: Install MinGW
run: | # dpkg-dev is apparently required for pkg-config for cross-building run: | # dpkg-dev is apparently required for pkg-config for cross-building
sudo apt-get install {gcc,g++}-mingw-w64-${{ matrix.arch }}-win32 mingw-w64-tools libz-mingw-w64-dev dpkg-dev sudo apt-get install {gcc,g++}-mingw-w64-${{ matrix.arch }}-win32 mingw-w64-tools libz-mingw-w64-dev dpkg-dev
- name: Install libpng dev headers for MinGW - name: Install libpng dev headers for MinGW
run: | run: |
sudo ./.github/actions/mingw-w64-libpng-dev.sh ${{ matrix.triplet }} sudo ./.github/scripts/mingw-w64-libpng-dev.sh ${{ matrix.triplet }}
- name: Cross-build Windows binaries - name: Cross-build Windows binaries
run: | run: |
make mingw${{ matrix.bits }} -j Q= make mingw${{ matrix.bits }} -j Q=
@@ -205,7 +223,7 @@ jobs:
fail-fast: false fail-fast: false
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- name: Retrieve binaries - name: Retrieve binaries
uses: actions/download-artifact@v3 uses: actions/download-artifact@v3
with: with:
@@ -221,6 +239,26 @@ jobs:
run: | run: |
cp bins/* . cp bins/* .
cp bins/*.dll test/gfx cp bins/*.dll test/gfx
- name: Compute test dependency cache params
id: test-deps-cache-params
shell: bash
run: |
paths=$(test/fetch-test-deps.sh --get-paths)
hash=$(test/fetch-test-deps.sh --get-hash)
tee -a <<<"paths=\"${paths//,/\\n}\"" $GITHUB_OUTPUT
tee -a <<<"hash=${hash%-}" $GITHUB_OUTPUT
- name: Check test dependency repositories cache
id: test-deps-cache
uses: actions/cache@v3
with:
path: ${{ fromJSON(steps.test-deps-cache-params.outputs.paths) }}
key: mingw-${{ matrix.bits }}-${{ steps.test-deps-cache-params.outputs.hash }}
- if: steps.test-deps-cache.outputs.cache-hit != 'true'
name: Fetch test dependency repositories
shell: bash
continue-on-error: true
run: |
test/fetch-test-deps.sh
- name: Run tests - name: Run tests
shell: bash shell: bash
run: | run: |

View File

@@ -20,13 +20,13 @@ jobs:
runs-on: ubuntu-22.04 runs-on: ubuntu-22.04
steps: steps:
- name: Checkout rgbds@master - name: Checkout rgbds@master
uses: actions/checkout@v2 uses: actions/checkout@v3
with: with:
repository: gbdev/rgbds repository: gbdev/rgbds
ref: master ref: master
path: rgbds path: rgbds
- name: Checkout rgbds-www@master - name: Checkout rgbds-www@master
uses: actions/checkout@v2 uses: actions/checkout@v3
with: with:
repository: gbdev/rgbds-www repository: gbdev/rgbds-www
ref: master ref: master

View File

@@ -52,6 +52,7 @@ else()
-fsanitize=alignment -fsanitize=null -fsanitize=address) -fsanitize=alignment -fsanitize=null -fsanitize=address)
add_compile_options(${SAN_FLAGS}) add_compile_options(${SAN_FLAGS})
add_link_options(${SAN_FLAGS}) add_link_options(${SAN_FLAGS})
add_definitions(-D_GLIBCXX_ASSERTIONS)
# A non-zero optimization level is desired in debug mode, but allow overriding it nonetheless # A non-zero optimization level is desired in debug mode, but allow overriding it nonetheless
# TODO: this overrides anything previously set... that's a bit sloppy! # TODO: this overrides anything previously set... that's a bit sloppy!
set(CMAKE_C_FLAGS_DEBUG "-g -Og -fno-omit-frame-pointer -fno-optimize-sibling-calls" CACHE STRING "" FORCE) set(CMAKE_C_FLAGS_DEBUG "-g -Og -fno-omit-frame-pointer -fno-optimize-sibling-calls" CACHE STRING "" FORCE)

View File

@@ -35,8 +35,8 @@ VERSION_STRING := `git describe --tags --dirty --always 2>/dev/null`
WARNFLAGS := -Wall -pedantic WARNFLAGS := -Wall -pedantic
# Overridable CFLAGS # Overridable CFLAGS
CFLAGS ?= -O3 -flto=auto -DNDEBUG CFLAGS ?= -O3 -flto -DNDEBUG
CXXFLAGS ?= -O3 -flto=auto -DNDEBUG CXXFLAGS ?= -O3 -flto -DNDEBUG
# Non-overridable CFLAGS # Non-overridable CFLAGS
# _ISOC11_SOURCE is required on certain platforms to get C11 on top of the C99-based POSIX 2008 # _ISOC11_SOURCE is required on certain platforms to get C11 on top of the C99-based POSIX 2008
REALCFLAGS := ${CFLAGS} ${WARNFLAGS} -std=gnu11 -I include \ REALCFLAGS := ${CFLAGS} ${WARNFLAGS} -std=gnu11 -I include \
@@ -130,7 +130,7 @@ rgbfix: ${rgbfix_obj}
$Q${CC} ${REALLDFLAGS} -o $@ ${rgbfix_obj} ${REALCFLAGS} src/version.c $Q${CC} ${REALLDFLAGS} -o $@ ${rgbfix_obj} ${REALCFLAGS} src/version.c
rgbgfx: ${rgbgfx_obj} rgbgfx: ${rgbgfx_obj}
$Q${CXX} ${REALLDFLAGS} ${PNGLDFLAGS} -o $@ ${rgbgfx_obj} ${REALCXXFLAGS} -x c++ src/version.c ${PNGLDLIBS} $Q${CXX} ${REALLDFLAGS} ${PNGLDFLAGS} -o $@ ${rgbgfx_obj} ${REALCXXFLAGS} ${PNGLDLIBS} -x c++ src/version.c
test/gfx/randtilegen: test/gfx/randtilegen.c test/gfx/randtilegen: test/gfx/randtilegen.c
$Q${CC} ${REALLDFLAGS} ${PNGLDFLAGS} -o $@ $^ ${REALCFLAGS} ${PNGCFLAGS} ${PNGLDLIBS} $Q${CC} ${REALLDFLAGS} ${PNGLDFLAGS} -o $@ $^ ${REALCFLAGS} ${PNGCFLAGS} ${PNGLDLIBS}
@@ -183,21 +183,11 @@ clean:
# Target used to install the binaries and man pages. # Target used to install the binaries and man pages.
install: all install: all
$Qmkdir -p ${DESTDIR}${bindir} $Qinstall -d ${DESTDIR}${bindir}/ ${DESTDIR}${mandir}/man1/ ${DESTDIR}${mandir}/man5/ ${DESTDIR}${mandir}/man7/
$Qinstall ${STRIP} -m ${BINMODE} rgbasm ${DESTDIR}${bindir}/rgbasm $Qinstall ${STRIP} -m ${BINMODE} rgbasm rgblink rgbfix rgbgfx ${DESTDIR}${bindir}/
$Qinstall ${STRIP} -m ${BINMODE} rgbfix ${DESTDIR}${bindir}/rgbfix $Qinstall -m ${MANMODE} man/rgbasm.1 man/rgblink.1 man/rgbfix.1 man/rgbgfx.1 ${DESTDIR}${mandir}/man1/
$Qinstall ${STRIP} -m ${BINMODE} rgblink ${DESTDIR}${bindir}/rgblink $Qinstall -m ${MANMODE} man/rgbds.5 man/rgbasm.5 man/rgblink.5 ${DESTDIR}${mandir}/man5/
$Qinstall ${STRIP} -m ${BINMODE} rgbgfx ${DESTDIR}${bindir}/rgbgfx $Qinstall -m ${MANMODE} man/rgbds.7 man/gbz80.7 ${DESTDIR}${mandir}/man7/
$Qmkdir -p ${DESTDIR}${mandir}/man1 ${DESTDIR}${mandir}/man5 ${DESTDIR}${mandir}/man7
$Qinstall -m ${MANMODE} man/rgbds.7 ${DESTDIR}${mandir}/man7/rgbds.7
$Qinstall -m ${MANMODE} man/gbz80.7 ${DESTDIR}${mandir}/man7/gbz80.7
$Qinstall -m ${MANMODE} man/rgbds.5 ${DESTDIR}${mandir}/man5/rgbds.5
$Qinstall -m ${MANMODE} man/rgbasm.1 ${DESTDIR}${mandir}/man1/rgbasm.1
$Qinstall -m ${MANMODE} man/rgbasm.5 ${DESTDIR}${mandir}/man5/rgbasm.5
$Qinstall -m ${MANMODE} man/rgbfix.1 ${DESTDIR}${mandir}/man1/rgbfix.1
$Qinstall -m ${MANMODE} man/rgblink.1 ${DESTDIR}${mandir}/man1/rgblink.1
$Qinstall -m ${MANMODE} man/rgblink.5 ${DESTDIR}${mandir}/man5/rgblink.5
$Qinstall -m ${MANMODE} man/rgbgfx.1 ${DESTDIR}${mandir}/man1/rgbgfx.1
# Target used to check the coding style of the whole codebase. # Target used to check the coding style of the whole codebase.
# `extern/` is excluded, as it contains external code that should not be patched # `extern/` is excluded, as it contains external code that should not be patched
@@ -244,6 +234,7 @@ develop:
-Wno-type-limits -Wno-tautological-constant-out-of-range-compare \ -Wno-type-limits -Wno-tautological-constant-out-of-range-compare \
-Wvla \ -Wvla \
-Wno-unknown-warning-option \ -Wno-unknown-warning-option \
-D_GLIBCXX_ASSERTIONS \
-fsanitize=shift -fsanitize=integer-divide-by-zero \ -fsanitize=shift -fsanitize=integer-divide-by-zero \
-fsanitize=unreachable -fsanitize=vla-bound \ -fsanitize=unreachable -fsanitize=vla-bound \
-fsanitize=signed-integer-overflow -fsanitize=bounds \ -fsanitize=signed-integer-overflow -fsanitize=bounds \

103
include/file.hpp Normal file
View File

@@ -0,0 +1,103 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 2022, Eldred Habert and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#ifndef RGBDS_FILE_HPP
#define RGBDS_FILE_HPP
#include <array>
#include <assert.h>
#include <cassert>
#include <fcntl.h>
#include <fstream>
#include <ios>
#include <iostream>
#include <streambuf>
#include <string>
#include <string.h>
#include <string_view>
#include <variant>
#include "helpers.h"
#include "platform.h"
#include "gfx/main.hpp"
// Convenience feature for visiting the below.
template<typename... Ts>
struct Visitor : Ts... {
using Ts::operator()...;
};
template<typename... Ts>
Visitor(Ts...) -> Visitor<Ts...>;
class File {
// Construct a `std::streambuf *` by default, since it's probably lighter than a `filebuf`.
std::variant<std::streambuf *, std::filebuf> _file;
public:
File() {}
~File() { close(); }
/**
* This should only be called once, and before doing any `->` operations.
* Returns `nullptr` on error, and a non-null pointer otherwise.
*/
File *open(std::string const &path, std::ios_base::openmode mode) {
if (path != "-") {
return _file.emplace<std::filebuf>().open(path, mode) ? this : nullptr;
} else if (mode & std::ios_base::in) {
assert(!(mode & std::ios_base::out));
_file.emplace<std::streambuf *>(std::cin.rdbuf());
if (setmode(STDIN_FILENO, mode & std::ios_base::binary ? O_BINARY : O_TEXT) == -1) {
fatal("Failed to set stdin to %s mode: %s",
mode & std::ios_base::binary ? "binary" : "text", strerror(errno));
}
} else {
assert(mode & std::ios_base::out);
_file.emplace<std::streambuf *>(std::cout.rdbuf());
}
return this;
}
std::streambuf &operator*() {
return std::visit(Visitor{[](std::filebuf &file) -> std::streambuf & { return file; },
[](std::streambuf *buf) -> std::streambuf & { return *buf; }},
_file);
}
std::streambuf const &operator*() const {
// The non-`const` version does not perform any modifications, so it's okay.
return **const_cast<File *>(this);
}
std::streambuf *operator->() { return &**this; }
std::streambuf const *operator->() const {
// See the `operator*` equivalent.
return const_cast<File *>(this)->operator->();
}
File *close() {
return std::visit(Visitor{[this](std::filebuf &file) {
// This is called by the destructor, and an explicit `close`
// shouldn't close twice.
_file.emplace<std::streambuf *>(nullptr);
return file.close() != nullptr;
},
[](std::streambuf *buf) { return buf != nullptr; }},
_file)
? this
: nullptr;
}
char const *c_str(std::string const &path) const {
return std::visit(Visitor{[&path](std::filebuf const &) { return path.c_str(); },
[](std::streambuf const *buf) {
return buf == std::cin.rdbuf() ? "<stdin>" : "<stdout>";
}},
_file);
}
};
#endif // RGBDS_FILE_HPP

View File

@@ -63,8 +63,10 @@
# define O_RDWR _O_RDWR # define O_RDWR _O_RDWR
# define S_ISREG(field) ((field) & _S_IFREG) # define S_ISREG(field) ((field) & _S_IFREG)
# define O_BINARY _O_BINARY # define O_BINARY _O_BINARY
# define O_TEXT _O_TEXT
#elif !defined(O_BINARY) // Cross-compilers define O_BINARY #elif !defined(O_BINARY) // Cross-compilers define O_BINARY
# define O_BINARY 0 // POSIX says we shouldn't care! # define O_BINARY 0 // POSIX says we shouldn't care!
# define O_TEXT 0 // Assume that it's not defined either
#endif // _MSC_VER #endif // _MSC_VER
// Windows has stdin and stdout open as text by default, which we may not want // Windows has stdin and stdout open as text by default, which we may not want
@@ -72,7 +74,7 @@
# include <io.h> # include <io.h>
# define setmode(fd, mode) _setmode(fd, mode) # define setmode(fd, mode) _setmode(fd, mode)
#else #else
# define setmode(fd, mode) ((void)0) # define setmode(fd, mode) (0)
#endif #endif
#endif // RGBDS_PLATFORM_H #endif // RGBDS_PLATFORM_H

View File

@@ -15,7 +15,7 @@ extern "C" {
#define PACKAGE_VERSION_MAJOR 0 #define PACKAGE_VERSION_MAJOR 0
#define PACKAGE_VERSION_MINOR 6 #define PACKAGE_VERSION_MINOR 6
#define PACKAGE_VERSION_PATCH 0 #define PACKAGE_VERSION_PATCH 1
char const *get_package_version_string(void); char const *get_package_version_string(void);

View File

@@ -72,6 +72,18 @@ All of these are equivalent:
.Ql 0X2A , .Ql 0X2A ,
.Ql 0x2a . .Ql 0x2a .
.Pp .Pp
Unless otherwise noted, passing
.Ql -
(a single dash) as a file name makes
.Nm
use standard input (for input files) or standard output (for output files).
To suppress this behavior, and open a file in the current directory actually called
.Ql - ,
pass
.Ql ./-
instead.
Using standard input or output more than once in a single command will likely produce unexpected results.
.Pp
The following options are accepted: The following options are accepted:
.Bl -tag -width Ds .Bl -tag -width Ds
.It Fl a Ar attrmap , Fl Fl attr-map Ar attrmap .It Fl a Ar attrmap , Fl Fl attr-map Ar attrmap
@@ -145,7 +157,9 @@ The expected format is
.Ql format:path , .Ql format:path ,
where where
.Ar path .Ar path
is a path to a file, which will be processed according to the is a path to a file
.Ql ( -
is not treated specially), which will be processed according to the
.Ar format . .Ar format .
See See
.Sx PALETTE SPECIFICATION FORMATS .Sx PALETTE SPECIFICATION FORMATS

View File

@@ -14,21 +14,20 @@ set(common_src
"_version.c" "_version.c"
) )
find_package(BISON REQUIRED) find_package(BISON 3.0.0 REQUIRED)
set(BISON_FLAGS "-Wall") set(BISON_FLAGS "-Wall")
# Set sompe optimization flags on versions that support them # Set some optimization flags on versions that support them
if(BISON_VERSION VERSION_GREATER_EQUAL "3.5") if(BISON_VERSION VERSION_GREATER_EQUAL "3.5")
set(BISON_FLAGS "${BISON_FLAGS} -Dapi.token.raw=true") set(BISON_FLAGS "${BISON_FLAGS} -Dapi.token.raw=true")
endif() endif()
if(BISON_VERSION VERSION_GREATER_EQUAL "3.6") if(BISON_VERSION VERSION_GREATER_EQUAL "3.6")
set(BISON_FLAGS "${BISON_FLAGS} -Dparse.error=detailed") set(BISON_FLAGS "${BISON_FLAGS} -Dparse.error=detailed")
elseif(BISON_VERSION VERSION_GREATER_EQUAL "3.0") else()
set(BISON_FLAGS "${BISON_FLAGS} -Dparse.error=verbose") set(BISON_FLAGS "${BISON_FLAGS} -Dparse.error=verbose")
endif() endif()
if(BISON_VERSION VERSION_GREATER_EQUAL "3.0")
set(BISON_FLAGS "${BISON_FLAGS} -Dparse.lac=full") set(BISON_FLAGS "${BISON_FLAGS} -Dparse.lac=full")
set(BISON_FLAGS "${BISON_FLAGS} -Dlr.type=ielr") set(BISON_FLAGS "${BISON_FLAGS} -Dlr.type=ielr")
endif()
BISON_TARGET(PARSER "asm/parser.y" BISON_TARGET(PARSER "asm/parser.y"
"${PROJECT_SOURCE_DIR}/src/asm/parser.c" "${PROJECT_SOURCE_DIR}/src/asm/parser.c"
COMPILE_FLAGS "${BISON_FLAGS}" COMPILE_FLAGS "${BISON_FLAGS}"

View File

@@ -359,10 +359,10 @@ int main(int argc, char *argv[])
targetFileName[targetFileNameLen - 1] = '\0'; // Overwrite the last space targetFileName[targetFileNameLen - 1] = '\0'; // Overwrite the last space
if (argc == musl_optind) { if (argc == musl_optind) {
fputs("FATAL: No input files\n", stderr); fputs("FATAL: Please specify an input file (pass `-` to read from standard input)\n", stderr);
print_usage(); print_usage();
} else if (argc != musl_optind + 1) { } else if (argc != musl_optind + 1) {
fputs("FATAL: More than one input file given\n", stderr); fputs("FATAL: More than one input file specified\n", stderr);
print_usage(); print_usage();
} }

View File

@@ -690,17 +690,19 @@ asmfile : lines
; ;
lines : %empty lines : %empty
| lines line | lines opt_diff_mark line
; ;
endofline : T_NEWLINE | T_EOB endofline : T_NEWLINE | T_EOB
; ;
plain_directive : label opt_diff_mark : %empty // OK
| label cpu_command | T_OP_ADD {
| label macro error("syntax error, unexpected + at the beginning of the line (is it a leftover diff mark?)\n");
| label directive }
| assignment_directive | T_OP_SUB {
error("syntax error, unexpected - at the beginning of the line (is it a leftover diff mark?)\n");
}
; ;
line : plain_directive endofline line : plain_directive endofline
@@ -786,6 +788,13 @@ else : T_POP_ELSE T_NEWLINE {
} }
; ;
plain_directive : label
| label cpu_command
| label macro
| label directive
| assignment_directive
;
endc : T_POP_ENDC { endc : T_POP_ENDC {
lexer_DecIFDepth(); lexer_DecIFDepth();
} }

View File

@@ -1174,8 +1174,8 @@ static bool processFilename(char const *name)
{ {
nbErrors = 0; nbErrors = 0;
if (!strcmp(name, "-")) { if (!strcmp(name, "-")) {
setmode(STDIN_FILENO, O_BINARY); (void)setmode(STDIN_FILENO, O_BINARY);
setmode(STDOUT_FILENO, O_BINARY); (void)setmode(STDOUT_FILENO, O_BINARY);
name = "<stdin>"; name = "<stdin>";
processFile(STDIN_FILENO, STDOUT_FILENO, name, 0); processFile(STDIN_FILENO, STDOUT_FILENO, name, 0);

View File

@@ -23,8 +23,10 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <string_view> #include <string_view>
#include <type_traits>
#include "extern/getopt.h" #include "extern/getopt.h"
#include "file.hpp"
#include "platform.h" #include "platform.h"
#include "version.h" #include "version.h"
@@ -253,10 +255,13 @@ static void registerInput(char const *arg) {
* @param argPool Argument characters will be appended to this vector, for storage purposes. * @param argPool Argument characters will be appended to this vector, for storage purposes.
*/ */
static std::vector<size_t> readAtFile(std::string const &path, std::vector<char> &argPool) { static std::vector<size_t> readAtFile(std::string const &path, std::vector<char> &argPool) {
std::filebuf file; File file;
file.open(path, std::ios_base::in); if (!file.open(path, std::ios_base::in)) {
fatal("Error reading @%s: %s", file.c_str(path), strerror(errno));
}
static_assert(decltype(file)::traits_type::eof() == EOF, // We only filter out `EOF`, but calling `isblank()` on anything else is UB!
static_assert(std::remove_reference_t<decltype(*file)>::traits_type::eof() == EOF,
"isblank(char_traits<...>::eof()) is UB!"); "isblank(char_traits<...>::eof()) is UB!");
std::vector<size_t> argvOfs; std::vector<size_t> argvOfs;
@@ -265,7 +270,7 @@ static std::vector<size_t> readAtFile(std::string const &path, std::vector<char>
// First, discard any leading whitespace // First, discard any leading whitespace
do { do {
c = file.sbumpc(); c = file->sbumpc();
if (c == EOF) { if (c == EOF) {
return argvOfs; return argvOfs;
} }
@@ -273,7 +278,7 @@ static std::vector<size_t> readAtFile(std::string const &path, std::vector<char>
switch (c) { switch (c) {
case '#': // If it's a comment, discard everything until EOL case '#': // If it's a comment, discard everything until EOL
while ((c = file.sbumpc()) != '\n') { while ((c = file->sbumpc()) != '\n') {
if (c == EOF) { if (c == EOF) {
return argvOfs; return argvOfs;
} }
@@ -281,7 +286,7 @@ static std::vector<size_t> readAtFile(std::string const &path, std::vector<char>
continue; // Start processing the next line continue; // Start processing the next line
// If it's an empty line, ignore it // If it's an empty line, ignore it
case '\r': // Assuming CRLF here case '\r': // Assuming CRLF here
file.sbumpc(); // Discard the upcoming '\n' file->sbumpc(); // Discard the upcoming '\n'
[[fallthrough]]; [[fallthrough]];
case '\n': case '\n':
continue; // Start processing the next line continue; // Start processing the next line
@@ -296,11 +301,11 @@ static std::vector<size_t> readAtFile(std::string const &path, std::vector<char>
// on `vector` and `sbumpc` to do the right thing here. // on `vector` and `sbumpc` to do the right thing here.
argPool.push_back(c); // Push the character we've already read argPool.push_back(c); // Push the character we've already read
for (;;) { for (;;) {
c = file.sbumpc(); c = file->sbumpc();
if (isblank(c) || c == '\n' || c == EOF) { if (c == EOF || c == '\n' || isblank(c)) {
break; break;
} else if (c == '\r') { } else if (c == '\r') {
file.sbumpc(); // Discard the '\n' file->sbumpc(); // Discard the '\n'
break; break;
} }
argPool.push_back(c); argPool.push_back(c);
@@ -309,10 +314,10 @@ static std::vector<size_t> readAtFile(std::string const &path, std::vector<char>
// Discard whitespace until the next argument (candidate) // Discard whitespace until the next argument (candidate)
while (isblank(c)) { while (isblank(c)) {
c = file.sbumpc(); c = file->sbumpc();
} }
if (c == '\r') { if (c == '\r') {
c = file.sbumpc(); // Skip the '\n' c = file->sbumpc(); // Skip the '\n'
} }
} while (c != '\n' && c != EOF); // End if we reached EOL } while (c != '\n' && c != EOF); // End if we reached EOL
} }

View File

@@ -27,6 +27,7 @@
#include <vector> #include <vector>
#include "defaultinitalloc.hpp" #include "defaultinitalloc.hpp"
#include "file.hpp"
#include "helpers.h" #include "helpers.h"
#include "itertools.hpp" #include "itertools.hpp"
@@ -77,7 +78,7 @@ public:
class Png { class Png {
std::string const &path; std::string const &path;
std::filebuf file{}; File file{};
png_structp png = nullptr; png_structp png = nullptr;
png_infop info = nullptr; png_infop info = nullptr;
@@ -93,25 +94,26 @@ class Png {
[[noreturn]] static void handleError(png_structp png, char const *msg) { [[noreturn]] static void handleError(png_structp png, char const *msg) {
Png *self = reinterpret_cast<Png *>(png_get_error_ptr(png)); Png *self = reinterpret_cast<Png *>(png_get_error_ptr(png));
fatal("Error reading input image (\"%s\"): %s", self->path.c_str(), msg); fatal("Error reading input image (\"%s\"): %s", self->file.c_str(self->path), msg);
} }
static void handleWarning(png_structp png, char const *msg) { static void handleWarning(png_structp png, char const *msg) {
Png *self = reinterpret_cast<Png *>(png_get_error_ptr(png)); Png *self = reinterpret_cast<Png *>(png_get_error_ptr(png));
warning("In input image (\"%s\"): %s", self->path.c_str(), msg); warning("In input image (\"%s\"): %s", self->file.c_str(self->path), msg);
} }
static void readData(png_structp png, png_bytep data, size_t length) { static void readData(png_structp png, png_bytep data, size_t length) {
Png *self = reinterpret_cast<Png *>(png_get_io_ptr(png)); Png *self = reinterpret_cast<Png *>(png_get_io_ptr(png));
std::streamsize expectedLen = length; std::streamsize expectedLen = length;
std::streamsize nbBytesRead = self->file.sgetn(reinterpret_cast<char *>(data), expectedLen); std::streamsize nbBytesRead =
self->file->sgetn(reinterpret_cast<char *>(data), expectedLen);
if (nbBytesRead != expectedLen) { if (nbBytesRead != expectedLen) {
fatal("Error reading input image (\"%s\"): file too short (expected at least %zd more " fatal("Error reading input image (\"%s\"): file too short (expected at least %zd more "
"bytes after reading %lld)", "bytes after reading %lld)",
self->path.c_str(), length - nbBytesRead, self->file.c_str(self->path), length - nbBytesRead,
self->file.pubseekoff(0, std::ios_base::cur)); self->file->pubseekoff(0, std::ios_base::cur));
} }
} }
@@ -142,7 +144,7 @@ public:
} }
uint8_t bins = 0; uint8_t bins = 0;
for (auto const &color : colors) { for (auto const &color : colors) {
if (color->isTransparent()) { if (!color.has_value() || color->isTransparent()) {
continue; continue;
} }
if (!color->isGray()) { if (!color->isGray()) {
@@ -175,17 +177,17 @@ public:
*/ */
explicit Png(std::string const &filePath) : path(filePath), colors() { explicit Png(std::string const &filePath) : path(filePath), colors() {
if (file.open(path, std::ios_base::in | std::ios_base::binary) == nullptr) { if (file.open(path, std::ios_base::in | std::ios_base::binary) == nullptr) {
fatal("Failed to open input image (\"%s\"): %s", path.c_str(), strerror(errno)); fatal("Failed to open input image (\"%s\"): %s", file.c_str(path), strerror(errno));
} }
options.verbosePrint(Options::VERB_LOG_ACT, "Opened input file\n"); options.verbosePrint(Options::VERB_LOG_ACT, "Opened input file\n");
std::array<unsigned char, 8> pngHeader; std::array<unsigned char, 8> pngHeader;
if (file.sgetn(reinterpret_cast<char *>(pngHeader.data()), pngHeader.size()) if (file->sgetn(reinterpret_cast<char *>(pngHeader.data()), pngHeader.size())
!= static_cast<std::streamsize>(pngHeader.size()) // Not enough bytes? != static_cast<std::streamsize>(pngHeader.size()) // Not enough bytes?
|| png_sig_cmp(pngHeader.data(), 0, pngHeader.size()) != 0) { || png_sig_cmp(pngHeader.data(), 0, pngHeader.size()) != 0) {
fatal("Input file (\"%s\") is not a PNG image!", path.c_str()); fatal("Input file (\"%s\") is not a PNG image!", file.c_str(path));
} }
options.verbosePrint(Options::VERB_INTERM, "PNG header signature is OK\n"); options.verbosePrint(Options::VERB_INTERM, "PNG header signature is OK\n");
@@ -624,14 +626,16 @@ static std::tuple<DefaultInitVec<size_t>, std::vector<Palette>>
} }
static void outputPalettes(std::vector<Palette> const &palettes) { static void outputPalettes(std::vector<Palette> const &palettes) {
std::filebuf output; File output;
output.open(options.palettes, std::ios_base::out | std::ios_base::binary); if (!output.open(options.palettes, std::ios_base::out | std::ios_base::binary)) {
fatal("Failed to open \"%s\": %s", output.c_str(options.palettes), strerror(errno));
}
for (Palette const &palette : palettes) { for (Palette const &palette : palettes) {
for (uint8_t i = 0; i < options.nbColorsPerPal; ++i) { for (uint8_t i = 0; i < options.nbColorsPerPal; ++i) {
uint16_t color = palette.colors[i]; // Will return `UINT16_MAX` for unused slots uint16_t color = palette.colors[i]; // Will return `UINT16_MAX` for unused slots
output.sputc(color & 0xFF); output->sputc(color & 0xFF);
output.sputc(color >> 8); output->sputc(color >> 8);
} }
} }
} }
@@ -750,8 +754,10 @@ namespace unoptimized {
static void outputTileData(Png const &png, DefaultInitVec<AttrmapEntry> const &attrmap, static void outputTileData(Png const &png, DefaultInitVec<AttrmapEntry> const &attrmap,
std::vector<Palette> const &palettes, std::vector<Palette> const &palettes,
DefaultInitVec<size_t> const &mappings) { DefaultInitVec<size_t> const &mappings) {
std::filebuf output; File output;
output.open(options.output, std::ios_base::out | std::ios_base::binary); if (!output.open(options.output, std::ios_base::out | std::ios_base::binary)) {
fatal("Failed to open \"%s\": %s", output.c_str(options.output), strerror(errno));
}
uint64_t remainingTiles = (png.getWidth() / 8) * (png.getHeight() / 8); uint64_t remainingTiles = (png.getWidth() / 8) * (png.getHeight() / 8);
if (remainingTiles <= options.trim) { if (remainingTiles <= options.trim) {
@@ -764,9 +770,9 @@ static void outputTileData(Png const &png, DefaultInitVec<AttrmapEntry> const &a
Palette const &palette = palettes[attr.getPalID(mappings)]; Palette const &palette = palettes[attr.getPalID(mappings)];
for (uint32_t y = 0; y < 8; ++y) { for (uint32_t y = 0; y < 8; ++y) {
uint16_t bitplanes = TileData::rowBitplanes(tile, palette, y); uint16_t bitplanes = TileData::rowBitplanes(tile, palette, y);
output.sputc(bitplanes & 0xFF); output->sputc(bitplanes & 0xFF);
if (options.bitDepth == 2) { if (options.bitDepth == 2) {
output.sputc(bitplanes >> 8); output->sputc(bitplanes >> 8);
} }
} }
@@ -780,18 +786,27 @@ static void outputTileData(Png const &png, DefaultInitVec<AttrmapEntry> const &a
static void outputMaps(DefaultInitVec<AttrmapEntry> const &attrmap, static void outputMaps(DefaultInitVec<AttrmapEntry> const &attrmap,
DefaultInitVec<size_t> const &mappings) { DefaultInitVec<size_t> const &mappings) {
std::optional<std::filebuf> tilemapOutput, attrmapOutput, palmapOutput; std::optional<File> tilemapOutput, attrmapOutput, palmapOutput;
if (!options.tilemap.empty()) { if (!options.tilemap.empty()) {
tilemapOutput.emplace(); tilemapOutput.emplace();
tilemapOutput->open(options.tilemap, std::ios_base::out | std::ios_base::binary); if (!tilemapOutput->open(options.tilemap, std::ios_base::out | std::ios_base::binary)) {
fatal("Failed to open \"%s\": %s", tilemapOutput->c_str(options.tilemap),
strerror(errno));
}
} }
if (!options.attrmap.empty()) { if (!options.attrmap.empty()) {
attrmapOutput.emplace(); attrmapOutput.emplace();
attrmapOutput->open(options.attrmap, std::ios_base::out | std::ios_base::binary); if (!attrmapOutput->open(options.attrmap, std::ios_base::out | std::ios_base::binary)) {
fatal("Failed to open \"%s\": %s", attrmapOutput->c_str(options.attrmap),
strerror(errno));
}
} }
if (!options.palmap.empty()) { if (!options.palmap.empty()) {
palmapOutput.emplace(); palmapOutput.emplace();
palmapOutput->open(options.palmap, std::ios_base::out | std::ios_base::binary); if (!palmapOutput->open(options.palmap, std::ios_base::out | std::ios_base::binary)) {
fatal("Failed to open \"%s\": %s", palmapOutput->c_str(options.palmap),
strerror(errno));
}
} }
uint8_t tileID = 0; uint8_t tileID = 0;
@@ -804,14 +819,14 @@ static void outputMaps(DefaultInitVec<AttrmapEntry> const &attrmap,
} }
if (tilemapOutput.has_value()) { if (tilemapOutput.has_value()) {
tilemapOutput->sputc(tileID + options.baseTileIDs[bank]); (*tilemapOutput)->sputc(tileID + options.baseTileIDs[bank]);
} }
if (attrmapOutput.has_value()) { if (attrmapOutput.has_value()) {
uint8_t palID = attr.getPalID(mappings) & 7; uint8_t palID = attr.getPalID(mappings) & 7;
attrmapOutput->sputc(palID | bank << 3); // The other flags are all 0 (*attrmapOutput)->sputc(palID | bank << 3); // The other flags are all 0
} }
if (palmapOutput.has_value()) { if (palmapOutput.has_value()) {
palmapOutput->sputc(attr.getPalID(mappings)); (*palmapOutput)->sputc(attr.getPalID(mappings));
} }
++tileID; ++tileID;
} }
@@ -886,47 +901,55 @@ static UniqueTiles dedupTiles(Png const &png, DefaultInitVec<AttrmapEntry> &attr
} }
static void outputTileData(UniqueTiles const &tiles) { static void outputTileData(UniqueTiles const &tiles) {
std::filebuf output; File output;
output.open(options.output, std::ios_base::out | std::ios_base::binary); if (!output.open(options.output, std::ios_base::out | std::ios_base::binary)) {
fatal("Failed to create \"%s\": %s", output.c_str(options.output), strerror(errno));
}
uint16_t tileID = 0; uint16_t tileID = 0;
for (auto iter = tiles.begin(), end = tiles.end() - options.trim; iter != end; ++iter) { for (auto iter = tiles.begin(), end = tiles.end() - options.trim; iter != end; ++iter) {
TileData const *tile = *iter; TileData const *tile = *iter;
assert(tile->tileID == tileID); assert(tile->tileID == tileID);
++tileID; ++tileID;
output.sputn(reinterpret_cast<char const *>(tile->data().data()), options.bitDepth * 8); output->sputn(reinterpret_cast<char const *>(tile->data().data()), options.bitDepth * 8);
} }
} }
static void outputTilemap(DefaultInitVec<AttrmapEntry> const &attrmap) { static void outputTilemap(DefaultInitVec<AttrmapEntry> const &attrmap) {
std::filebuf output; File output;
output.open(options.tilemap, std::ios_base::out | std::ios_base::binary); if (!output.open(options.tilemap, std::ios_base::out | std::ios_base::binary)) {
fatal("Failed to create \"%s\": %s", output.c_str(options.tilemap), strerror(errno));
}
for (AttrmapEntry const &entry : attrmap) { for (AttrmapEntry const &entry : attrmap) {
output.sputc(entry.tileID); // The tile ID has already been converted output->sputc(entry.tileID); // The tile ID has already been converted
} }
} }
static void outputAttrmap(DefaultInitVec<AttrmapEntry> const &attrmap, static void outputAttrmap(DefaultInitVec<AttrmapEntry> const &attrmap,
DefaultInitVec<size_t> const &mappings) { DefaultInitVec<size_t> const &mappings) {
std::filebuf output; File output;
output.open(options.attrmap, std::ios_base::out | std::ios_base::binary); if (!output.open(options.attrmap, std::ios_base::out | std::ios_base::binary)) {
fatal("Failed to create \"%s\": %s", output.c_str(options.attrmap), strerror(errno));
}
for (AttrmapEntry const &entry : attrmap) { for (AttrmapEntry const &entry : attrmap) {
uint8_t attr = entry.xFlip << 5 | entry.yFlip << 6; uint8_t attr = entry.xFlip << 5 | entry.yFlip << 6;
attr |= entry.bank << 3; attr |= entry.bank << 3;
attr |= entry.getPalID(mappings) & 7; attr |= entry.getPalID(mappings) & 7;
output.sputc(attr); output->sputc(attr);
} }
} }
static void outputPalmap(DefaultInitVec<AttrmapEntry> const &attrmap, static void outputPalmap(DefaultInitVec<AttrmapEntry> const &attrmap,
DefaultInitVec<size_t> const &mappings) { DefaultInitVec<size_t> const &mappings) {
std::filebuf output; File output;
output.open(options.attrmap, std::ios_base::out | std::ios_base::binary); if (!output.open(options.attrmap, std::ios_base::out | std::ios_base::binary)) {
fatal("Failed to create \"%s\": %s", output.c_str(options.attrmap), strerror(errno));
}
for (AttrmapEntry const &entry : attrmap) { for (AttrmapEntry const &entry : attrmap) {
output.sputc(entry.getPalID(mappings)); output->sputc(entry.getPalID(mappings));
} }
} }

View File

@@ -21,15 +21,16 @@
#include <vector> #include <vector>
#include "defaultinitalloc.hpp" #include "defaultinitalloc.hpp"
#include "file.hpp"
#include "helpers.h" #include "helpers.h"
#include "itertools.hpp" #include "itertools.hpp"
#include "gfx/main.hpp" #include "gfx/main.hpp"
static DefaultInitVec<uint8_t> readInto(std::string path) { static DefaultInitVec<uint8_t> readInto(std::string path) {
std::filebuf file; File file;
if (!file.open(path, std::ios::in | std::ios::binary)) { if (!file.open(path, std::ios::in | std::ios::binary)) {
fatal("Failed to open \"%s\": %s", path.c_str(), strerror(errno)); fatal("Failed to open \"%s\": %s", file.c_str(path), strerror(errno));
} }
DefaultInitVec<uint8_t> data(128 * 16); // Begin with some room pre-allocated DefaultInitVec<uint8_t> data(128 * 16); // Begin with some room pre-allocated
@@ -40,7 +41,7 @@ static DefaultInitVec<uint8_t> readInto(std::string path) {
// Fill the new area ([oldSize; curSize[) with bytes // Fill the new area ([oldSize; curSize[) with bytes
size_t nbRead = size_t nbRead =
file.sgetn(reinterpret_cast<char *>(&data.data()[oldSize]), curSize - oldSize); file->sgetn(reinterpret_cast<char *>(&data.data()[oldSize]), curSize - oldSize);
if (nbRead != curSize - oldSize) { if (nbRead != curSize - oldSize) {
// Shrink the vector to discard bytes that weren't read // Shrink the vector to discard bytes that weren't read
data.resize(oldSize + nbRead); data.resize(oldSize + nbRead);
@@ -68,13 +69,13 @@ static void pngWarning(png_structp png, char const *msg) {
} }
void writePng(png_structp png, png_bytep data, size_t length) { void writePng(png_structp png, png_bytep data, size_t length) {
auto &pngFile = *static_cast<std::filebuf *>(png_get_io_ptr(png)); auto &pngFile = *static_cast<File *>(png_get_io_ptr(png));
pngFile.sputn(reinterpret_cast<char *>(data), length); pngFile->sputn(reinterpret_cast<char *>(data), length);
} }
void flushPng(png_structp png) { void flushPng(png_structp png) {
auto &pngFile = *static_cast<std::filebuf *>(png_get_io_ptr(png)); auto &pngFile = *static_cast<File *>(png_get_io_ptr(png));
pngFile.pubsync(); pngFile->pubsync();
} }
void reverse() { void reverse() {
@@ -146,14 +147,16 @@ void reverse() {
{Rgba(0xffffffff), Rgba(0xaaaaaaff), Rgba(0x555555ff), Rgba(0x000000ff)} {Rgba(0xffffffff), Rgba(0xaaaaaaff), Rgba(0x555555ff), Rgba(0x000000ff)}
}; };
if (!options.palettes.empty()) { if (!options.palettes.empty()) {
std::filebuf file; File file;
file.open(options.palettes, std::ios::in | std::ios::binary); if (!file.open(options.palettes, std::ios::in | std::ios::binary)) {
fatal("Failed to open \"%s\": %s", file.c_str(options.palettes), strerror(errno));
}
palettes.clear(); palettes.clear();
std::array<uint8_t, sizeof(uint16_t) * 4> buf; // 4 colors std::array<uint8_t, sizeof(uint16_t) * 4> buf; // 4 colors
size_t nbRead; size_t nbRead;
do { do {
nbRead = file.sgetn(reinterpret_cast<char *>(buf.data()), buf.size()); nbRead = file->sgetn(reinterpret_cast<char *>(buf.data()), buf.size());
if (nbRead == buf.size()) { if (nbRead == buf.size()) {
// Expand the colors // Expand the colors
auto &palette = palettes.emplace_back(); auto &palette = palettes.emplace_back();
@@ -231,11 +234,13 @@ void reverse() {
} }
options.verbosePrint(Options::VERB_LOG_ACT, "Writing image...\n"); options.verbosePrint(Options::VERB_LOG_ACT, "Writing image...\n");
std::filebuf pngFile; File pngFile;
pngFile.open(options.input, std::ios::out | std::ios::binary); if (!pngFile.open(options.input, std::ios::out | std::ios::binary)) {
fatal("Failed to create \"%s\": %s", pngFile.c_str(options.input), strerror(errno));
}
png_structp png = png_create_write_struct( png_structp png = png_create_write_struct(
PNG_LIBPNG_VER_STRING, PNG_LIBPNG_VER_STRING,
const_cast<png_voidp>(static_cast<void const *>(options.input.c_str())), pngError, const_cast<png_voidp>(static_cast<void const *>(pngFile.c_str(options.input))), pngError,
pngWarning); pngWarning);
if (!png) { if (!png) {
fatal("Couldn't create PNG write struct: %s", strerror(errno)); fatal("Couldn't create PNG write struct: %s", strerror(errno));

View File

@@ -398,6 +398,8 @@ static void readSection(FILE *file, struct Section *section, char const *fileNam
for (uint32_t i = 0; i < section->nbPatches; i++) for (uint32_t i = 0; i < section->nbPatches; i++)
readPatch(file, &patches[i], fileName, section->name, i, fileNodes); readPatch(file, &patches[i], fileName, section->name, i, fileNodes);
section->patches = patches; section->patches = patches;
} else {
section->data = NULL; // `mergeSections()` expects to be able to always read the ptr
} }
} }

View File

@@ -404,6 +404,16 @@ static void writeSymBank(struct SortedSections const *bankSections,
} }
static void writeEmptySpace(uint16_t begin, uint16_t end)
{
if (begin < end) {
uint16_t len = end - begin;
fprintf(mapFile, "\tEMPTY: $%04x-$%04x ($%04" PRIx16 " byte%s)\n",
begin, end - 1, len, len == 1 ? "" : "s");
}
}
/* /*
* Write a bank's contents to the map file * Write a bank's contents to the map file
* @param bankSections The bank's sections * @param bankSections The bank's sections
@@ -432,12 +442,7 @@ static uint16_t writeMapBank(struct SortedSections const *sectList,
used += sect->size; used += sect->size;
assert(sect->offset == 0); assert(sect->offset == 0);
if (prevEndAddr < sect->org) { writeEmptySpace(prevEndAddr, sect->org);
uint16_t empty = sect->org - prevEndAddr;
fprintf(mapFile, "\tEMPTY: $%04" PRIx16 " byte%s\n", empty,
empty == 1 ? "" : "s");
}
prevEndAddr = sect->org + sect->size; prevEndAddr = sect->org + sect->size;
@@ -455,16 +460,22 @@ static uint16_t writeMapBank(struct SortedSections const *sectList,
uint16_t org = sect->org; uint16_t org = sect->org;
while (sect) { while (sect) {
if (sect->modifier == SECTION_UNION)
fprintf(mapFile, "\t\t; New union\n");
else if (sect->modifier == SECTION_FRAGMENT)
fprintf(mapFile, "\t\t; New fragment\n");
for (size_t i = 0; i < sect->nbSymbols; i++) for (size_t i = 0; i < sect->nbSymbols; i++)
// "\tSECTION: $xxxx ..." // Space matches "\tSECTION: $xxxx ..."
fprintf(mapFile, "\t $%04" PRIx32 " = %s\n", fprintf(mapFile, "\t $%04" PRIx32 " = %s\n",
sect->symbols[i]->offset + org, sect->symbols[i]->offset + org,
sect->symbols[i]->name); sect->symbols[i]->name);
if (sect->nextu) {
// Announce the following "piece"
if (sect->nextu->modifier == SECTION_UNION)
fprintf(mapFile,
"\t ; Next union\n");
else if (sect->nextu->modifier == SECTION_FRAGMENT)
fprintf(mapFile,
"\t ; Next fragment\n");
}
sect = sect->nextu; // Also print symbols in the following "pieces" sect = sect->nextu; // Also print symbols in the following "pieces"
} }
} }
@@ -474,19 +485,14 @@ static uint16_t writeMapBank(struct SortedSections const *sectList,
uint16_t bankEndAddr = sectionTypeInfo[type].startAddr + sectionTypeInfo[type].size; uint16_t bankEndAddr = sectionTypeInfo[type].startAddr + sectionTypeInfo[type].size;
if (prevEndAddr < bankEndAddr) {
uint16_t empty = bankEndAddr - prevEndAddr;
fprintf(mapFile, "\tEMPTY: $%04" PRIx16 " byte%s\n", empty,
empty == 1 ? "" : "s");
}
if (used == 0) { if (used == 0) {
fputs(" EMPTY\n\n", mapFile); fputs("\tEMPTY\n\n", mapFile);
} else { } else {
writeEmptySpace(prevEndAddr, bankEndAddr);
uint16_t slack = sectionTypeInfo[type].size - used; uint16_t slack = sectionTypeInfo[type].size - used;
fprintf(mapFile, "\tSLACK: $%04" PRIx16 " byte%s\n\n", slack, fprintf(mapFile, "\tTOTAL EMPTY: $%04" PRIx16 " byte%s\n\n", slack,
slack == 1 ? "" : "s"); slack == 1 ? "" : "s");
} }

View File

@@ -272,14 +272,12 @@ void sdobj_ReadFile(struct FileStackNode const *where, FILE *file) {
getToken(line, "'A' line is too short"); getToken(line, "'A' line is too short");
assert(strlen(token) != 0); // This should be impossible, tokens are non-empty assert(strlen(token) != 0); // This should be impossible, tokens are non-empty
curSection->name = strdup(token); // We need a pointer that will live longer
if (!curSection->name)
fatal(where, lineNo, "Failed to alloc new area's name: %s", strerror(errno));
// The following is required for fragment offsets to be reliably predicted // The following is required for fragment offsets to be reliably predicted
for (size_t i = 0; i < nbSections; ++i) { for (size_t i = 0; i < nbSections; ++i) {
if (!strcmp(token, fileSections[i].section->name)) if (!strcmp(token, fileSections[i].section->name))
fatal(where, lineNo, "Area \"%s\" already defined earlier", token); fatal(where, lineNo, "Area \"%s\" already defined earlier", token);
} }
char const *sectionName = token; // We'll deal with the section's name depending on type
expectToken("size", 'A'); expectToken("size", 'A');
@@ -299,6 +297,19 @@ void sdobj_ReadFile(struct FileStackNode const *where, FILE *file) {
curSection->isBankFixed = curSection->isAddressFixed; curSection->isBankFixed = curSection->isAddressFixed;
curSection->modifier = curSection->isAddressFixed || (tmp & (1 << AREA_TYPE)) curSection->modifier = curSection->isAddressFixed || (tmp & (1 << AREA_TYPE))
? SECTION_NORMAL : SECTION_FRAGMENT; ? SECTION_NORMAL : SECTION_FRAGMENT;
// If the section is absolute, its name might not be unique; thus, mangle the name
if (curSection->modifier == SECTION_NORMAL) {
size_t len = strlen(where->name) + 1 + strlen(token);
curSection->name = malloc(len + 1);
if (!curSection->name)
fatal(where, lineNo, "Failed to alloc new area's name: %s", strerror(errno));
sprintf(curSection->name, "%s %s", where->name, sectionName);
} else {
curSection->name = strdup(sectionName); // We need a pointer that will live longer
if (!curSection->name)
fatal(where, lineNo, "Failed to alloc new area's name: %s", strerror(errno));
}
expectToken("addr", 'A'); expectToken("addr", 'A');

38
test/fetch-test-deps.sh Executable file
View File

@@ -0,0 +1,38 @@
#!/usr/bin/env bash
set -e
cd "$(dirname "$0")"
case "$1" in
--get-hash)
action() { # owner/repo shallow-since commit
printf "%s@%s-" "${1##*/}" "$3"
}
;;
--get-paths)
action() { # owner/repo shallow-since commit
printf "test/%s," "${1##*/}"
}
;;
*)
echo "Fetching test dependency repositories"
action() { # owner/repo shallow-since commit
if [ ! -d ${1##*/} ]; then
git clone https://github.com/$1.git --shallow-since=$2 --single-branch
fi
pushd ${1##*/}
git checkout -f $3
if [ -f ../patches/${1##*/}.patch ]; then
git apply --ignore-whitespace ../patches/${1##*/}.patch
fi
popd
}
esac
action pret/pokecrystal 2022-09-29 70a3ec1accb6de1c1c273470af0ddfa2edc1b0a9
action pret/pokered 2022-09-29 2b52ceb718b55dce038db24d177715ae4281d065
action AntonioND/ucity 2022-04-20 d8878233da7a6569f09f87b144cb5bf140146a0f

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env bash #!/usr/bin/env bash
[[ -e ./rgbgfx_test ]] || make -C ../.. test/gfx/rgbgfx_test [[ -e ./rgbgfx_test ]] || make -C ../.. test/gfx/rgbgfx_test || exit
[[ -e ./randtilegen ]] || make -C ../.. test/gfx/randtilegen [[ -e ./randtilegen ]] || make -C ../.. test/gfx/randtilegen || exit
trap 'rm -f "$errtmp"' EXIT trap 'rm -f "$errtmp"' EXIT
errtmp="$(mktemp)" errtmp="$(mktemp)"
@@ -12,9 +12,11 @@ red="$(tput setaf 1)"
green="$(tput setaf 2)" green="$(tput setaf 2)"
rescolors="$(tput op)" rescolors="$(tput op)"
RGBGFX=../../rgbgfx
rc=0 rc=0
new_test() { new_test() {
cmdline="${*@Q}" cmdline="$*"
echo "$bold${green}Testing: $cmdline$rescolors$resbold" >&2 echo "$bold${green}Testing: $cmdline$rescolors$resbold" >&2
} }
test() { test() {
@@ -42,14 +44,22 @@ rm -f out*.png result.png
for f in *.png; do for f in *.png; do
flags="$([[ -e "${f%.png}.flags" ]] && echo "@${f%.png}.flags")" flags="$([[ -e "${f%.png}.flags" ]] && echo "@${f%.png}.flags")"
new_test ../../rgbgfx $flags "$f"
new_test "$RGBGFX" $flags "$f"
if [[ -e "${f%.png}.err" ]]; then if [[ -e "${f%.png}.err" ]]; then
test 2>"$errtmp" test 2>"$errtmp"
diff -u --strip-trailing-cr "${f%.png}.err" "$errtmp" || fail diff -u --strip-trailing-cr "${f%.png}.err" "$errtmp" || fail
else else
test || fail $? test || fail $?
fi fi
new_test "$RGBGFX" $flags - "<$f"
if [[ -e "${f%.png}.err" ]]; then
test 2>"$errtmp"
diff -u --strip-trailing-cr <(sed "s/$f/<stdin>/g" "${f%.png}.err") "$errtmp" || fail
else
test || fail $?
fi
done done
exit $rc exit $rc

View File

@@ -25,20 +25,16 @@ done
# When updating subprojects, change the commit being checked out, and set the `shallow-since` # When updating subprojects, change the commit being checked out, and set the `shallow-since`
# to the day before, to reduce the amount of refs being transferred and thus speed up CI. # to the day before, to reduce the amount of refs being transferred and thus speed up CI.
test_downstream() { # owner/repo shallow-since commit make-target test_downstream() { # owner/repo make-target
if [ ! -d ${1##*/} ]; then if ! pushd ${1##*/}; then
git clone https://github.com/$1.git --shallow-since=$2 --single-branch echo >&2 'Please run `fetch-test-deps.sh` before running the test suite'
fi return 1
pushd ${1##*/}
git checkout -f $3
if [ -f ../patches/${1##*/}.patch ]; then
git apply --ignore-whitespace ../patches/${1##*/}.patch
fi fi
make clean make clean
make -j4 $4 RGBDS=../../ make -j4 $2 RGBDS=../../
popd popd
} }
test_downstream pret/pokecrystal 2022-09-29 70a3ec1accb6de1c1c273470af0ddfa2edc1b0a9 compare test_downstream pret/pokecrystal compare
test_downstream pret/pokered 2022-09-29 2b52ceb718b55dce038db24d177715ae4281d065 compare test_downstream pret/pokered compare
test_downstream AntonioND/ucity 2022-04-20 d8878233da7a6569f09f87b144cb5bf140146a0f '' test_downstream AntonioND/ucity ''