Compare commits

..

3 Commits

Author SHA1 Message Date
ISSOtm
bffe7eb4de Implement new instructions
"Who are you? What are you doing in my commit history?"
~ https://xkcd.com/163/
2022-04-01 12:46:52 +02:00
ISSOtm
cd454d2e9a Hack in new register syntax
Oh my god I want to die x_x
2022-04-01 12:46:52 +02:00
ISSOtm
c814a616d6 Port Gan's work to Mandoc format
Hopefully I didn't forget anything
2022-04-01 12:46:52 +02:00
1302 changed files with 24180 additions and 34945 deletions

88
.checkpatch.conf Normal file
View File

@@ -0,0 +1,88 @@
# Configuration for checkpatch.pl
# ===============================
# Enable more tests
--strict
# Quiet
--quiet
# No per-file summary
--no-summary
# Don't expect the Linux kernel tree
--no-tree
# Show file line, not input line
--showfile
# Don't expect SPDX tag in the first line of a file
--ignore SPDX_LICENSE_TAG
# Don't expect Signed-off-by lines in commit messages
--no-signoff
# List of ignored rules
# ---------------------
# There's no BIT macro
--ignore BIT_MACRO
# Don't complain when bools are used in structs
--ignore BOOL_MEMBER
# Allow CamelCase
--ignore CAMELCASE
# Comparing to NULL explicitly isn't a bad thing
--ignore COMPARISON_TO_NULL
# Causes false positives
--ignore COMPLEX_MACRO
# Don't complain about structs not being const
--ignore CONST_STRUCT
# Don't complain about printing "warning:" without the function name, as warning
# printing is relevant to the code being parsed, not RGBDS' code
--ignore EMBEDDED_FUNCTION_NAME
# Do not check the format of commit messages
--ignore GIT_COMMIT_ID
# Do not check for global initializers (this is specific to the kernel)
--ignore GLOBAL_INITIALISERS
# Don't complain about initializing statics (this is specific to the kernel)
--ignore INITIALISED_STATIC
# We don't have a MAINTAINERS file, don't complain about it.
--ignore FILE_PATH_CHANGES
# Writing the continuation on the start of the line can make it clearer
--ignore LOGICAL_CONTINUATIONS
# Don't complain if a line that contains a string is too long. It's better to
# have a really long line that can be found with grep.
--ignore LONG_LINE_STRING
# Don't complain when files are modified in 'include/asm'
--ignore MODIFIED_INCLUDE_ASM
# Allow new typedefs
--ignore NEW_TYPEDEFS
# We allow lines ending with parentheses for the usage prints
--ignore OPEN_ENDED_LINE
# Prefer stdint.h types over kernel types
--ignore PREFER_KERNEL_TYPES
# Don't ask to replace sscanf by kstrto
--ignore SSCANF_TO_KSTRTO
# Parentheses can make the code clearer
--ignore UNNECESSARY_PARENTHESES
# We don't have `fallthrough;` */
--ignore PREFER_FALLTHROUGH

View File

@@ -1,13 +1,13 @@
AccessModifierOffset: -4 AccessModifierOffset: -4
AlignAfterOpenBracket: BlockIndent AlignAfterOpenBracket: Align
AlignArrayOfStructures: Left AlignArrayOfStructures: Left
AlignConsecutiveAssignments: None AlignConsecutiveAssignments: None
AlignConsecutiveBitFields: Consecutive AlignConsecutiveBitFields: Consecutive
AlignConsecutiveDeclarations: None AlignConsecutiveDeclarations: None
AlignConsecutiveMacros: Consecutive AlignConsecutiveMacros: Consecutive
AlignEscapedNewlines: DontAlign AlignEscapedNewlines: Left
AlignOperands: Align AlignOperands: Align
AlignTrailingComments: true AlignTrailingComments: false
AllowShortBlocksOnASingleLine: Empty AllowShortBlocksOnASingleLine: Empty
AllowShortCaseLabelsOnASingleLine: false AllowShortCaseLabelsOnASingleLine: false
AllowShortEnumsOnASingleLine: true AllowShortEnumsOnASingleLine: true
@@ -21,8 +21,8 @@ AlwaysBreakTemplateDeclarations: Yes
AttributeMacros: AttributeMacros:
- format_ - format_
- attr_ - attr_
BinPackArguments: false BinPackArguments: true
BinPackParameters: false BinPackParameters: true
BitFieldColonSpacing: Both BitFieldColonSpacing: Both
BreakBeforeBinaryOperators: NonAssignment BreakBeforeBinaryOperators: NonAssignment
BreakBeforeBraces: Attach BreakBeforeBraces: Attach
@@ -60,8 +60,8 @@ IndentPPDirectives: BeforeHash
IndentRequires: true IndentRequires: true
IndentWidth: 4 IndentWidth: 4
IndentWrappedFunctionNames: true IndentWrappedFunctionNames: true
# Only support for Javascript as of clang-format 14... # Only support for Javascript as of clang-format 13...
# InsertTrailingCommas: Wrapped # InsertTrailingCommas: true
KeepEmptyLinesAtTheStartOfBlocks: false KeepEmptyLinesAtTheStartOfBlocks: false
LambdaBodyIndentation: Signature LambdaBodyIndentation: Signature
Language: Cpp Language: Cpp
@@ -69,7 +69,6 @@ MaxEmptyLinesToKeep: 1
NamespaceIndentation: None NamespaceIndentation: None
PPIndentWidth: -1 PPIndentWidth: -1
PointerAlignment: Right PointerAlignment: Right
QualifierAlignment: Right
ReflowComments: true ReflowComments: true
SortIncludes: CaseSensitive SortIncludes: CaseSensitive
SortUsingDeclarations: true SortUsingDeclarations: true
@@ -97,4 +96,4 @@ SpacesInSquareBrackets: false
Standard: c++20 Standard: c++20
TabWidth: 4 TabWidth: 4
UseCRLF: false UseCRLF: false
UseTab: ForIndentation UseTab: AlignWithSpaces

View File

@@ -1,2 +1,7 @@
# This file is part of RGBDS.
#
# Copyright (c) 2018-2019, Phil Smith and RGBDS contributors.
#
# SPDX-License-Identifier: MIT
.git .git
docs docs

16
.gitattributes vendored
View File

@@ -1,18 +1,2 @@
# Shell scripts need Unix line endings (see https://github.com/gbdev/rgbds/issues/841) # Shell scripts need Unix line endings (see https://github.com/gbdev/rgbds/issues/841)
*.sh text eol=lf *.sh text eol=lf
*.bash text eol=lf
# Flags also need Unix line endings (see https://github.com/gbdev/rgbds/issues/955)
*.flags text eol=lf
# Binary files need exact bytes
*.bin binary
*.gb binary
*.1bpp binary
*.2bpp binary
*.pal binary
*.attrmap binary
*.tilemap binary
*.palmap binary
*.patch binary
*.png binary

3
.github/FUNDING.yml vendored
View File

@@ -1,2 +1,3 @@
github: avivace
patreon: gbdev01
open_collective: gbdev open_collective: gbdev
github: gbdev

56
.github/actions/doc_postproc.awk vendored Executable file
View File

@@ -0,0 +1,56 @@
#!/usr/bin/awk -f
/^\s+<td><b class="Sy">.+<\/b><\/td>$/ {
# Assuming that all cells whose contents are bold are heading cells,
# use the HTML tag for those
sub(/td><b class="Sy"/, "th");
sub(/b><\/td/, "th");
}
# The whole page is being generated, so it's not meant to contain any Liquid
BEGIN {
print "{% raw %}"
}
END {
print "{% endraw %}"
}
BEGIN {
in_synopsis = 0
}
/<table class="Nm">/ {
in_synopsis = 1
}
/<\/table>/ {
# Resets synopsis state even when already reset, but whatever
in_synopsis = 0
}
/<code class="Fl">-[a-zA-Z]/ {
# Add links to arg descr in synopsis section
if (in_synopsis) {
while (match($0, /<code class="Fl">-[a-zA-Z]+/)) {
# 123456789012345678 -> 18 chars
optchars = substr($0, RSTART + 18, RLENGTH - 18)
i = length(optchars)
while (i) {
end = RSTART + 18 + i
i -= 1
len = i ? 1 : 2
$0 = sprintf("%s<a href=\"#%s\">%s</a>%s",
substr($0, 0, end - len - 1),
substr($0, end - 1, 1),
substr($0, end - len, len),
substr($0, end))
}
}
}
}
{
# Make long opts (defined using `Fl Fl`) into a single tag
gsub(/<code class="Fl">-<\/code>\s*<code class="Fl">/, "<code class=\"Fl\">-")
}
{
print
}

113
.github/actions/get-pages.sh vendored Executable file
View File

@@ -0,0 +1,113 @@
#!/bin/bash
usage() {
cat <<EOF
Usage: $0 [-h] [-r] <rgbds-www> <version>
Copy renders from RGBDS repository to rgbds-www documentation
Execute from the root folder of the RGBDS repo, checked out at the desired tag
<rgbds-www> : Path to the rgbds-www repository
<version> : Version to be copied, such as 'v0.4.1' or 'master'
-h Display this help message
-r Update "latest stable" redirection pages and add a new entry to the index
(use for releases, not master)
EOF
}
is_release=0
bad_usage=0
while getopts ":hr" opt; do
case $opt in
r)
is_release=1
;;
h)
usage
exit 0
;;
\?)
echo "Unknown option '$OPTARG'"
bad_usage=1
;;
esac
done
if [ $bad_usage -ne 0 ]; then
usage
exit 1
fi
shift $(($OPTIND - 1))
declare -A PAGES
PAGES=(
[rgbasm.1.html]=src/asm/rgbasm.1
[rgbasm.5.html]=src/asm/rgbasm.5
[rgblink.1.html]=src/link/rgblink.1
[rgblink.5.html]=src/link/rgblink.5
[rgbfix.1.html]=src/fix/rgbfix.1
[rgbgfx.1.html]=src/gfx/rgbgfx.1
[rgbds.5.html]=src/rgbds.5
[rgbds.7.html]=src/rgbds.7
[gbz80.7.html]=src/gbz80.7
)
WWWPATH="/docs"
mkdir -p "$1/_documentation/$2"
# `mandoc` uses a different format for referring to man pages present in the **current** directory.
# We want that format for RGBDS man pages, and the other one for the rest;
# we thus need to copy all pages to a temporary directory, and process them there.
# Copy all pages to current dir
cp "${PAGES[@]}" .
for page in "${!PAGES[@]}"; do
stem="${page%.html}"
manpage="${stem%.?}(${stem#*.})"
descr="$(awk -v 'FS=.Nd ' '/.Nd/ { print $2; }' "${PAGES[$page]}")"
cat >"$1/_documentation/$2/$page" <<EOF
---
layout: doc
title: $manpage [$2]
description: RGBDS $2 — $descr
---
EOF
options=fragment,man='%N.%S;https://linux.die.net/man/%S/%N'
if [ $stem = rgbasm.5 ]; then
options+=,toc
fi
mandoc -Thtml -I os=Linux -O$options "${PAGES[$page]##*/}" | .github/actions/doc_postproc.awk >> "$1/_documentation/$2/$page"
groff -Tpdf -mdoc -wall "${PAGES[$page]##*/}" >"$1/_documentation/$2/$stem.pdf"
if [ $is_release -ne 0 ]; then
cat - >"$1/_documentation/$page" <<EOF
---
redirect_to: $WWWPATH/$2/${page%.html}
permalink: $WWWPATH/${page%.html}/
title: $manpage [latest stable]
description: RGBDS latest stable — $descr
---
EOF
fi
done
cat - >"$1/_documentation/$2/index.html" <<EOF
---
layout: doc_index
permalink: /docs/$2/
title: RGBDS online manual [$2]
description: RGBDS $2 - Online manual
---
EOF
# If making a release, add a new entry right after `master`
if [ $is_release -ne 0 ]; then
awk '{ print }
/"name": "master"/ { print "\t\t{\"name\": \"'$2'\", \"text\": \"'$2'\" }," }
' "$1/_data/doc.json" >"$1/_data/doc.json.tmp"
mv "$1/_data/doc.json"{.tmp,}
fi
# Clean up
rm "${PAGES[@]##*/}"

21
.github/actions/install_deps.sh vendored Executable file
View File

@@ -0,0 +1,21 @@
#!/bin/bash
set -e
case "${1%-*}" in
ubuntu)
sudo apt-get -qq update
sudo apt-get install -yq bison libpng-dev pkg-config
;;
macos)
brew install bison libpng pkg-config md5sha1sum
# For the version check below exclusively, re-do this before building
export PATH="/usr/local/opt/bison/bin:$PATH"
;;
*)
echo "WARNING: Cannot install deps for OS '$1'"
;;
esac
bison --version
make --version
cmake --version

17
.github/actions/mingw-configure.sh vendored Normal file
View File

@@ -0,0 +1,17 @@
#!/bin/bash
source mingw-env @TRIPLE@
echo LAST IS: $last
# check if last arg is a path to configure, else use parent
for last; do true; done
if test -x "${last}/configure"; then
config_path="$last"
else
config_path=".."
fi
${config_path}/configure \
--host=@TRIPLE@ --target=@TRIPLE@ --build="$CHOST" \
--prefix=/usr/@TRIPLE@ --libdir=/usr/@TRIPLE@/lib --includedir=/usr/@TRIPLE@/include \
--enable-shared --enable-static "$@"

16
.github/actions/mingw-env.sh vendored Normal file
View File

@@ -0,0 +1,16 @@
#!/bin/sh
_arch=$1
default_mingw_pp_flags="-D_FORTIFY_SOURCE=2"
default_mingw_compiler_flags="$default_mingw_pp_flags -O2 -pipe -fno-plt -fexceptions --param=ssp-buffer-size=4"
default_mingw_linker_flags="-Wl,-O1,--sort-common,--as-needed -fstack-protector"
export CPPFLAGS="${MINGW_CPPFLAGS:-$default_mingw_pp_flags $CPPFLAGS}"
export CFLAGS="${MINGW_CFLAGS:-$default_mingw_compiler_flags $CFLAGS}"
export CXXFLAGS="${MINGW_CXXFLAGS:-$default_mingw_compiler_flags $CXXFLAGS}"
export LDFLAGS="${MINGW_LDFLAGS:-$default_mingw_linker_flags $LDFLAGS}"
mingw_prefix=/usr/${_arch}
export PKG_CONFIG_SYSROOT_DIR="${mingw_prefix}"
export PKG_CONFIG_LIBDIR="${mingw_prefix}/lib/pkgconfig:${mingw_prefix}/share/pkgconfig"

44
.github/actions/mingw-w64-libpng-dev.sh vendored Executable file
View File

@@ -0,0 +1,44 @@
#!/bin/sh
# This script was written by ISSOtm while looking at Arch Linux's PKGBUILD for
# the corresponding package. (And its dependencies)
# https://aur.archlinux.org/packages/mingw-w64-libpng/
set -e
pngver=1.6.37
_apngver=$pngver
_arch="$1"
## Install mingw-configure and mingw-env (both build dependencies)
install -m 755 .github/actions/mingw-env.sh /usr/bin/mingw-env
sed "s|@TRIPLE@|${_arch}|g" .github/actions/mingw-configure.sh > ${_arch}-configure
install -m 755 ${_arch}-configure /usr/bin/
## Grab sources and check them
wget http://downloads.sourceforge.net/sourceforge/libpng/libpng-$pngver.tar.xz
wget http://downloads.sourceforge.net/project/apng/libpng/libpng16/libpng-$_apngver-apng.patch.gz
sha256sum -c .github/actions/mingw-w64-libpng-dev.sha256sums
## Extract sources
tar -xf libpng-$pngver.tar.xz
gunzip libpng-$_apngver-apng.patch.gz
## Start building!
cd libpng-$pngver
# Patch in apng support
patch -p0 ../libpng-$_apngver-apng.patch
mkdir -p build-${_arch}
cd build-${_arch}
${_arch}-configure LDFLAGS=-static-libgcc
make
make install

View File

@@ -0,0 +1,2 @@
10d9e0cb60e2b387a79b355eb7527c0bee2ed8cbd12cf04417cabc4d6976683c libpng-1.6.37-apng.patch.gz
505e70834d35383537b6491e7ae8641f1a4bed1876dbfe361201fc80868d88ca libpng-1.6.37.tar.xz

View File

@@ -1,27 +0,0 @@
#!/bin/bash
set -euo pipefail
pngver=1.6.43
## Grab sources and check them
curl -LOJ "http://prdownloads.sourceforge.net/libpng/libpng-$pngver.tar.xz?download"
# Brew doesn't provide any sha256sum, so we're making do with `sha2` instead.
if [ "$(sha2 -q -256 libpng-$pngver.tar.xz)" != 6a5ca0652392a2d7c9db2ae5b40210843c0bbc081cbd410825ab00cc59f14a6c ]; then
sha2 -256 libpng-$pngver.tar.xz
echo Checksum mismatch! Aborting. >&2
exit 1
fi
## Extract sources and patch them
tar -xvf libpng-$pngver.tar.xz
## Start building!
mkdir -p build
cd build
../libpng-$pngver/configure --disable-shared --enable-static \
CFLAGS="-O3 -flto -DNDEBUG -mmacosx-version-min=10.9 -arch x86_64 -arch arm64 -fno-exceptions"
make -kj
make install prefix="$PWD/../libpng-staging"

View File

@@ -1,23 +0,0 @@
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/zlib131.zip' 'zlib.zip' '72af66d44fcc14c22013b46b814d5d2514673dda3d115e64b690c1ad636e7b17' .
getlibrary 'https://github.com/glennrp/libpng/archive/refs/tags/v1.6.43.zip' 'libpng.zip' '5e18474a26814ae479e02ca6432da32d19dc6e615551d140c954a68d63b3f192' .
getlibrary 'https://github.com/lexxmark/winflexbison/releases/download/v2.5.25/win_flex_bison-2.5.25.zip' 'winflexbison.zip' '8d324b62be33604b2c45ad1dd34ab93d722534448f55a16ca7292de32b6ac135' install_dir
Move-Item zlib-1.3.1 zlib
Move-Item libpng-1.6.43 libpng

View File

@@ -1,7 +0,0 @@
#!/usr/bin/env 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 rgbasm-old.5 /usr/local/share/man/man5/
install -m 644 rgbds.7 gbz80.7 /usr/local/share/man/man7/

View File

@@ -1,23 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
case "${1%-*}" in
ubuntu)
sudo apt-get -qq update
sudo apt-get install -yq bison libpng-dev pkg-config
;;
macos)
brew install bison sha2 md5sha1sum
# Export `bison` to allow using the version we install from Homebrew,
# instead of the outdated one preinstalled on macOS (which doesn't even support `-Wall`...)
export PATH="/opt/homebrew/opt/bison/bin:$PATH"
printf 'PATH=%s\n' "$PATH" >>"$GITHUB_ENV" # Make it available to later CI steps too
;;
*)
echo "WARNING: Cannot install deps for OS '$1'"
;;
esac
bison --version
make --version
cmake --version

View File

@@ -1,33 +0,0 @@
#!/bin/bash
set -euo pipefail
pngver=1.6.43
arch="$1"
## Grab sources and check them
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
sha256sum -c .github/scripts/mingw-w64-libpng-dev.sha256sums
## Extract sources and patch them
tar -xf libpng-$pngver.tar.xz
gunzip libpng-$pngver-apng.patch.gz
# Patch in apng support
env -C libpng-$pngver patch -p0 ../libpng-$pngver-apng.patch
## Start building!
mkdir -p build
cd build
../libpng-$pngver/configure \
--host="$arch" --target="$arch" \
--prefix="/usr/$arch" \
--enable-shared --disable-static \
CPPFLAGS="-D_FORTIFY_SOURCE=2" \
CFLAGS="-O2 -pipe -fno-plt -fno-exceptions --param=ssp-buffer-size=4" \
LDFLAGS="-Wl,-O1,--sort-common,--as-needed -fstack-protector"
make -kj
sudo make install

View File

@@ -1,2 +0,0 @@
d6bd2a3f43f17020918a4c1bd81c1a78111b6f759af9c1d3c754f704a1bf0429 libpng-1.6.43-apng.patch.gz
6a5ca0652392a2d7c9db2ae5b40210843c0bbc081cbd410825ab00cc59f14a6c libpng-1.6.43.tar.xz

View File

@@ -1,51 +0,0 @@
name: Build container image
on:
push:
branches:
- master
tags:
- '*'
jobs:
publish-docker-image:
if: github.repository_owner == 'gbdev'
runs-on: ubuntu-latest
permissions:
packages: write
steps:
- name: Checkout repo
uses: actions/checkout@v4
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push the master container image
if: github.ref == 'refs/heads/master'
run: |
COMMIT_HASH=$(git rev-parse --short HEAD)
sed -i "2i LABEL org.opencontainers.image.description=\"RGBDS container image, containing the git version master:$COMMIT_HASH\"" Dockerfile
docker build . --tag ghcr.io/gbdev/rgbds:master
docker push ghcr.io/gbdev/rgbds:master
- name: Build and push the version-tagged container image
if: startsWith(github.ref, 'refs/tags/')
run: |
TAG_NAME=${GITHUB_REF#refs/tags/}
sed -i "2i LABEL org.opencontainers.image.description=\"RGBDS container image for the release version $TAG_NAME\"" Dockerfile
docker build . --tag ghcr.io/gbdev/rgbds:$TAG_NAME
docker push ghcr.io/gbdev/rgbds:$TAG_NAME
- name: Delete untagged container images
if: github.repository_owner == 'gbdev'
uses: Chizkiyahu/delete-untagged-ghcr-action@v5
with:
# Requires a personal access token with delete:packages permissions
token: ${{ secrets.PAT_TOKEN }}
package_name: 'rgbds'
untagged_only: true
except_untagged_multiplatform: true
owner_type: 'org'

View File

@@ -1,4 +1,4 @@
name: Code coverage checking name: "Code coverage checking"
on: pull_request on: pull_request
jobs: jobs:

25
.github/workflows/checkpatch.yml vendored Normal file
View File

@@ -0,0 +1,25 @@
name: "Code style checking"
on: pull_request
jobs:
checkpatch:
runs-on: ubuntu-latest
steps:
- name: Set up repo
run: |
git clone -b "${{ github.event.pull_request.head.ref }}" "${{ github.event.pull_request.head.repo.clone_url }}" rgbds
cd rgbds
git remote add upstream "${{ github.event.pull_request.base.repo.clone_url }}"
git fetch upstream
- name: Set up checkpatch
working-directory: rgbds
run: |
wget 'https://raw.githubusercontent.com/torvalds/linux/master/scripts/checkpatch.pl'
chmod +x checkpatch.pl
wget 'https://raw.githubusercontent.com/torvalds/linux/master/scripts/const_structs.checkpatch'
wget 'https://raw.githubusercontent.com/torvalds/linux/master/scripts/spelling.txt'
- name: Checkpatch
working-directory: rgbds
run: |
make checkpatch CHECKPATCH=./checkpatch.pl "BASE_REF=${{ github.event.pull_request.base.sha }}" Q= | tee log
if grep -q ERROR: log; then exit 1; else exit 0; fi

View File

@@ -0,0 +1,96 @@
name: "Create release artifacts"
on:
push:
tags:
- v[0-9]*
jobs:
windows:
runs-on: windows-2019
steps:
- uses: actions/checkout@v2
- name: Get version from tag
shell: bash
run: | # Turn "refs/tags/vX.Y.Z" into "X.Y.Z"
VERSION="${{ github.ref }}"
echo "version=${VERSION##*/v}" >> $GITHUB_ENV
- name: Get zlib, libpng and bison
run: | # TODO: use an array
$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
- 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: |
cmake -S libpng -B pngbuild32 -A Win32 -DCMAKE_INSTALL_PREFIX=install_dir -DPNG_SHARED=ON -DPNG_STATIC=ON -DPNG_TESTS=OFF
cmake --build pngbuild32 --config Release
cmake --install pngbuild32
- name: Build 32-bit Windows binaries
run: |
cmake -S . -B build32 -A Win32 -DCMAKE_INSTALL_PREFIX=install_dir -DCMAKE_BUILD_TYPE=Release
cmake --build build32 --config Release
cmake --install build32
- name: Package 32-bit 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 }}-win32.zip"
- name: Build 64-bit zlib
run: | # BUILD_SHARED_LIBS causes the output DLL to be correctly called `zlib1.dll`
cmake -S zlib -B zbuild64 -A x64 -DCMAKE_INSTALL_PREFIX=install_dir -DBUILD_SHARED_LIBS=ON
cmake --build zbuild64 --config Release
cmake --install zbuild64
- name: Build 64-bit libpng
run: |
cmake -S libpng -B pngbuild64 -A x64 -DCMAKE_INSTALL_PREFIX=install_dir -DPNG_SHARED=ON -DPNG_STATIC=ON -DPNG_TESTS=OFF
cmake --build pngbuild64 --config Release
cmake --install pngbuild64
- name: Build 64-bit Windows binaries
run: |
cmake -S . -B build64 -A x64 -DCMAKE_INSTALL_PREFIX=install_dir -DCMAKE_BUILD_TYPE=Release
cmake --build build64 --config Release
cmake --install build64
- name: Package 64-bit 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 }}-win64.zip"
- name: Package sources
run: |
make dist
- name: Release
uses: softprops/action-gh-release@v1
with:
body: |
Please ensure that the three assets below work properly.
Once that's done, replace this text with the changelog, un-draft the release, and update the `release` branch.
By the way, if you forgot to update `include/version.h`, RGBASM's version test is gonna fail in the tag's regression testing! (Use `git push --delete origin <tag>` to delete it)
draft: true # Don't publish the release quite yet...
prerelease: ${{ contains(github.ref, '-rc') }}
files: |
rgbds-${{ env.version }}-win32.zip
rgbds-${{ env.version }}-win64.zip
rgbds-${{ env.version }}.tar.gz
fail_on_unmatched_files: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -1,165 +0,0 @@
name: Create release artifacts
on:
push:
tags:
- v[0-9]*
jobs:
windows:
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
- name: Checkout repo
uses: actions/checkout@v4
- name: Install deps
run: .github/scripts/get_win_deps.ps1
- name: Check libraries cache
id: cache
uses: actions/cache@v4
with:
path: |
zbuild
pngbuild
key: ${{ matrix.arch }}-${{ hashFiles('zlib/**', 'libpng/**') }}
- name: Build zlib
if: steps.cache.outputs.cache-hit != 'true'
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
- name: Install zlib
run: |
cmake --install zbuild
- name: Build libpng
if: steps.cache.outputs.cache-hit != 'true'
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
cmake --build pngbuild --config Release -j
- 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
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@v4
with:
name: win${{ matrix.bits }}
path: rgbds-${{ env.version }}-win${{ matrix.bits }}.zip
macos:
runs-on: macos-14
steps:
- name: Get version from tag
shell: bash
run: | # Turn "refs/tags/vX.Y.Z" into "X.Y.Z"
VERSION="${{ github.ref_name }}"
echo "version=${VERSION#v}" >> $GITHUB_ENV
- name: Checkout repo
uses: actions/checkout@v4
- name: Install deps
shell: bash
run: |
./.github/scripts/install_deps.sh macos
- name: Build libpng
run: |
./.github/scripts/build_libpng.sh
# We force linking libpng statically; the other libs are provided by macOS itself
- name: Build binaries
run: |
make -kj CXXFLAGS="-O3 -flto -DNDEBUG -mmacosx-version-min=10.9 -arch x86_64 -arch arm64" PNGCFLAGS="-I libpng-staging/include" PNGLDLIBS="libpng-staging/lib/libpng.a -lz" Q=
strip rgb{asm,link,fix,gfx}
- name: Package binaries
run: |
zip --junk-paths rgbds-${{ env.version }}-macos.zip rgb{asm,link,fix,gfx} man/* .github/scripts/install.sh
- name: Upload macOS binaries
uses: actions/upload-artifact@v4
with:
name: macos
path: rgbds-${{ env.version }}-macos.zip
linux:
runs-on: ubuntu-20.04 # Oldest supported, for best glibc compatibility.
steps:
- name: Get version from tag
shell: bash
run: | # Turn "refs/tags/vX.Y.Z" into "X.Y.Z"
VERSION="${{ github.ref_name }}"
echo "version=${VERSION#v}" >> $GITHUB_ENV
- name: Checkout repo
uses: actions/checkout@v4
- name: Install deps
shell: bash
run: |
./.github/scripts/install_deps.sh ubuntu-20.04
- name: Build binaries
run: |
make -kj WARNFLAGS="-Wall -Wextra -pedantic -static" PKG_CONFIG="pkg-config --static" Q=
strip rgb{asm,link,fix,gfx}
- name: Package binaries
run: |
tar caf rgbds-${{ env.version }}-linux-x86_64.tar.xz --transform='s#.*/##' rgb{asm,link,fix,gfx} man/* .github/scripts/install.sh
- name: Upload Linux binaries
uses: actions/upload-artifact@v4
with:
name: linux
path: rgbds-${{ env.version }}-linux-x86_64.tar.xz
release:
runs-on: ubuntu-latest
needs: [windows, macos, linux]
permissions:
contents: write
steps:
- name: Get version from tag
shell: bash
run: | # Turn "refs/tags/vX.Y.Z" into "X.Y.Z"
VERSION="${{ github.ref_name }}"
echo "version=${VERSION#v}" >> $GITHUB_ENV
- name: Checkout repo
uses: actions/checkout@v4
- name: Package sources
run: |
make dist Q=
ls
- name: Download Linux binaries
uses: actions/download-artifact@v4
- name: Release
uses: softprops/action-gh-release@v2
with:
body: |
Please ensure that the packages below work properly.
Once that's done, replace this text with the changelog, un-draft the release, and update the `release` branch.
By the way, if you forgot to update `include/version.hpp`, RGBASM's version test is gonna fail in the tag's regression testing! (Use `git push --delete origin <tag>` to delete it)
draft: true # Don't publish the release quite yet...
prerelease: ${{ contains(github.ref, '-rc') }}
files: |
win32/rgbds-${{ env.version }}-win32.zip
win64/rgbds-${{ env.version }}-win64.zip
macos/rgbds-${{ env.version }}-macos.zip
linux/rgbds-${{ env.version }}-linux-x86_64.tar.xz
rgbds-${{ env.version }}.tar.gz
fail_on_unmatched_files: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -1,4 +1,4 @@
name: Create release docs name: "Create release docs"
on: on:
release: release:
types: types:
@@ -7,26 +7,32 @@ on:
jobs: jobs:
build: build:
if: github.repository_owner == 'gbdev' if: github.repository_owner == 'gbdev'
runs-on: ubuntu-latest runs-on: ubuntu-18.04
steps: steps:
- name: Checkout rgbds@release - name: Checkout rgbds@release
uses: actions/checkout@v4 uses: actions/checkout@v2
with: with:
path: rgbds path: rgbds
- name: Checkout rgbds-www@master - name: Checkout rgbds-www@master
uses: actions/checkout@v4 uses: actions/checkout@v2
with: with:
repository: ${{ github.repository_owner }}/rgbds-www repository: ${{ github.repository_owner }}/rgbds-www
path: rgbds-www path: rgbds-www
- name: Install groff and mandoc # `-O toc` was added in 1.14.5, but the repos only have 1.14.4
- name: Build and install mandoc + install groff
run: | run: |
sudo apt-get -qq update sudo apt-get -qq update
sudo apt-get install -yq groff mandoc sudo apt-get install -yq groff zlib1g-dev
wget 'http://mandoc.bsd.lv/snapshots/mandoc-1.14.5.tar.gz'
tar xf mandoc-1.14.5.tar.gz
cd mandoc-1.14.5
./configure
make
sudo make install
- name: Update pages - name: Update pages
working-directory: rgbds/man working-directory: rgbds
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/maintainer/man_to_html.sh ${GITHUB_REF##*/} * ./.github/actions/get-pages.sh -r ../rgbds-www ${GITHUB_REF##*/}
../../rgbds-www/maintainer/new_release.sh ${GITHUB_REF##*/}
- name: Push new pages - name: Push new pages
working-directory: rgbds-www working-directory: rgbds-www
run: | run: |

View File

@@ -1,133 +1,64 @@
name: Regression testing name: "Regression testing"
on: on:
- push - push
- pull_request - pull_request
jobs: jobs:
unix: unix-testing:
strategy: strategy:
matrix: matrix:
os: [ubuntu-20.04, ubuntu-22.04, macos-14] os: [ubuntu-20.04, ubuntu-18.04, macos-11.0, macos-10.15]
cxx: [g++, clang++] cc: [gcc, clang]
buildsys: [make, cmake] buildsys: [make, cmake]
exclude: exclude:
# Don't use `g++` on macOS; it's just an alias to `clang++`. # `gcc` is just an alias to `clang` on macOS, don't bother
- os: macos-14 - os: macos-10.15
cxx: g++ cc: gcc
- os: macos-11.0
cc: gcc
fail-fast: false fail-fast: false
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- name: Checkout repo - uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Install deps - name: Install deps
shell: bash shell: bash
run: | run: |
./.github/scripts/install_deps.sh ${{ matrix.os }} ./.github/actions/install_deps.sh ${{ matrix.os }}
# The `export` lines are to allow working on macOS...
# Apple's base version is severely outdated, not even supporting -Wall,
# but it overrides Homebrew's version nonetheless...
- name: Build & install using Make - name: Build & install using Make
if: matrix.buildsys == 'make'
run: | run: |
make develop -kj Q= CXX=${{ matrix.cxx }} export PATH="/usr/local/opt/bison/bin:$PATH"
make develop -j Q= CC=${{ matrix.cc }}
sudo make install -j Q= sudo make install -j Q=
if: matrix.buildsys == 'make'
- name: Build & install using CMake - name: Build & install using CMake
run: |
export PATH="/usr/local/opt/bison/bin:$PATH"
cmake -S . -B build -DCMAKE_VERBOSE_MAKEFILE=ON -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=${{ matrix.cc }} -DSANITIZERS=ON -DMORE_WARNINGS=ON
cmake --build build -j
cp build/src/rgb{asm,link,fix,gfx} .
sudo cmake --install build
if: matrix.buildsys == 'cmake' if: matrix.buildsys == 'cmake'
run: |
cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_COMPILER=${{ matrix.cxx }} -DSANITIZERS=ON -DMORE_WARNINGS=ON
cmake --build build -j --verbose
sudo cmake --install build --verbose
- name: Package binaries - name: Package binaries
run: | run: |
mkdir bins mkdir bins
cp rgb{asm,link,fix,gfx} bins cp rgb{asm,link,fix,gfx} bins
- name: Upload binaries - name: Upload binaries
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v1
with: with:
name: rgbds-canary-${{ matrix.os }}-${{ matrix.cxx }}-${{ matrix.buildsys }} name: rgbds-canary-${{ matrix.os }}-${{ matrix.cc }}-${{ matrix.buildsys }}
path: bins path: bins
- name: Compute test dependency cache params - name: Test
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@v4
with:
path: ${{ fromJSON(steps.test-deps-cache-params.outputs.paths) }}
key: ${{ matrix.os }}-${{ steps.test-deps-cache-params.outputs.hash }}
- name: Fetch test dependency repositories
if: steps.test-deps-cache.outputs.cache-hit != 'true'
continue-on-error: true
run: |
test/fetch-test-deps.sh
- name: Install test dependency dependencies
shell: bash
run: |
test/fetch-test-deps.sh --get-deps ${{ matrix.os }}
- name: Run tests
shell: bash
run: |
CXX=${{ matrix.cxx }} test/run-tests.sh
macos-static:
runs-on: macos-14
steps:
- name: Checkout repo
uses: actions/checkout@v4
- name: Install deps
shell: bash
run: |
./.github/scripts/install_deps.sh macos
- name: Build libpng
run: |
./.github/scripts/build_libpng.sh
- name: Build & install
run: |
make -kj CXXFLAGS="-O3 -flto -DNDEBUG -mmacosx-version-min=10.9 -arch x86_64 -arch arm64" PNGCFLAGS="-I libpng-staging/include" PNGLDLIBS="libpng-staging/lib/libpng.a -lz" Q=
- name: Package binaries
run: |
mkdir bins
cp rgb{asm,link,fix,gfx} bins
- name: Upload binaries
uses: actions/upload-artifact@v4
with:
name: rgbds-canary-macos-static
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@v4
with:
path: ${{ fromJSON(steps.test-deps-cache-params.outputs.paths) }}
key: ${{ matrix.os }}-${{ steps.test-deps-cache-params.outputs.hash }}
- name: Fetch test dependency repositories
if: steps.test-deps-cache.outputs.cache-hit != 'true'
continue-on-error: true
run: |
test/fetch-test-deps.sh
- name: Install test dependency dependencies
shell: bash
run: |
test/fetch-test-deps.sh --get-deps macos
- name: Run tests
shell: bash shell: bash
run: | run: |
test/run-tests.sh test/run-tests.sh
windows: windows-testing:
strategy: strategy:
matrix: matrix:
bits: [32, 64] bits: [32, 64]
os: [windows-2019, windows-2022]
include: include:
- bits: 32 - bits: 32
arch: x86 arch: x86
@@ -136,88 +67,70 @@ jobs:
arch: x86_x64 arch: x86_x64
platform: x64 platform: x64
fail-fast: false fail-fast: false
runs-on: ${{ matrix.os }} runs-on: windows-2019
steps: steps:
- name: Checkout repo - uses: actions/checkout@v2
uses: actions/checkout@v4 - name: Get zlib, libpng and bison
- name: Install deps run: | # TODO: use an array
run: .github/scripts/get_win_deps.ps1 $wc = New-Object System.Net.WebClient
- name: Check libraries cache $wc.DownloadFile('https://www.zlib.net/zlib1212.zip', 'zlib.zip')
id: cache $hash = (Get-FileHash "zlib.zip" -Algorithm SHA256).Hash
uses: actions/cache@v4 if ($hash -ne '173e89893dcb8b4a150d7731cd72f0602f1d6b45e60e2a54efdf7f3fc3325fd7') {
with: Write-Host "zlib SHA256 mismatch! ($hash)"
path: | exit 1
zbuild }
pngbuild $wc.DownloadFile('https://download.sourceforge.net/libpng/lpng1637.zip', 'libpng.zip')
key: ${{ matrix.arch }}-${{ hashFiles('zlib/**', 'libpng/**') }} $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 zlib - name: Build zlib
if: steps.cache.outputs.cache-hit != 'true'
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 }} -Wno-dev -DCMAKE_INSTALL_PREFIX=install_dir -DBUILD_SHARED_LIBS=ON cmake -S zlib -B zbuild -A ${{ matrix.platform }} -DCMAKE_INSTALL_PREFIX=install_dir -DBUILD_SHARED_LIBS=ON
cmake --build zbuild --config Release -j cmake --build zbuild --config Release -j
- name: Install zlib
run: |
cmake --install zbuild cmake --install zbuild
- name: Build libpng - name: Build libpng
if: steps.cache.outputs.cache-hit != 'true'
shell: bash
run: | 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 cmake -S libpng -B pngbuild -A ${{ matrix.platform }} -DCMAKE_INSTALL_PREFIX=install_dir -DPNG_SHARED=ON -DPNG_STATIC=ON -DPNG_TESTS=OFF
cmake --build pngbuild --config Release -j cmake --build pngbuild --config Release -j
- name: Install libpng
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
cmake --build build --config Release -j --verbose cmake --build build --config Release -j
cmake --install build --verbose --prefix install_dir cmake --install build
- name: Package binaries - name: Package binaries
shell: bash shell: bash
run: | run: |
mkdir bins mkdir bins
cp install_dir/bin/{rgbasm.exe,rgblink.exe,rgbfix.exe,rgbgfx.exe,zlib1.dll,libpng16.dll} bins cp install_dir/bin/{rgbasm.exe,rgblink.exe,rgbfix.exe,rgbgfx.exe,zlib1.dll,libpng16.dll} bins
- name: Upload Windows binaries - name: Upload Windows binaries
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v1
with: with:
name: rgbds-canary-w${{ matrix.bits }}-${{ matrix.os }} name: rgbds-canary-win${{ matrix.bits }}
path: bins path: bins
- name: Compute test dependency cache params - name: Test
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@v4
with:
path: ${{ fromJSON(steps.test-deps-cache-params.outputs.paths) }}
key: ${{ matrix.os }}-${{ matrix.bits }}-${{ steps.test-deps-cache-params.outputs.hash }}
- name: Fetch test dependency repositories
if: steps.test-deps-cache.outputs.cache-hit != 'true'
shell: bash
continue-on-error: true
run: |
test/fetch-test-deps.sh
- name: Install test dependency dependencies
shell: bash
run: |
test/fetch-test-deps.sh --get-deps ${{ matrix.os }}
- name: Run tests
shell: bash shell: bash
run: | run: |
cp bins/* . cp bins/* .
cp bins/*.dll test/gfx
test/run-tests.sh test/run-tests.sh
windows-mingw-build: windows-xbuild:
strategy: strategy:
matrix: matrix:
bits: [32, 64] bits: [32, 64]
os: [ubuntu-18.04]
include: include:
- bits: 32 - bits: 32
arch: i686 arch: i686
@@ -226,96 +139,58 @@ jobs:
arch: x86-64 arch: x86-64
triplet: x86_64-w64-mingw32 triplet: x86_64-w64-mingw32
fail-fast: false fail-fast: false
runs-on: ubuntu-22.04 runs-on: ${{ matrix.os }}
env: env:
DIST_DIR: win${{ matrix.bits }} DIST_DIR: win${{ matrix.bits }}
steps: steps:
- name: Checkout repo - uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Install deps - name: Install deps
shell: bash shell: bash
run: | run: |
./.github/scripts/install_deps.sh ubuntu ./.github/actions/install_deps.sh ${{ matrix.os }}
- name: Install MinGW - name: Install MinGW
run: | # dpkg-dev is apparently required for pkg-config for cross-building run: |
sudo apt-get install g++-mingw-w64-${{ matrix.arch }}-win32 mingw-w64-tools libz-mingw-w64-dev dpkg-dev sudo apt-get install gcc-mingw-w64-${{ matrix.arch }} mingw-w64-tools libz-mingw-w64-dev
- name: Install libpng dev headers for MinGW - name: Install libpng dev headers for MinGW
run: | run: |
./.github/scripts/mingw-w64-libpng-dev.sh ${{ matrix.triplet }} sudo ./.github/actions/mingw-w64-libpng-dev.sh ${{ matrix.triplet }}
- name: Cross-build Windows binaries - name: Cross-build Windows binaries
run: | run: |
make mingw${{ matrix.bits }} -kj Q= make mingw${{ matrix.bits }} -j Q=
- name: Package binaries - name: Package binaries
run: | # DLL dependencies can be figured out using e.g. Dependency Walker or objdump -p run: |
mkdir bins mkdir bins
mv -v rgb{asm,link,fix,gfx}.exe bins/ mv rgbasm bins/rgbasm.exe
cp -v /usr/${{ matrix.triplet }}/lib/zlib1.dll bins mv rgblink bins/rgblink.exe
cp -v /usr/${{ matrix.triplet }}/bin/libpng16-16.dll bins mv rgbfix bins/rgbfix.exe
cp -v /usr/lib/gcc/${{ matrix.triplet }}/10-win32/lib{ssp-0,stdc++-6}.dll bins mv rgbgfx bins/rgbgfx.exe
[ "${{ matrix.bits }}" -ne 32 ] || cp -v /usr/lib/gcc/${{ matrix.triplet }}/10-win32/libgcc_s_dw2-1.dll bins cp /usr/${{ matrix.triplet }}/lib/zlib1.dll bins
cp /usr/${{ matrix.triplet }}/bin/libpng16-16.dll bins
if [ ${{ matrix.bits }} -eq 32 ]; then cp /usr/lib/gcc/${{ matrix.triplet }}/7.3-win32/libgcc_s_sjlj-1.dll bins; fi
- name: Upload Windows binaries - name: Upload Windows binaries
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v1
with: with:
name: rgbds-canary-mingw-win${{ matrix.bits }} name: rgbds-canary-mingw-win${{ matrix.bits }}
path: bins path: bins
- name: Upload Windows test binaries
uses: actions/upload-artifact@v4
with:
name: testing-programs-mingw-win${{ matrix.bits }}
path: |
test/gfx/randtilegen.exe
test/gfx/rgbgfx_test.exe
windows-mingw-testing: windows-xtesting:
needs: windows-mingw-build needs: windows-xbuild
strategy: strategy:
matrix: matrix:
os: [windows-2019, windows-2022]
bits: [32, 64] bits: [32, 64]
fail-fast: false fail-fast: false
runs-on: ${{ matrix.os }} runs-on: windows-2019
steps: steps:
- name: Checkout repo - uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Retrieve binaries - name: Retrieve binaries
uses: actions/download-artifact@v4 uses: actions/download-artifact@v1
with: with:
name: rgbds-canary-mingw-win${{ matrix.bits }} name: rgbds-canary-mingw-win${{ matrix.bits }}
path: bins path: bins
- name: Retrieve test binaries
uses: actions/download-artifact@v4
with:
name: testing-programs-mingw-win${{ matrix.bits }}
path: test/gfx
- name: Extract binaries - name: Extract binaries
shell: bash shell: bash
run: | run: |
cp bins/* . cp bins/* .
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@v4
with:
path: ${{ fromJSON(steps.test-deps-cache-params.outputs.paths) }}
key: mingw-${{ matrix.bits }}-${{ steps.test-deps-cache-params.outputs.hash }}
- name: Fetch test dependency repositories
if: steps.test-deps-cache.outputs.cache-hit != 'true'
shell: bash
continue-on-error: true
run: |
test/fetch-test-deps.sh
- name: Install test dependency dependencies
shell: bash
run: |
test/fetch-test-deps.sh --get-deps ${{ matrix.os }}
- name: Run tests - name: Run tests
shell: bash shell: bash
run: | run: |

View File

@@ -1,45 +1,51 @@
name: Update master docs name: "Update master docs"
on: on:
push: push:
branches: branches:
- master - master
paths: paths:
- man/gbz80.7 - .github/actions/get-pages.sh
- man/rgbds.5 - src/gbz80.7
- man/rgbds.7 - src/rgbds.5
- man/rgbasm.1 - src/rgbds.7
- man/rgbasm.5 - src/asm/rgbasm.1
- man/rgbasm-old.5 - src/asm/rgbasm.5
- man/rgblink.1 - src/link/rgblink.1
- man/rgblink.5 - src/link/rgblink.5
- man/rgbfix.1 - src/fix/rgbfix.1
- man/rgbgfx.1 - src/gfx/rgbgfx.1
jobs: jobs:
build: build:
if: github.repository_owner == 'gbdev' if: github.repository_owner == 'gbdev'
runs-on: ubuntu-latest runs-on: ubuntu-18.04
steps: steps:
- name: Checkout rgbds@master - name: Checkout rgbds@master
uses: actions/checkout@v4 uses: actions/checkout@v2
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@v4 uses: actions/checkout@v2
with: with:
repository: gbdev/rgbds-www repository: gbdev/rgbds-www
ref: master ref: master
path: rgbds-www path: rgbds-www
- name: Install groff and mandoc - name: Build and install mandoc + install groff
run: | run: |
sudo apt-get -qq update sudo apt-get -qq update
sudo apt-get install -yq groff mandoc sudo apt-get install -yq groff zlib1g-dev
wget 'http://mandoc.bsd.lv/snapshots/mandoc-1.14.5.tar.gz'
tar xf mandoc-1.14.5.tar.gz
cd mandoc-1.14.5
./configure
make
sudo make install
- name: Update pages - name: Update pages
working-directory: rgbds/man working-directory: rgbds
run: | run: |
../../rgbds-www/maintainer/man_to_html.sh master * ./.github/actions/get-pages.sh ../rgbds-www master
- name: Push new pages - name: Push new pages
working-directory: rgbds-www working-directory: rgbds-www
run: | run: |
@@ -50,7 +56,7 @@ jobs:
ssh-add ~/.ssh/id_ed25519 ssh-add ~/.ssh/id_ed25519
git config --global user.name "GitHub Action" git config --global user.name "GitHub Action"
git config --global user.email "community@gbdev.io" git config --global user.email "community@gbdev.io"
git add -A git add .
git commit -m "Update RGBDS master documentation" git commit -m "Update RGBDS master documentation"
if git remote | grep -q origin; then if git remote | grep -q origin; then
git remote set-url origin git@github.com:gbdev/rgbds-www.git git remote set-url origin git@github.com:gbdev/rgbds-www.git

7
.gitignore vendored
View File

@@ -3,15 +3,10 @@
/rgbfix /rgbfix
/rgbgfx /rgbgfx
/rgbshim.sh /rgbshim.sh
/coverage/
*.o *.o
*.exe *.exe
*.dll *.dll
*.gcno .checkpatch-camelcase.*
*.gcda
*.gcov
CMakeCache.txt CMakeCache.txt
CMakeFiles/ CMakeFiles/
cmake_install.cmake cmake_install.cmake
build/
callgrind.out.*

View File

@@ -1,13 +1,16 @@
#
# This file is part of RGBDS.
#
# Copyright (c) 2020 RGBDS contributors.
#
# SPDX-License-Identifier: MIT # SPDX-License-Identifier: MIT
#
# 3.9 required for LTO checks # 3.9 required for LTO checks
# 3.17 optional for CMAKE_CTEST_ARGUMENTS cmake_minimum_required(VERSION 3.9 FATAL_ERROR)
cmake_minimum_required(VERSION 3.9..3.17 FATAL_ERROR)
project(rgbds project(rgbds
LANGUAGES CXX) LANGUAGES C)
include(CTest)
# get real path of source and binary directories # get real path of source and binary directories
get_filename_component(srcdir "${CMAKE_SOURCE_DIR}" REALPATH) get_filename_component(srcdir "${CMAKE_SOURCE_DIR}" REALPATH)
@@ -24,26 +27,13 @@ option(SANITIZERS "Build with sanitizers enabled" OFF) # Ignored on MSVC
option(MORE_WARNINGS "Turn on more warnings" OFF) # Ignored on MSVC option(MORE_WARNINGS "Turn on more warnings" OFF) # Ignored on MSVC
if(MSVC) if(MSVC)
# MSVC's own standard library triggers warning C5105, # MSVC's standard library triggers warning C5105,
# "macro expansion producing 'defined' has undefined behavior". # "macro expansion producing 'defined' has undefined behavior"
# Warning C5030 is about unknown attributes (`[[gnu::ATTR]]`), none of ours being load-bearing. add_compile_options(/std:c11 /W1 /MP /wd5105)
# Warning C4996 is about using POSIX names, which we want to do for portability.
# We also opt into the C++20-conformant preprocessor.
add_compile_options(/MP /wd5105 /wd5030 /wd4996 /Zc:preprocessor)
add_definitions(/D_CRT_SECURE_NO_WARNINGS) add_definitions(/D_CRT_SECURE_NO_WARNINGS)
if(SANITIZERS)
set(SAN_FLAGS /fsanitize=address)
add_compile_options(${SAN_FLAGS})
add_link_options(${SAN_FLAGS})
endif()
else() else()
add_compile_options(-Wall -pedantic) add_compile_options(-Wall -pedantic)
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") add_definitions(-D_POSIX_C_SOURCE=200809L -D_ISOC11_SOURCE)
# C++20 allows macros to take zero variadic arguments, but Clang (aka AppleClang on macOS)
# does not recognize this yet.
add_compile_options(-Wno-gnu-zero-variadic-macro-arguments)
endif()
if(SANITIZERS) if(SANITIZERS)
set(SAN_FLAGS -fsanitize=shift -fsanitize=integer-divide-by-zero set(SAN_FLAGS -fsanitize=shift -fsanitize=integer-divide-by-zero
-fsanitize=unreachable -fsanitize=vla-bound -fsanitize=unreachable -fsanitize=vla-bound
@@ -51,22 +41,22 @@ else()
-fsanitize=object-size -fsanitize=bool -fsanitize=enum -fsanitize=object-size -fsanitize=bool -fsanitize=enum
-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}) link_libraries(${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_CXX_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)
endif() endif()
if(MORE_WARNINGS) if(MORE_WARNINGS)
add_compile_options(-Werror -Wextra add_compile_options(-Werror -Wextra
-Walloc-zero -Wcast-align -Wcast-qual -Wduplicated-branches -Wduplicated-cond -Walloc-zero -Wcast-align -Wcast-qual -Wduplicated-branches -Wduplicated-cond
-Wfloat-equal -Wlogical-op -Wnull-dereference -Wold-style-cast -Wshift-overflow=2 -Wfloat-equal -Winline -Wlogical-op -Wnested-externs -Wnull-dereference
-Wstringop-overflow=4 -Wundef -Wuninitialized -Wunused -Wold-style-definition -Wshift-overflow=2 -Wstrict-overflow=5
-Wshadow # TODO: -Wshadow=compatible-local? -Wstrict-prototypes -Wstringop-overflow=4 -Wundef -Wuninitialized -Wunused
-Wshadow # TODO: -Wshadow=compatible-local ?
-Wformat=2 -Wformat-overflow=2 -Wformat-truncation=1 -Wformat=2 -Wformat-overflow=2 -Wformat-truncation=1
-Wno-format-nonliteral -Wno-strict-overflow -Wno-format-nonliteral # We have a couple of "dynamic" prints
-Wno-unused-but-set-variable # bison's `yynerrs_` is incremented but unused # We do some range checks that are always false on some platforms (GCC, Clang)
-Wno-type-limits -Wno-tautological-constant-out-of-range-compare -Wno-type-limits -Wno-tautological-constant-out-of-range-compare
-Wvla # MSVC does not support VLAs -Wvla # MSVC does not support VLAs
-Wno-unknown-warning-option) # Clang shouldn't diagnose unknown warnings -Wno-unknown-warning-option) # Clang shouldn't diagnose unknown warnings
@@ -78,7 +68,7 @@ endif()
find_program(GIT git) find_program(GIT git)
if(GIT) if(GIT)
execute_process(COMMAND ${GIT} --git-dir=.git describe --tags --dirty --always execute_process(COMMAND ${GIT} describe --tags --dirty --always
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_REV OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE GIT_REV OUTPUT_STRIP_TRAILING_WHITESPACE
ERROR_QUIET) ERROR_QUIET)
@@ -87,24 +77,12 @@ else(GIT)
message(STATUS "Cannot determine RGBDS version (Git not installed), falling back") message(STATUS "Cannot determine RGBDS version (Git not installed), falling back")
endif(GIT) endif(GIT)
find_package(PkgConfig)
if(MSVC OR NOT PKG_CONFIG_FOUND)
# fallback to find_package
# cmake's FindPNG is very fragile; it breaks when multiple versions are installed
# this is most evident on macOS but can occur on Linux too
find_package(PNG REQUIRED)
else()
pkg_check_modules(LIBPNG REQUIRED libpng)
endif()
include_directories("${PROJECT_SOURCE_DIR}/include") include_directories("${PROJECT_SOURCE_DIR}/include")
set(CMAKE_CXX_STANDARD 20) set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True) set(CMAKE_C_STANDARD_REQUIRED True)
add_subdirectory(src) add_subdirectory(src)
set(CMAKE_CTEST_ARGUMENTS "--verbose")
add_subdirectory(test)
# By default, build in Release mode; Debug mode must be explicitly requested # By default, build in Release mode; Debug mode must be explicitly requested
# (You may want to augment it with the options above) # (You may want to augment it with the options above)
@@ -119,20 +97,3 @@ if(CMAKE_BUILD_TYPE STREQUAL "Release")
message(CHECK_FAIL "no") message(CHECK_FAIL "no")
endif() endif()
endif() endif()
set(MANDIR "share/man")
set(man1 "man/rgbasm.1"
"man/rgbfix.1"
"man/rgbgfx.1"
"man/rgblink.1")
set(man5 "man/rgbasm.5"
"man/rgbasm-old.5"
"man/rgblink.5"
"man/rgbds.5")
set(man7 "man/gbz80.7"
"man/rgbds.7")
foreach(SECTION "man1" "man5" "man7")
set(DEST "${MANDIR}/${SECTION}")
install(FILES ${${SECTION}} DESTINATION ${DEST})
endforeach()

View File

@@ -1,190 +0,0 @@
# Contributing
RGBDS was created in the late '90s and has received contributions from several
developers since then. It wouldn't have been possible to get to this point
without their work, and it is always open to the contributions of other people.
## Reporting Bugs
Bug reports are essential to improve RGBDS and they are always welcome. If you
want to report a bug:
1. Make sure that there isn't a similar issue
[already reported](https://github.com/gbdev/rgbds/issues).
2. Figure out a way of reproducing it reliably.
3. If there is a piece of code that triggers the bug, try to reduce it to the
smallest file you can.
4. Create a new [issue](https://github.com/gbdev/rgbds/issues).
Of course, it may not always be possible to give an accurate bug report, but it
always helps to fix it.
## Requesting new features
If you come up with a good idea that could be implemented, you can propose it to
be done.
1. Create a new [issue](https://github.com/gbdev/rgbds/issues).
2. Try to be as accurate as possible. Describe what you need and why you need
it, maybe with examples.
Please understand that the contributors are doing it in their free time, so
simple requests are more likely to catch the interest of a contributor than
complicated ones. If you really need something to be done, and you think you can
implement it yourself, you can always contribute to RGBDS with your own code.
## Contributing code
If you want to contribute with your own code, whether it is to fix a current
issue or to add something that nobody had requested, you should first consider
if your change is going to be small (and likely to be accepted as-is) or big
(and will have to go through some rework).
Big changes will most likely require some discussion, so open an
[issue](https://github.com/gbdev/rgbds/issues) and explain what you want to
do and how you intend to do it. If you already have a prototype, it's always a
good idea to show it. Tests help, too.
If you are going to work on a specific issue that involves a lot of work, it is
always a good idea to leave a message, just in case someone else is interested
but doesn't know that there's someone working on it.
Note that you must contribute all your changes under the MIT License. If you are
just modifying a file, you don't need to do anything (maybe update the copyright
years). If you are adding new files, you need to use the `SPDX-License-Identifier: MIT`
header.
1. Fork this repository.
2. Checkout the `master` branch.
3. Create a new branch to work on. You could still work on `master`, but it's
easier that way.
4. Compile your changes with `make develop` instead of just `make`. This
target checks for additional warnings. Your patches shouldn't introduce any
new warning (but it may be possible to remove some warning checks if it makes
the code much easier).
5. Test your changes by running `./run-tests.sh` in the `test` directory.
(You must run `./fetch-test-deps.sh` first; if you forget to, the test suite will fail and remind you mid-way.)
5. Format your changes according to `clang-format`, which will reformat the
coding style according to our standards defined in `.clang-format`.
6. Create a pull request against the branch `master`.
7. Be prepared to get some comments about your code and to modify it. Tip: Use
`git rebase -i origin/master` to modify chains of commits.
## Adding a test
The test suite is a little ad-hoc, so the way tests work is different for each program being tested.
Feel free to modify how the test scripts work, if the thing you want to test doesn't fit the existing scheme(s).
### RGBASM
Each `.asm` file corresponds to one test.
RGBASM will be invoked on the `.asm` file with all warnings enabled.
If a `.out` file exists, RGBASM's output (`print`, `println`, etc.) must match its contents.
If a `.err` file exists, RGBASM's error output (`warn`, errors, etc.) must match its contents.
If a `.out.bin` file exists, the object file will be linked, and the generated ROM truncated to the length of the `.out.bin` file.
After that, the ROM must match the `.out.bin` file.
### RGBLINK
Each `.asm` file corresponds to one test, or one *set* of tests.
All tests begin by assembling the `.asm` file into an object file, which will be linked in various ways depending on the test.
#### Simple tests
These simply check that RGBLINK's output matches some expected output.
A `.out` file **must** exist, and RGBLINK's output must match that file's contents.
Additionally, if a `.out.bin` file exists, the `.gb` file generated by RGBLINK must match it.
#### Linker script tests
These allow applying various linker scripts to the same object file.
If one or more `.link` files exist, whose names start the same as the `.asm` file, then each of those files correspond to one test.
Each `.link` linker script **must** be accompanied by a `.out` file, and RGBLINK's output must match that file's contents when passed the corresponding linker script.
#### Variant tests
These allow testing RGBLINK's `-d`, `-t`, and `-w` flags.
If one or more <code>-<var>&lt;flag&gt;</var>.out</code> or <code>-no-<var>&lt;flag&gt;</var>.out</code> files exist, then each of them corresponds to one test.
The object file will be linked with and without said flag, respectively; and in each case, RGBLINK's output must match the `.out` file's contents.
### RGBFIX
Each `.flags` file corresponds to one test.
Each one is a text file whose first line contains flags to pass to RGBFIX.
(There may be more lines, which will be ignored; they can serve as comments to explain what the test is about.)
RGBFIX will be invoked on the `.bin` file if it exists, or else on default-input.bin.
If no `.err` file exists, RGBFIX is simply expected to be able to process the file normally.
If one *does* exist, RGBFIX's return status is ignored, but its output **must** match the `.err` file's contents.
Additionally, if a `.gb` file exists, the output of RGBFIX must match the `.gb`.
### RGBGFX
There are three kinds of test.
#### Simple tests
Each `.png` file corresponds to one test.
RGBGFX will be invoked on the file.
If a `.flags` file exists, it will be used as part of the RGBGFX invocation (<code>@<var>&lt;file&gt;</var>.flags</code>).
If `.out.1bpp`, `.out.2bpp`, `.out.pal`, `.out.tilemap`, `.out.attrmap`, or `.out.palmap` files exist, RGBGFX will create the corresponding kind of output, which must match the file's contents.
Multiple kinds of output may be tested for the same input.
If no `.err` file exists, RGBGFX is simply expected to be able to process the file normally.
If one *does* exist, RGBGFX's return status is ignored, but its output **must** match the `.err` file's contents.
#### Reverse tests
Each `.1bpp` or `.2bpp` file corresponds to one test.
RGBGFX will be invoked on the file with `-r 1` for reverse mode, then invoked on the output without `-r 1`.
The round-trip output must match the input file's contents.
If a `.flags` file exists, it will be used as part of the RGBGFX invocation (<code>@<var>&lt;file&gt;</var>.flags</code>).
#### Random seed tests
Each `seed*.bin` file corresponds to one test.
Each one is a binary RNG file which is passed to the `rgbgfx_test` program.
### Downstream projects
1. Make sure the downstream project supports <code>make <var>&lt;target&gt;</var> RGBDS=<var>&lt;path/to/RGBDS/&gt;</var></code>.
While the test suite supports any Make target name, only [Make](//gnu.org/software/make) is currently supported, and the Makefile must support a `RGBDS` variable to use a non-system RGBDS directory.
Also, only projects hosted on GitHub are currently supported.
2. Add the project to `test/fetch-test-deps.sh`: add a new `action` line at the bottom, following the existing pattern:
```sh
action <owner> <repo> <date of last commit> <hash of last commit>
```
(The date is used to avoid fetching too much history when cloning the repositories.)
3. Add the project to `test/run-tests.sh`: add a new `test_downstream` line at the bottom, following the existing pattern:
```sh
test_downstream <owner> <repo> <makefile target> <build file> <sha1 hash of build file>
```
## Container images
The CI will [take care](https://github.com/gbdev/rgbds/blob/master/.github/workflows/build-container.yml) of updating the [rgbds container](https://github.com/gbdev/rgbds/pkgs/container/rgbds) image tagged `master`.
When a git tag is pushed, the image is also tagged with that tag.
The image can be built locally and pushed to the GitHub container registry by manually running:
```bash
# e.g. to build and tag as 'master'
docker build . --tag ghcr.io/gbdev/rgbds:master
docker push ghcr.io/gbdev/rgbds:master
```

95
CONTRIBUTING.rst Normal file
View File

@@ -0,0 +1,95 @@
Contributing
============
RGBDS was created in the late '90s and has received contributions from several
developers since then. It wouldn't have been possible to get to this point
without their work, and it is always open to the contributions of other people.
Reporting Bugs
--------------
Bug reports are essential to improve RGBDS and they are always welcome. If you
want to report a bug:
1. Make sure that there isn't a similar issue already reported
`here <https://github.com/rednex/rgbds/issues>`__.
2. Figure out a way of reproducing it reliably.
3. If there is a piece of code that triggers the bug, try to reduce it to the
smallest file you can.
4. Create a new `issue <https://github.com/rednex/rgbds/issues>`__.
Of course, it may not always be possible to give an accurate bug report, but it
always helps to fix it.
Requesting new features
-----------------------
If you come up with a good idea that could be implemented, you can propose it to
be done.
1. Create a new `issue <https://github.com/rednex/rgbds/issues>`__.
2. Try to be as accurate as possible. Describe what you need and why you need
it, maybe with examples.
Please understand that the contributors are doing it in their free time, so
simple requests are more likely to catch the interest of a contributor than
complicated ones. If you really need something to be done, and you think you can
implement it yourself, you can always contribute to RGBDS with your own code.
Contributing code
-----------------
If you want to contribute with your own code, whether it is to fix a current
issue or to add something that nobody had requested, you should first consider
if your change is going to be small (and likely to be accepted as-is) or big
(and will have to go through some rework).
Big changes will most likely require some discussion, so open an
`issue <https://github.com/rednex/rgbds/issues>`__ and explain what you want to
do and how you intend to do it. If you already have a prototype, it's always a
good idea to show it. Tests help, too.
If you are going to work on a specific issue that involves a lot of work, it is
always a good idea to leave a message, just in case someone else is interested
but doesn't know that there's someone working on it.
Note that you must contribute all your changes under the MIT License. If you are
just modifying a file, you don't need to do anything (maybe update the copyright
years). If you are adding new files, you need to use the correct header with the
copyright and the reference to the MIT License.
1. Fork this repository.
2. Checkout the ``master`` branch.
3. Create a new branch to work on. You could still work on ``master``, but it's
easier that way.
4. Compile your changes with ``make develop`` instead of just ``make``. This
target checks for additional warnings. Your patches shouldn't introduce any
new warning (but it may be possible to remove some warning checks if it makes
the code much easier).
5. Follow the Linux kernel coding style, which can be found in the file
``Documentation/process/coding-style.rst`` in the Linux kernel repository.
Note that the coding style isn't written in stone, if there is a good reason
to deviate from it, it should be fine.
6. Download the files ``checkpatch.pl``, ``const_structs.checkpatch`` and
``spelling.txt`` from the folder ``scripts`` in the Linux kernel repository.
7. To use ``checkpatch.pl`` you can use ``make checkpatch``, which will check
the coding style of all patches between the current one and the upstream
code. By default, the Makefile expects the script (and associate files) to be
located in ``../linux/scripts/``, but you can place them anywhere you like as
long as you specify it when executing the command:
``make checkpatch CHECKPATCH=../path/to/folder``.
8. Create a pull request against the branch ``master``.
9. Be prepared to get some comments about your code and to modify it. Tip: Use
``git rebase -i origin/master`` to modify chains of commits.

View File

@@ -1,34 +0,0 @@
# Contributors to RGBDS
## Original author
- Carsten Elton Sørensen &lt;csoren@gmail.com&gt;
## Main contributors
- Justin Lloyd &lt;jlloyd@imf.la&gt;
- Vegard Nossum &lt;vegard.nossum@gmail.com&gt;
- Anthony J. Bentley &lt;anthony@anjbe.name&gt;
- stag019 &lt;stag019@gmail.com&gt;
- Antonio Niño Díaz &lt;antonio_nd@outlook.com&gt;
- Eldred "ISSOtm" Habert &lt;me@eldred.fr&gt;
- Sylvie "Rangi" Oukaour &lt;https://github.com/Rangi42&gt;
## Other contributors
- Ben Hetherington &lt;dev@ben-h.uk&gt;
- Björn Höhrmann &lt;bjoern@hoehrmann.de&gt;
- Christophe Staïesse &lt;chastai@skynet.be&gt;
- David Brotz &lt;dbrotz007@gmail.com&gt;
- Evie &lt;https://evie.gbdev.io&gt;
- James "JL2210" Larrowe &lt;https://github.com/JL2210&gt;
- Maja Kądziołka &lt;github@compilercrim.es&gt;
- The Musl C library &lt;https://musl.libc.org/&gt;
- obskyr &lt;powpowd@gmail.com&gt;
- The OpenBSD Project &lt;http://www.openbsd.org&gt;
- Quint Guvernator &lt;quint@guvernator.net&gt;
- Sanqui &lt;gsanky@gmail.com&gt;
- YamaArashi &lt;shadow962@live.com&gt;
- yenatch &lt;yenatch@gmail.com&gt;
- phs &lt;phil@philhsmith.com&gt;
- jidoc01 &lt;jidoc01@naver.com&gt;

57
CONTRIBUTORS.rst Normal file
View File

@@ -0,0 +1,57 @@
Contributors to RGBDS
=====================
Original author
---------------
- Carsten Elton Sørensen <csoren@gmail.com>
Main contributors
-----------------
- Justin Lloyd <jlloyd@imf.la>
- Vegard Nossum <vegard.nossum@gmail.com>
- Anthony J. Bentley <anthony@anjbe.name>
- stag019 <stag019@gmail.com>
- Antonio Niño Díaz <antonio_nd@outlook.com>
- Eldred "ISSOtm" Habert <eldredhabert0@gmail.com>
- Rangi <http://github.com/Rangi42>
Other contributors
------------------
- Ben Hetherington <dev@ben-h.uk>
- Björn Höhrmann <bjoern@hoehrmann.de>
- Christophe Staïesse <chastai@skynet.be>
- David Brotz <dbrotz007@gmail.com>
- Jakub Kądziołka <kuba@kadziolka.net>
- James "JL2210" Larrowe <https://github.com/JL2210>
- The Musl C library <http://www.musl-libc.org>
- obskyr <powpowd@gmail.com>
- The OpenBSD Project <http://www.openbsd.org>
- Quint Guvernator <quint@guvernator.net>
- Sanqui <gsanky@gmail.com>
- YamaArashi <shadow962@live.com>
- yenatch <yenatch@gmail.com>
- phs <phil@philhsmith.com>
- jidoc01 <jidoc01@naver.com>

View File

@@ -1,14 +1,24 @@
FROM debian:11-slim # This file is part of RGBDS.
LABEL org.opencontainers.image.source=https://github.com/gbdev/rgbds #
ARG version=0.9.0 # Copyright (c) 2018-2019, Phil Smith and RGBDS contributors.
#
# SPDX-License-Identifier: MIT
# docker build -t rgbds:vX.X.X-alpine
FROM alpine:latest
RUN apk add --update \
build-base \
bison \
libpng-dev
COPY . /rgbds
WORKDIR /rgbds WORKDIR /rgbds
RUN make Q='' all
COPY . . FROM alpine:latest
RUN apk add --update \
RUN apt-get update && \ libpng
apt-get install sudo make cmake gcc build-essential -y COPY --from=0 \
/rgbds/rgbasm \
RUN ./.github/scripts/install_deps.sh ubuntu-20.04 /rgbds/rgbfix \
RUN make -j CXXFLAGS="-O3 -flto -DNDEBUG -static" PKG_CONFIG="pkg-config --static" Q= /rgbds/rgblink \
/rgbds/rgbgfx \
RUN tar caf rgbds-${version}-linux-x86_64.tar.xz --transform='s#.*/##' rgbasm rgblink rgbfix rgbgfx man/* .github/scripts/install.sh /bin/

View File

@@ -1,6 +1,6 @@
The MIT License The MIT License
Copyright (c) 1997-2024, Carsten Sørensen and RGBDS contributors. Copyright (c) 1997-2020, Carsten Sorensen and RGBDS contributors.
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to of this software and associated documentation files (the "Software"), to

227
Makefile
View File

@@ -1,9 +1,13 @@
#
# This file is part of RGBDS.
#
# Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
#
# SPDX-License-Identifier: MIT # SPDX-License-Identifier: MIT
#
.SUFFIXES: .SUFFIXES:
.SUFFIXES: .cpp .y .o .SUFFIXES: .h .y .c .o
.PHONY: all clean install checkdiff develop debug profile coverage iwyu mingw32 mingw64 wine-shim dist
# User-defined variables # User-defined variables
@@ -11,10 +15,10 @@ Q := @
PREFIX := /usr/local PREFIX := /usr/local
bindir := ${PREFIX}/bin bindir := ${PREFIX}/bin
mandir := ${PREFIX}/share/man mandir := ${PREFIX}/share/man
SUFFIX :=
STRIP := -s STRIP := -s
BINMODE := 755 BINMODE := 755
MANMODE := 644 MANMODE := 644
CHECKPATCH := ../linux/scripts/checkpatch.pl
# Other variables # Other variables
@@ -23,23 +27,26 @@ PNGCFLAGS := `${PKG_CONFIG} --cflags libpng`
PNGLDFLAGS := `${PKG_CONFIG} --libs-only-L libpng` PNGLDFLAGS := `${PKG_CONFIG} --libs-only-L libpng`
PNGLDLIBS := `${PKG_CONFIG} --libs-only-l libpng` PNGLDLIBS := `${PKG_CONFIG} --libs-only-l libpng`
# Note: if this comes up empty, `version.cpp` will automatically fall back to last release number # Note: if this comes up empty, `version.c` will automatically fall back to last release number
VERSION_STRING := `git --git-dir=.git describe --tags --dirty --always 2>/dev/null` VERSION_STRING := `git describe --tags --dirty --always 2>/dev/null`
WARNFLAGS := -Wall -pedantic -Wno-unknown-warning-option -Wno-gnu-zero-variadic-macro-arguments WARNFLAGS := -Wall -pedantic
# Overridable CXXFLAGS # Overridable CFLAGS
CXXFLAGS ?= -O3 -flto -DNDEBUG CFLAGS ?= -O3 -flto -DNDEBUG
# Non-overridable CXXFLAGS # Non-overridable CFLAGS
REALCXXFLAGS := ${CXXFLAGS} ${WARNFLAGS} -std=c++2a -I include -fno-exceptions -fno-rtti # _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 \
-D_POSIX_C_SOURCE=200809L -D_ISOC11_SOURCE
# Overridable LDFLAGS # Overridable LDFLAGS
LDFLAGS ?= LDFLAGS ?=
# Non-overridable LDFLAGS # Non-overridable LDFLAGS
REALLDFLAGS := ${LDFLAGS} ${WARNFLAGS} -DBUILD_VERSION_STRING=\"${VERSION_STRING}\" REALLDFLAGS := ${LDFLAGS} ${WARNFLAGS} \
-DBUILD_VERSION_STRING=\"${VERSION_STRING}\"
# Wrapper around bison that passes flags depending on what the version supports YFLAGS ?= -Wall
BISON := src/bison.sh
BISON := bison
RM := rm -rf RM := rm -rf
# Used for checking pull requests # Used for checking pull requests
@@ -63,15 +70,16 @@ rgbasm_obj := \
src/asm/rpn.o \ src/asm/rpn.o \
src/asm/section.o \ src/asm/section.o \
src/asm/symbol.o \ src/asm/symbol.o \
src/asm/util.o \
src/asm/warning.o \ src/asm/warning.o \
src/extern/getopt.o \ src/extern/getopt.o \
src/extern/utf8decoder.o \ src/extern/utf8decoder.o \
src/error.o \ src/error.o \
src/hashmap.o \
src/linkdefs.o \ src/linkdefs.o \
src/opmath.o \ src/opmath.o
src/util.o
src/asm/lexer.o src/asm/main.o: src/asm/parser.hpp src/asm/lexer.o src/asm/main.o: src/asm/parser.h
rgblink_obj := \ rgblink_obj := \
src/link/assign.o \ src/link/assign.o \
@@ -80,17 +88,13 @@ rgblink_obj := \
src/link/output.o \ src/link/output.o \
src/link/patch.o \ src/link/patch.o \
src/link/script.o \ src/link/script.o \
src/link/sdas_obj.o \
src/link/section.o \ src/link/section.o \
src/link/symbol.o \ src/link/symbol.o \
src/extern/getopt.o \ src/extern/getopt.o \
src/extern/utf8decoder.o \
src/error.o \ src/error.o \
src/hashmap.o \
src/linkdefs.o \ src/linkdefs.o \
src/opmath.o \ src/opmath.o
src/util.o
src/link/main.o: src/link/script.hpp
rgbfix_obj := \ rgbfix_obj := \
src/fix/main.o \ src/fix/main.o \
@@ -98,69 +102,50 @@ rgbfix_obj := \
src/error.o src/error.o
rgbgfx_obj := \ rgbgfx_obj := \
src/gfx/gb.o \
src/gfx/main.o \ src/gfx/main.o \
src/gfx/pal_packing.o \ src/gfx/makepng.o \
src/gfx/pal_sorting.o \
src/gfx/pal_spec.o \
src/gfx/process.o \
src/gfx/proto_palette.o \
src/gfx/reverse.o \
src/gfx/rgba.o \
src/extern/getopt.o \ src/extern/getopt.o \
src/error.o src/error.o
rgbasm: ${rgbasm_obj} rgbasm: ${rgbasm_obj}
$Q${CXX} ${REALLDFLAGS} -o $@ ${rgbasm_obj} ${REALCXXFLAGS} src/version.cpp -lm $Q${CC} ${REALLDFLAGS} -o $@ ${rgbasm_obj} ${REALCFLAGS} src/version.c -lm
rgblink: ${rgblink_obj} rgblink: ${rgblink_obj}
$Q${CXX} ${REALLDFLAGS} -o $@ ${rgblink_obj} ${REALCXXFLAGS} src/version.cpp $Q${CC} ${REALLDFLAGS} -o $@ ${rgblink_obj} ${REALCFLAGS} src/version.c
rgbfix: ${rgbfix_obj} rgbfix: ${rgbfix_obj}
$Q${CXX} ${REALLDFLAGS} -o $@ ${rgbfix_obj} ${REALCXXFLAGS} src/version.cpp $Q${CC} ${REALLDFLAGS} -o $@ ${rgbfix_obj} ${REALCFLAGS} src/version.c
rgbgfx: ${rgbgfx_obj} rgbgfx: ${rgbgfx_obj}
$Q${CXX} ${REALLDFLAGS} ${PNGLDFLAGS} -o $@ ${rgbgfx_obj} ${REALCXXFLAGS} ${PNGLDLIBS} src/version.cpp $Q${CC} ${REALLDFLAGS} ${PNGLDFLAGS} -o $@ ${rgbgfx_obj} ${REALCFLAGS} src/version.c ${PNGLDLIBS}
test/gfx/randtilegen: test/gfx/randtilegen.cpp
$Q${CXX} ${REALLDFLAGS} ${PNGLDFLAGS} -o $@ $^ ${REALCXXFLAGS} ${PNGCFLAGS} ${PNGLDLIBS}
test/gfx/rgbgfx_test: test/gfx/rgbgfx_test.cpp
$Q${CXX} ${REALLDFLAGS} ${PNGLDFLAGS} -o $@ $^ ${REALCXXFLAGS} ${PNGCFLAGS} ${PNGLDLIBS}
# Rules to process files # Rules to process files
# We want the Bison invocation to pass through our rules, not default ones # We want the Bison invocation to pass through our rules, not default ones
.y.o: .y.o:
.y.cpp: # Bison-generated C files have an accompanying header
$Q${BISON} $@ $< src/asm/parser.h: src/asm/parser.c
# Bison-generated C++ files have an accompanying header
src/asm/parser.hpp: src/asm/parser.cpp
$Qtouch $@
src/link/script.hpp: src/link/script.cpp
$Qtouch $@ $Qtouch $@
# Only RGBGFX uses libpng (POSIX make doesn't support pattern rules to cover all these) src/asm/parser.c: src/asm/parser.y
src/gfx/main.o: src/gfx/main.cpp $QDEFS=; \
$Q${CXX} ${REALCXXFLAGS} ${PNGCFLAGS} -c -o $@ $< add_flag(){ \
src/gfx/pal_packing.o: src/gfx/pal_packing.cpp if src/check_bison_ver.sh $$1 $$2; then \
$Q${CXX} ${REALCXXFLAGS} ${PNGCFLAGS} -c -o $@ $< DEFS="-D$$3 $$DEFS"; \
src/gfx/pal_sorting.o: src/gfx/pal_sorting.cpp fi \
$Q${CXX} ${REALCXXFLAGS} ${PNGCFLAGS} -c -o $@ $< }; \
src/gfx/pal_spec.o: src/gfx/pal_spec.cpp add_flag 3 5 api.token.raw=true; \
$Q${CXX} ${REALCXXFLAGS} ${PNGCFLAGS} -c -o $@ $< add_flag 3 6 parse.error=detailed; \
src/gfx/process.o: src/gfx/process.cpp add_flag 3 0 parse.error=verbose; \
$Q${CXX} ${REALCXXFLAGS} ${PNGCFLAGS} -c -o $@ $< add_flag 3 0 parse.lac=full; \
src/gfx/proto_palette.o: src/gfx/proto_palette.cpp add_flag 3 0 lr.type=ielr; \
$Q${CXX} ${REALCXXFLAGS} ${PNGCFLAGS} -c -o $@ $< echo "DEFS=$$DEFS"; \
src/gfx/reverse.o: src/gfx/reverse.cpp ${BISON} $$DEFS -d ${YFLAGS} -o $@ $<
$Q${CXX} ${REALCXXFLAGS} ${PNGCFLAGS} -c -o $@ $<
src/gfx/rgba.o: src/gfx/rgba.cpp
$Q${CXX} ${REALCXXFLAGS} ${PNGCFLAGS} -c -o $@ $<
.cpp.o: .c.o:
$Q${CXX} ${REALCXXFLAGS} -c -o $@ $< $Q${CC} ${REALCFLAGS} ${PNGCFLAGS} -c -o $@ $<
# Target used to remove all files generated by other Makefile targets # Target used to remove all files generated by other Makefile targets
@@ -170,23 +155,51 @@ clean:
$Q${RM} rgbfix rgbfix.exe $Q${RM} rgbfix rgbfix.exe
$Q${RM} rgbgfx rgbgfx.exe $Q${RM} rgbgfx rgbgfx.exe
$Qfind src/ -name "*.o" -exec rm {} \; $Qfind src/ -name "*.o" -exec rm {} \;
$Qfind . -type f \( -name "*.gcno" -o -name "*.gcda" -o -name "*.gcov" \) -exec rm {} \;
$Q${RM} rgbshim.sh $Q${RM} rgbshim.sh
$Q${RM} src/asm/parser.cpp src/asm/parser.hpp src/asm/stack.hh $Q${RM} src/asm/parser.c src/asm/parser.h
$Q${RM} src/link/script.cpp src/link/script.hpp src/link/stack.hh
$Q${RM} test/gfx/randtilegen test/gfx/rgbgfx_test
# Target used to install the binaries and man pages. # Target used to install the binaries and man pages.
install: all install: all
$Qinstall -d ${DESTDIR}${bindir}/ ${DESTDIR}${mandir}/man1/ ${DESTDIR}${mandir}/man5/ ${DESTDIR}${mandir}/man7/ $Qmkdir -p ${DESTDIR}${bindir}
$Qinstall ${STRIP} -m ${BINMODE} rgbasm ${DESTDIR}${bindir}/rgbasm${SUFFIX} $Qinstall ${STRIP} -m ${BINMODE} rgbasm ${DESTDIR}${bindir}/rgbasm
$Qinstall ${STRIP} -m ${BINMODE} rgblink ${DESTDIR}${bindir}/rgblink${SUFFIX} $Qinstall ${STRIP} -m ${BINMODE} rgbfix ${DESTDIR}${bindir}/rgbfix
$Qinstall ${STRIP} -m ${BINMODE} rgbfix ${DESTDIR}${bindir}/rgbfix${SUFFIX} $Qinstall ${STRIP} -m ${BINMODE} rgblink ${DESTDIR}${bindir}/rgblink
$Qinstall ${STRIP} -m ${BINMODE} rgbgfx ${DESTDIR}${bindir}/rgbgfx${SUFFIX} $Qinstall ${STRIP} -m ${BINMODE} rgbgfx ${DESTDIR}${bindir}/rgbgfx
$Qinstall -m ${MANMODE} man/rgbasm.1 man/rgblink.1 man/rgbfix.1 man/rgbgfx.1 ${DESTDIR}${mandir}/man1/ $Qmkdir -p ${DESTDIR}${mandir}/man1 ${DESTDIR}${mandir}/man5 ${DESTDIR}${mandir}/man7
$Qinstall -m ${MANMODE} man/rgbds.5 man/rgbasm.5 man/rgbasm-old.5 man/rgblink.5 ${DESTDIR}${mandir}/man5/ $Qinstall -m ${MANMODE} src/rgbds.7 ${DESTDIR}${mandir}/man7/rgbds.7
$Qinstall -m ${MANMODE} man/rgbds.7 man/gbz80.7 ${DESTDIR}${mandir}/man7/ $Qinstall -m ${MANMODE} src/gbz80.7 ${DESTDIR}${mandir}/man7/gbz80.7
$Qinstall -m ${MANMODE} src/rgbds.5 ${DESTDIR}${mandir}/man5/rgbds.5
$Qinstall -m ${MANMODE} src/asm/rgbasm.1 ${DESTDIR}${mandir}/man1/rgbasm.1
$Qinstall -m ${MANMODE} src/asm/rgbasm.5 ${DESTDIR}${mandir}/man5/rgbasm.5
$Qinstall -m ${MANMODE} src/fix/rgbfix.1 ${DESTDIR}${mandir}/man1/rgbfix.1
$Qinstall -m ${MANMODE} src/link/rgblink.1 ${DESTDIR}${mandir}/man1/rgblink.1
$Qinstall -m ${MANMODE} src/link/rgblink.5 ${DESTDIR}${mandir}/man5/rgblink.5
$Qinstall -m ${MANMODE} src/gfx/rgbgfx.1 ${DESTDIR}${mandir}/man1/rgbgfx.1
# Target used to check the coding style of the whole codebase.
# `extern/` is excluded, as it contains external code that should not be patched
# to meet our coding style, so applying upstream patches is easier.
# `.y` files aren't checked, unfortunately...
checkcodebase:
$Qfor file in `git ls-files | grep -E '(\.c|\.h)$$' | grep -Ev '(src|include)/extern/'`; do \
${CHECKPATCH} -f "$$file"; \
done
# Target used to check the coding style of the patches from the upstream branch
# to the HEAD. Runs checkpatch once for each commit between the current HEAD and
# the first common commit between the HEAD and origin/master.
# `.y` files aren't checked, unfortunately...
checkpatch:
$QCOMMON_COMMIT=`git merge-base HEAD ${BASE_REF}`; \
for commit in `git rev-list $$COMMON_COMMIT..HEAD`; do \
echo "[*] Analyzing commit '$$commit'"; \
git format-patch --stdout "$$commit~..$$commit" \
-- src include '!src/extern' '!include/extern' \
| ${CHECKPATCH} - || true; \
done
# Target used to check for suspiciously missing changed files. # Target used to check for suspiciously missing changed files.
@@ -199,64 +212,40 @@ checkdiff:
# The rationale for some of the flags is documented in the CMakeLists. # The rationale for some of the flags is documented in the CMakeLists.
develop: develop:
$Q${MAKE} WARNFLAGS="${WARNFLAGS} -Werror -Wextra \ $Qenv ${MAKE} WARNFLAGS="-Werror -Wextra \
-Walloc-zero -Wcast-align -Wcast-qual -Wduplicated-branches -Wduplicated-cond \ -Walloc-zero -Wcast-align -Wcast-qual -Wduplicated-branches -Wduplicated-cond \
-Wfloat-equal -Wlogical-op -Wnull-dereference -Wold-style-cast -Wshift-overflow=2 \ -Wfloat-equal -Winline -Wlogical-op -Wnested-externs -Wold-style-definition \
-Wstringop-overflow=4 -Wundef -Wuninitialized -Wunused -Wshadow \ -Wshift-overflow=2 \
-Wstrict-overflow=5 -Wstrict-prototypes -Wundef -Wuninitialized -Wunused \
-Wshadow \
-Wnull-dereference -Wstringop-overflow=4 \
-Wformat=2 -Wformat-overflow=2 -Wformat-truncation=1 \ -Wformat=2 -Wformat-overflow=2 -Wformat-truncation=1 \
-Wno-format-nonliteral -Wno-strict-overflow -Wno-unused-but-set-variable \ -Wno-format-nonliteral \
-Wno-type-limits -Wno-tautological-constant-out-of-range-compare -Wvla \ -Wno-type-limits -Wno-tautological-constant-out-of-range-compare \
-D_GLIBCXX_ASSERTIONS \ -Wvla \
-Wno-unknown-warning-option \
-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 \
-fsanitize=object-size -fsanitize=bool -fsanitize=enum \ -fsanitize=object-size -fsanitize=bool -fsanitize=enum \
-fsanitize=alignment -fsanitize=null -fsanitize=address" \ -fsanitize=alignment -fsanitize=null -fsanitize=address" \
CXXFLAGS="-ggdb3 -Og -fno-omit-frame-pointer -fno-optimize-sibling-calls" CFLAGS="-ggdb3 -Og -fno-omit-frame-pointer -fno-optimize-sibling-calls"
# This target is used during development in order to more easily debug with gdb.
debug:
$Qenv ${MAKE} \
CXXFLAGS="-ggdb3 -O0 -fno-omit-frame-pointer -fno-optimize-sibling-calls"
# This target is used during development in order to more easily profile with callgrind.
profile:
$Qenv ${MAKE} \
CXXFLAGS="-ggdb3 -O3 -fno-omit-frame-pointer -fno-optimize-sibling-calls"
# This target is used during development in order to inspect code coverage with gcov.
coverage:
$Qenv ${MAKE} \
CXXFLAGS="-ggdb3 -Og --coverage -fno-omit-frame-pointer -fno-optimize-sibling-calls"
# This target is used during development in order to remove unused `#include` headers.
iwyu:
$Qenv ${MAKE} \
CXX="include-what-you-use" \
REALCXXFLAGS="-std=c++2a -I include"
# Targets for the project maintainer to easily create Windows exes. # Targets for the project maintainer to easily create Windows exes.
# This is not for Windows users! # This is not for Windows users!
# If you're building on Windows with Cygwin or MinGW, just follow the Unix # If you're building on Windows with Cygwin or Mingw, just follow the Unix
# install instructions instead. # install instructions instead.
mingw32: mingw32:
$Q${MAKE} all test/gfx/randtilegen test/gfx/rgbgfx_test \ $Q${MAKE} CC=i686-w64-mingw32-gcc BISON=bison \
CXX=i686-w64-mingw32-g++ \ PKG_CONFIG=i686-w64-mingw32-pkg-config -j
CXXFLAGS="-O3 -flto -DNDEBUG -static-libgcc -static-libstdc++" \
PKG_CONFIG="PKG_CONFIG_SYSROOT_DIR=/usr/i686-w64-mingw32 pkg-config"
mingw64: mingw64:
$Q${MAKE} all test/gfx/randtilegen test/gfx/rgbgfx_test \ $Q${MAKE} CC=x86_64-w64-mingw32-gcc BISON=bison \
CXX=x86_64-w64-mingw32-g++ \ PKG_CONFIG=x86_64-w64-mingw32-pkg-config -j
PKG_CONFIG="PKG_CONFIG_SYSROOT_DIR=/usr/x86_64-w64-mingw32 pkg-config"
wine-shim: wine-shim:
$Qecho '#!/usr/bin/env bash' > rgbshim.sh $Qecho '#!/bin/bash' > rgbshim.sh
$Qecho 'WINEDEBUG=-all wine $$0.exe "$${@:1}"' >> rgbshim.sh $Qecho 'WINEDEBUG=-all wine $$0.exe "$${@:1}"' >> rgbshim.sh
$Qchmod +x rgbshim.sh $Qchmod +x rgbshim.sh
$Qln -s rgbshim.sh rgbasm $Qln -s rgbshim.sh rgbasm

161
README.md
View File

@@ -1,161 +0,0 @@
# RGBDS
RGBDS (Rednex Game Boy Development System) is a free assembler/linker package
for the Game Boy and Game Boy Color. It consists of:
- RGBASM (assembler)
- RGBLINK (linker)
- RGBFIX (checksum/header fixer)
- RGBGFX (PNGtoGame Boy graphics converter)
This is a fork of the original RGBDS which aims to make the programs more like
other UNIX tools.
This toolchain is maintained [on GitHub](https://github.com/gbdev/rgbds).
The documentation of this toolchain can be [viewed online](https://rgbds.gbdev.io/docs/).
It is generated from the man pages found in this repository.
The source code of the website itself is on GitHub as well under the repository
[rgbds-www](https://github.com/gbdev/rgbds-www).
If you want to contribute or maintain RGBDS, or you have questions regarding the code, its
organization, etc. you can find the maintainers [on the gbdev community channels](https://gbdev.io/chat)
or via mail at `rgbds at gbdev dot io`.
## 1. Installing RGBDS
The [installation procedure](https://rgbds.gbdev.io/install) is available
online for various platforms. [Building from source](https://rgbds.gbdev.io/install/source)
is possible using `make` or `cmake`; follow the link for more detailed instructions.
```sh
make
sudo make install
```
```sh
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build
cmake --install build
```
Two parameters available when building are a prefix (e.g. to put the executables in a directory)
and a suffix (e.g. to append the version number or commit ID).
```sh
make
sudo make install PREFIX=install_dir/ SUFFIX=-$(git rev-parse --short HEAD)
```
```sh
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DSUFFIX=-$(git rev-parse --short HEAD)
cmake --build build
cmake --install build --prefix install_dir
```
(If you set a `SUFFIX`, it should include the `.exe` extension on Windows.)
## 2. RGBDS Folder Organization
The RGBDS source code file structure is as follows:
```
.
├── .github/
│ ├── scripts/
│ │ └── ...
│ └── workflows/
│ └── ...
├── contrib/
│ ├── zsh_compl/
│ │ └── ...
│ └── ...
├── include/
│ └── ...
├── man/
│ └── ...
├── src/
│ ├── asm/
│ │ └── ...
│ ├── extern/
│ │ └── ...
│ ├── fix/
│ │ └── ...
│ ├── gfx/
│ │ └── ...
│ ├── link/
│ │ └── ...
│ ├── CMakeLists.txt
│ └── ...
├── test/
│ ├── ...
│ └── run-tests.sh
├── .clang-format
├── CMakeLists.txt
├── Dockerfile
├── Makefile
└── README.md
```
- `.github/` - files and scripts related to the integration of the RGBDS codebase with
GitHub.
* `scripts/` - scripts used by workflow files.
* `workflows/` - CI workflow description files.
- `contrib/` - scripts and other resources which may be useful to users and developers of
RGBDS.
* `zsh_compl` contains tab completion scripts for use with zsh. Put them somewhere in
your `fpath`, and they should auto-load.
* `bash_compl` contains tab completion scripts for use with bash. Run them with `source`
somewhere in your `.bashrc`, and they should load every time you open a shell.
- `include/` - header files for the respective source files in `src`.
- `man/` - manual pages.
- `src/` - source code of RGBDS.
* Note that the code unique to each RGBDS tool is stored in its respective subdirectory
(RGBASM's code is in `src/asm/`, for example). `src/extern/` contains code imported from
external sources.
- `test/` - testing framework used to verify that changes to the code don't break or
modify the behavior of RGBDS.
- `.clang-format` - code style for automated C++ formatting with
[`clang-format`](https://clang.llvm.org/docs/ClangFormat.html).
- `Dockerfile` - defines how to build RGBDS with Docker.
## 3. History
- 1996-10-01: Carsten Sørensen (a.k.a. SurfSmurf) releases
[xAsm](http://otakunozoku.com/RGBDSdocs/asm.htm),
[xLink](http://otakunozoku.com/RGBDSdocs/link.htm), and
[RGBFix](http://otakunozoku.com/RGBDSdocs/fix.htm),
a Game Boy SM83 (GBZ80) assembler/linker system for DOS/Win32.
- 1997-07-03: Sørensen releases [ASMotor](http://otakunozoku.com/RGBDSdocs/geninfo.htm),
packaging the three programs together and moving towards making them a
general-purpose target-independent system.
- 1999-08-01: Justin Lloyd (a.k.a. Otaku no Zoku) adapts ASMotor to re-focus
on SM83 assembly/machine code, and releases this version as
[RGBDS](http://otakunozoku.com/rednex-gameboy-development-system/).
- 2009-06-11: Vegard Nossum adapts the code to be more UNIX-like and releases
this version as [rgbds-linux](https://github.com/vegard/rgbds-linux).
- 2010-01-12: Anthony J. Bentley [forks](https://github.com/bentley) Nossum's
repository. The fork becomes the reference implementation of RGBDS.
- 2015-01-18: stag019 begins implementing [RGBGFX](https://github.com/stag019/rgbgfx),
a PNGtoGame Boy graphics converter, for eventual integration into RGBDS.
- 2016-09-05: RGBGFX is [integrated](https://github.com/gbdev/rgbds/commit/c3c31138ddbd8680d4e67957e387f2816798a71b)
into Bentley's repository.
- 2017-02-23: Bentley's repository is moved to the [rednex](https://github.com/rednex)
organization.
- 2018-01-26: The codebase is [relicensed](https://github.com/gbdev/rgbds/issues/128)
under the MIT license.
- 2020-09-15: The repository is [moved](https://github.com/gbdev/rgbds/issues/567)
to the [gbdev](https://github.com/gbdev) organization.
- 2022-05-17: The [rgbds.gbdev.io](https://rgbds.gbdev.io) website for RGBDS
documentation and downloads is published.
## 4. Acknowledgements
RGBGFX generates palettes using algorithms found in the paper
["Algorithms for the Pagination Problem, a Bin Packing with Overlapping Items"](https://arxiv.org/abs/1605.00558)
([GitHub](https://github.com/pagination-problem/pagination), MIT license),
by Aristide Grange, Imed Kacem, and Sébastien Martin.
RGBGFX's color palette was taken from [SameBoy](https://sameboy.github.io), with permission and help
by [LIJI](https://github.com/LIJI32).

128
README.rst Normal file
View File

@@ -0,0 +1,128 @@
RGBDS
=====
RGBDS (Rednex Game Boy Development System) is a free assembler/linker package
for the Game Boy and Game Boy Color. It consists of:
- rgbasm (assembler)
- rgblink (linker)
- rgbfix (checksum/header fixer)
- rgbgfx (PNGtoGame Boy graphics converter)
This is a fork of the original RGBDS which aims to make the programs more like
other UNIX tools.
This toolchain is maintained on `GitHub <https://github.com/rednex/rgbds>`__.
The documentation of this toolchain can be viewed online
`here <https://rgbds.gbdev.io/docs/>`__, it is generated from the man pages
found in this repository.
If you want to contribute or maintain RGBDS, and have questions regarding the code, its organisation, etc. you can find me `on GBDev <https://gbdev.io/chat>`__ or via mail at ``rgbds at eldred dot fr``.
1. Installing RGBDS
-------------------
The `installation procedure <https://rgbds.gbdev.io/install>`__ is available
online for various platforms. `Building from source <https://rgbds.gbdev.io/install/source>`__
is possible using ``make`` or ``cmake``; follow the link for more detailed instructions.
.. code:: sh
make
sudo make install
.. code:: sh
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build
cmake --install build
2. RGBDS Folder Organization
----------------------------
The RGBDS source code file structure somewhat resembles the following:
::
.
├── .github/
│ ├── actions/
│ │ └── ...
│ └── workflows/
│ └── ...
├── contrib/
│ ├── zsh_compl/
│ │ └── ...
│ └── ...
├── include/
│ └── ...
├── src/
│ ├── asm/
│ │ └── ...
│ ├── extern/
│ │ └── ...
│ ├── fix/
│ │ └── ...
│ ├── gfx/
│ │ └── ...
│ ├── link/
│ │ └── ...
│ ├── CMakeLists.txt
│ └── ...
├── test/
│ ├── ...
│ └── run-tests.sh
├── .clang-format
├── CMakeLists.txt
├── Makefile
└── README.rst
.. |clang-format| replace:: ``clang-format``
.. _clang-format: https://clang.llvm.org/docs/ClangFormat.html
- ``.github/`` - files and scripts related to the integration of the RGBDS codebase with
GitHub.
* ``actions/`` - scripts used by workflow files.
* ``workflows/`` - CI workflow description files.
- ``contrib/`` - scripts and other resources which may be useful to users and developers of
RGBDS.
* ``zsh_compl`` contains tab completion scripts for use with zsh. Put them somewhere in your ``fpath``, and they should auto-load.
* ``bash_compl`` contains tab completion scripts for use with bash. Run them with ``source`` somewhere in your ``.bashrc``, and they should load every time you open a shell.
- ``include/`` - header files for each respective C files in `src`.
- ``src/`` - source code and manual pages for RGBDS.
* Note that the code unique to each RGBDS tool is stored in its respective subdirectory
(rgbasm -> ``src/asm/``, for example). ``src/extern/`` contains code imported from external sources.
- ``test/`` - testing framework used to verify that changes to the code don't break or modify the behavior of RGBDS.
- ``.clang-format`` - code style for automated formatting with |clang-format|_. The C code does not currently follow this style, but all C++ code should.
3. History
----------
- Around 1997, Carsten Sørensen (AKA SurfSmurf) writes ASMotor as a
general-purpose assembler/linker system for DOS/Win32
- Around 1999, Justin Lloyd (AKA Otaku no Zoku) adapts ASMotor to read and
produce GBZ80 assembly/machine code, and releases this version as RGBDS.
- 2009, Vegard Nossum adapts the code to be more UNIX-like and releases
this version as rgbds-linux on
`GitHub <https://github.com/vegard/rgbds-linux>`__.
- 2010, Anthony J. Bentley forks that repository. The fork becomes the reference
implementation of rgbds.
- 2017, Bentley's repository is moved to a neutral name.
- 2018, codebase relicensed under the MIT license.
- 2020, repository is moved to the `gbdev <https://github.com/gbdev>`__ organisation. The `rgbds.gbdev.io <https://rgbds.gbdev.io>`__ website serving documentation and downloads is created.

View File

@@ -1,80 +0,0 @@
# Releasing
This describes for the maintainers of RGBDS how to publish a new release on
GitHub.
1. Update the following files, then commit and push.
You can use <code>git commit -m "Release <i>&lt;version&gt;</i>"</code> and `git push origin master`.
- [include/version.hpp](include/version.hpp): set appropriate values for `PACKAGE_VERSION_MAJOR`,
`PACKAGE_VERSION_MINOR`, `PACKAGE_VERSION_PATCH`, and `PACKAGE_VERSION_RC`.
**Only** define `PACKAGE_VERSION_RC` if you are publishing a release candidate!
- [Dockerfile](Dockerfile): update `ARG version`.
- [test/fetch-test-deps.sh](test/fetch-test-deps.sh): update test dependency commits
(preferably, use the latest available).
- [man/\*](man/): update dates and authors.
2. Create a Git tag formatted as <code>v<i>&lt;MAJOR&gt;</i>.<i>&lt;MINOR&gt;</i>.<i>&lt;PATCH&gt;</i></code>,
or <code>v<i>&lt;MAJOR&gt;</i>.<i>&lt;MINOR&gt;</i>.<i>&lt;PATCH&gt;</i>-rc<i>&lt;RC&gt;</i></code>
for a release candidate. <code><i>MAJOR</i></code>, <code><i>MINOR</i></code>,
<code><i>PATCH</i></code>, and <code><i>RC</i></code> should match their values from
[include/version.hpp](include/version.hpp). You can use <code>git tag <i>&lt;tag&gt;</i></code>.
3. Push the tag to GitHub. You can use <code>git push origin <i>&lt;tag&gt;</i></code>.
GitHub Actions will run the [create-release-artifacts.yaml](.github/workflows/create-release-artifacts.yaml)
workflow to detect the tag starting with "`v[0-9]`" and automatically do the following:
1. Build 32-bit and 64-bit RGBDS binaries for Windows with `cmake`.
2. Package the binaries into zip files.
3. Package the source code into a tar.gz file with `make dist`.
4. Create a draft GitHub release for the tag, attaching the three
packaged files. It will be a prerelease if the tag contains "`-rc`".
If an error occurred in the above steps, delete the tag and restart the
procedure. You can use <code>git push --delete origin <i>&lt;tag&gt;</i></code> and
<code>git tag --delete <i>&lt;tag&gt;</i></code>.
4. GitHub Actions will run the [create-release-docs.yml](.github/workflows/create-release-docs.yml)
workflow to add the release documentation to [rgbds-www](https://github.com/gbdev/rgbds-www).
This is not done automatically for prereleases, since we do not normally publish documentation
for them. If you want to manually publish prerelease documentation, such as for an April Fools
joke prerelease,
1. Clone [rgbds-www](https://github.com/gbdev/rgbds-www). You can use
`git clone https://github.com/gbdev/rgbds-www.git`.
2. Make sure that you have installed `groff` and `mandoc`. You will
need `mandoc` 1.14.5 or later to support `-O toc`.
3. Inside of the `man` directory, run <code><i>&lt;path/to/rgbds-www&gt;</i>/maintainer/man_to_html.sh <i>&lt;tag&gt;</i> *</code> then <code><i>&lt;path/to/rgbds-www&gt;</i>/maintainer/new_release.sh <i>&lt;tag&gt;</i></code>.
This will render the RGBDS documentation as HTML and PDF and copy it to
`rgbds-www`.
If you do not have `groff` installed, you can change
`groff -Tpdf -mdoc -wall` to `mandoc -Tpdf -I os=Linux` in
[maintainer/man_to_html.sh](https://github.com/gbdev/rgbds-www/blob/master/maintainer/man_to_html.sh)
and it will suffice.
4. Commit and push the documentation. You can use <code>git commit -m
"Create RGBDS <i>&lt;tag&gt;</i> documentation"</code> and `git push origin master`
(within the `rgbds-www` directory, not RGBDS).
5. Write a changelog in the GitHub draft release.
6. Click the "Publish release" button to publish it!
7. Update the `release` branch. You can use `git push origin release`.
8. Update the following related projects.
- [rgbobj](https://github.com/gbdev/rgbobj) and [rgbds-obj](https://github.com/gbdev/rgbds-obj):
make sure that object files created by the latest RGBASM can be parsed and displayed.
If the object file revision has been updated, rgbobj will need a corresponding release.
- [rgbds-www](https://github.com/gbdev/rgbds-www): update
[src/pages/versions.mdx](https://github.com/gbdev/rgbds-www/blob/master/src/pages/versions.mdx)
to list the new release.

67
RELEASE.rst Normal file
View File

@@ -0,0 +1,67 @@
Releasing
=========
This describes for the maintainers of RGBDS how to publish a new release on
GitHub.
1. Update, commit, and push `include/version.h <include/version.h>`__ with
values for ``PACKAGE_VERSION_MAJOR``, ``PACKAGE_VERSION_MINOR``,
``PACKAGE_VERSION_PATCH``, and ``PACKAGE_VERSION_RC``. Only define
``PACKAGE_VERSION_RC`` if you are publishing a release candidate! You can
use ``git commit -m "Release <version>"`` and ``git push origin master``.
2. Create a Git tag formatted as ``v<MAJOR>.<MINOR>.<PATCH>``, or
``v<MAJOR>.<MINOR>.<PATCH>-rc<RC>`` for a release candidate. ``MAJOR``,
``MINOR``, ``PATCH``, and ``RC`` should match their values from
`include/version.h <include/version.h>`__. You can use ``git tag <tag>``.
3. Push the tag to GitHub. You can use ``git push origin <tag>``.
GitHub Actions will run the `create-release-artifacts.yaml
<.github/workflows/create-release-artifacts.yaml>`__ workflow to detect the
tag starting with "``v[0-9]``" and automatically do the following:
1. Build 32-bit and 64-bit RGBDS binaries for Windows with ``cmake``.
2. Package the binaries into zip files.
3. Package the source code into a tar.gz file with ``make dist``.
4. Create a draft GitHub release for the tag, attaching the three
packaged files. It will be a prerelease if the tag contains "``-rc``".
If an error occurred in the above steps, delete the tag and restart the
procedure. You can use ``git push --delete origin <tag>`` and
``git tag --delete <tag>``.
4. GitHub Actions will run the `create-release-docs.yml
<.github/workflows/create-release-docs.yml>`__ workflow to add the release
documentation to `rgbds-www <https://github.com/gbdev/rgbds-www>`__.
For a release candidate, which creates a prerelease, you will have to
take these steps yourself.
1. Clone `rgbds-www <https://github.com/gbdev/rgbds-www>`__. You can use
``git clone https://github.com/gbdev/rgbds-www.git``.
2. Make sure that you have installed ``groff`` and ``mandoc``. You will
need ``mandoc`` 1.14.5 or later to support ``-O toc``.
3. Run ``.github/actions/get-pages.sh -r <path/to/rgbds-www> <tag>``. This
will render the RGBDS documentation as HTML and PDF and copy it to
``rgbds-www``.
If you do not have ``groff`` installed, you can change
``groff -Tpdf -mdoc -wall`` to ``mandoc -Tpdf -I os=Linux`` in
`.github/actions/get-pages.sh <.github/actions/get-pages.sh>`__ and it
will suffice.
4. Commit and push the documentation. You can use ``git commit -m
"Create RGBDS <tag> documentation"`` and ``git push origin master``
(within the ``rgbds-www`` directory, not RGBDS).
5. Write a changelog in the GitHub draft release.
6. Click the "Publish release" button to publish it!
7. Update the `release` branch. You can use ``git push origin release``.

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env bash #/usr/bin/env bash
# Known bugs: # Known bugs:
# - Newlines in file/directory names break this script # - Newlines in file/directory names break this script
@@ -11,7 +11,7 @@
# - Directories are not completed as such in "coalesced" short-opt arguments. For example, # - Directories are not completed as such in "coalesced" short-opt arguments. For example,
# `rgbasm -M d<tab>` can autocomplete to `rgbasm -M dir/` (no space), but # `rgbasm -M d<tab>` can autocomplete to `rgbasm -M dir/` (no space), but
# `rgbasm -Md<tab>` would autocomplete to `rgbasm -Mdir ` (trailing space) instead. # `rgbasm -Md<tab>` would autocomplete to `rgbasm -Mdir ` (trailing space) instead.
# This is because directory handling is performed by Readline, whom we can't tell about the short # This is because dircetory handling is performed by Readline, whom we can't tell about the short
# opt kerfuffle. The user can work around by separating the argument, as shown above. # opt kerfuffle. The user can work around by separating the argument, as shown above.
# (Also, there might be more possible bugs if `-Mdir` is actually a directory. Ugh.) # (Also, there might be more possible bugs if `-Mdir` is actually a directory. Ugh.)
@@ -20,27 +20,27 @@
# Thus, we don't need to do much to handle that form of argument passing: skip '=' after long opts. # Thus, we don't need to do much to handle that form of argument passing: skip '=' after long opts.
_rgbasm_completions() { _rgbasm_completions() {
COMPREPLY=()
# Format: "long_opt:state_after" # Format: "long_opt:state_after"
# Empty long opt = it doesn't exit # Empty long opt = it doesn't exit
# See the `state` variable below for info about `state_after` # See the `state` variable below for info about `state_after`
declare -A opts=( declare -A opts=(
[V]="version:normal" [V]="version:normal"
[E]="export-all:normal" [E]="export-all:normal"
[h]="halt-without-nop:normal"
[L]="preserve-ld:normal"
[v]="verbose:normal" [v]="verbose:normal"
[w]=":normal" [w]=":normal"
[b]="binary-digits:unk" [b]="binary-digits:unk"
[D]="define:unk" [D]="define:unk"
[g]="gfx-chars:unk" [g]="gfx-chars:unk"
[I]="include:dir" [i]="include:dir"
[M]="dependfile:glob-*.mk *.d" [M]="dependfile:glob-*.mk *.d"
[o]="output:glob-*.o" [o]="output:glob-*.o"
[P]="preinclude:glob-*.asm *.inc"
[p]="pad-value:unk" [p]="pad-value:unk"
[Q]="q-precision:unk"
[r]="recursion-depth:unk" [r]="recursion-depth:unk"
[s]="state:unk"
[W]="warning:warning" [W]="warning:warning"
[X]="max-errors:unk"
) )
# Parse command-line up to current word # Parse command-line up to current word
local opt_ena=true local opt_ena=true
@@ -58,18 +58,6 @@ _rgbasm_completions() {
# "normal" is not returned, `optlen` will be set to the length (dash included) of the "option" # "normal" is not returned, `optlen` will be set to the length (dash included) of the "option"
# part of the argument. # part of the argument.
parse_short_opt() { parse_short_opt() {
# These options act like a long option (= takes up the entire word), but only use a single dash
# So, they need some special handling
if [[ "$1" = "-M"[GP] ]]; then
state=normal
optlen=${#1}
return;
elif [[ "$1" = "-M"[QT] ]]; then
state='glob-*.d *.mk *.o'
optlen=${#1}
return;
fi
for (( i = 1; i < "${#1}"; i++ )); do for (( i = 1; i < "${#1}"; i++ )); do
# If the option is not known, assume it doesn't take an argument # If the option is not known, assume it doesn't take an argument
local opt="${opts["${1:$i:1}"]:-":normal"}" local opt="${opts["${1:$i:1}"]:-":normal"}"
@@ -83,7 +71,7 @@ _rgbasm_completions() {
optlen=0 optlen=0
} }
for (( i = 1; i < COMP_CWORD; i++ )); do for (( i = 1; i < $COMP_CWORD; i++ )); do
local word="${COMP_WORDS[$i]}" local word="${COMP_WORDS[$i]}"
# If currently processing an argument, skip this word # If currently processing an argument, skip this word
@@ -99,7 +87,7 @@ _rgbasm_completions() {
fi fi
# Check if it's a long option # Check if it's a long option
if [[ "$word" = '--'* ]]; then if [[ "${word:0:2}" = '--' ]]; then
# If the option is unknown, assume it takes no arguments: keep the state at "normal" # If the option is unknown, assume it takes no arguments: keep the state at "normal"
for long_opt in "${opts[@]}"; do for long_opt in "${opts[@]}"; do
if [[ "$word" = "--${long_opt%%:*}" ]]; then if [[ "$word" = "--${long_opt%%:*}" ]]; then
@@ -115,16 +103,25 @@ _rgbasm_completions() {
fi fi
done done
# Check if it's a short option # Check if it's a short option
elif [[ "$word" = '-'* ]]; then elif [[ "${word:0:1}" = '-' ]]; then
parse_short_opt "$word" # The `-M?` ones are a mix of short and long, augh
# The last option takes an argument... # They must match the *full* word, but only take a single dash
if [[ "$state" != 'normal' ]]; then # So, handle them here
if [[ "$optlen" -ne "${#word}" ]]; then if [[ "$1" = "-M"[GP] ]]; then
# If it's contained within the word, we won't complete it, revert to "normal" state=normal
state=normal elif [[ "$1" = "-M"[TQ] ]]; then
else state='glob-*.d *.mk *.o'
# Otherwise, complete it, but start at the beginning of *that* word else
optlen=0 parse_short_opt "$word"
# The last option takes an argument...
if [[ "$state" != 'normal' ]]; then
if [[ "$optlen" -ne "${#word}" ]]; then
# If it's contained within the word, we won't complete it, revert to "normal"
state=normal
else
# Otherwise, complete it, but start at the beginning of *that* word
optlen=0
fi
fi fi
fi fi
fi fi
@@ -132,48 +129,48 @@ _rgbasm_completions() {
# Parse current word # Parse current word
# Careful that it might look like an option, so use `--` aggressively! # Careful that it might look like an option, so use `--` aggressively!
local cur_word="${COMP_WORDS[$i]}" local cur_word="${COMP_WORDS[$COMP_CWORD]}"
# Process options, as short ones may change the state # Process options, as short ones may change the state
if $opt_ena && [[ "$state" = 'normal' && "$cur_word" = '-'* ]]; then if $opt_ena && [[ "$state" = 'normal' && "${cur_word:0:1}" = '-' ]]; then
# We might want to complete to an option or an arg to that option # We might want to complete to an option or an arg to that option
# Parse the option word to check # Parse the option word to check
# There's no whitespace in the option names, so we can ride a little dirty... # There's no whitespace in the option names, so we can ride a little dirty...
# Is this a long option? # Is this a long option?
if [[ "$cur_word" = '--'* ]]; then if [[ "${cur_word:1:1}" = '-' ]]; then
# It is, try to complete one # It is, try to complete one
mapfile -t COMPREPLY < <(compgen -W "${opts[*]%%:*}" -P '--' -- "${cur_word#--}") COMPREPLY+=( $(compgen -W "${opts[*]%%:*}" -P '--' -- "${cur_word#--}") )
return 0
elif [[ "$cur_word" = '-M'[GPQT] ]]; then
# These options act like long opts with no arguments, so return them and exactly them
COMPREPLY=( "$cur_word" )
return 0 return 0
else else
# Short options may be grouped, parse them to determine what to complete # Short options may be grouped, parse them to determine what to complete
parse_short_opt "$cur_word" # The `-M?` ones may not be followed by anything
if [[ "$1" != "-M"[GPTQ] ]]; then
parse_short_opt "$cur_word"
# We got some short options that behave like long ones
COMPREPLY+=( $(compgen -W '-MG -MP -MT -MQ' -- "$cur_word") )
if [[ "$state" = 'normal' ]]; then if [[ "$state" = 'normal' ]]; then
mapfile -t COMPREPLY < <(compgen -W "${!opts[*]}" -P "$cur_word" ''; compgen -W '-MG -MP -MQ -MT' "$cur_word") COMPREPLY+=( $(compgen -W "${!opts[*]}" -P "$cur_word" '') )
return 0 return 0
elif [[ "$optlen" = "${#cur_word}" && "$state" != "warning" ]]; then elif [[ "$optlen" = "${#cur_word}" && "$state" != "warning" ]]; then
# This short option group only awaits its argument! # This short option group only awaits its argument!
# Post the option group as-is as a reply so that Readline inserts a space, # Post the option group as-is as a reply so that Readline inserts a space,
# so that the next completion request switches to the argument # so that the next completion request switches to the argument
# An exception is made for warnings, since it's idiomatic to stick them to the # An exception is made for warnings, since it's idiomatic to stick them to the
# `-W`, and it doesn't break anything. # `-W`, and it doesn't break anything.
COMPREPLY=( "$cur_word" ) COMPREPLY+=( "$cur_word" )
return 0 return 0
fi
fi fi
fi fi
fi fi
COMPREPLY=()
case "$state" in case "$state" in
unk) # Return with no replies: no idea what to complete! unk) # Return with no replies: no idea what to complete!
;; ;;
warning) warning)
mapfile -t COMPREPLY < <(compgen -W " COMPREPLY+=( $(compgen -W "
assert assert
backwards-for backwards-for
builtin-args builtin-args
@@ -183,22 +180,19 @@ _rgbasm_completions() {
empty-macro-arg empty-macro-arg
empty-strrpl empty-strrpl
large-constant large-constant
long-string
macro-shift macro-shift
nested-comment nested-comment
numeric-string numeric-string
obsolete obsolete
purge
shift shift
shift-amount shift-amount
truncation truncation
unmapped-char
unmatched-directive
unterminated-load
user user
all all
extra extra
everything everything
error" -P "${cur_word:0:$optlen}" -- "${cur_word:$optlen}") error" -P "${cur_word:0:$optlen}" -- "${cur_word:$optlen}") )
;; ;;
normal) # Acts like a glob... normal) # Acts like a glob...
state="glob-*.asm *.inc *.sm83" state="glob-*.asm *.inc *.sm83"
@@ -215,10 +209,6 @@ _rgbasm_completions() {
done < <(compgen -A directory -- "${cur_word:$optlen}") done < <(compgen -A directory -- "${cur_word:$optlen}")
compopt -o filenames compopt -o filenames
;; ;;
*)
echo >&2 "Internal completion error: invalid state \"$state\", please report this bug"
return 1
;;
esac esac
} }

View File

@@ -1,8 +1,10 @@
#!/usr/bin/env bash #/usr/bin/env bash
# Same notes as RGBASM # Same notes as RGBASM
_rgbfix_completions() { _rgbfix_completions() {
COMPREPLY=()
# Format: "long_opt:state_after" # Format: "long_opt:state_after"
# Empty long opt = it doesn't exit # Empty long opt = it doesn't exit
# See the `state` variable below for info about `state_after` # See the `state` variable below for info about `state_after`
@@ -16,7 +18,6 @@ _rgbfix_completions() {
[f]="fix-spec:fix-spec" [f]="fix-spec:fix-spec"
[i]="game-id:unk" [i]="game-id:unk"
[k]="new-licensee:unk" [k]="new-licensee:unk"
[L]="custom-logo:glob-*.1bpp"
[l]="old-licensee:unk" [l]="old-licensee:unk"
[m]="mbc-type:mbc" [m]="mbc-type:mbc"
[n]="rom-version:unk" [n]="rom-version:unk"
@@ -53,7 +54,7 @@ _rgbfix_completions() {
optlen=0 optlen=0
} }
for (( i = 1; i < COMP_CWORD; i++ )); do for (( i = 1; i < $COMP_CWORD; i++ )); do
local word="${COMP_WORDS[$i]}" local word="${COMP_WORDS[$i]}"
# If currently processing an argument, skip this word # If currently processing an argument, skip this word
@@ -69,7 +70,7 @@ _rgbfix_completions() {
fi fi
# Check if it's a long option # Check if it's a long option
if [[ "$word" = '--'* ]]; then if [[ "${word:0:2}" = '--' ]]; then
# If the option is unknown, assume it takes no arguments: keep the state at "normal" # If the option is unknown, assume it takes no arguments: keep the state at "normal"
for long_opt in "${opts[@]}"; do for long_opt in "${opts[@]}"; do
if [[ "$word" = "--${long_opt%%:*}" ]]; then if [[ "$word" = "--${long_opt%%:*}" ]]; then
@@ -85,7 +86,7 @@ _rgbfix_completions() {
fi fi
done done
# Check if it's a short option # Check if it's a short option
elif [[ "$word" = '-'* ]]; then elif [[ "${word:0:1}" = '-' ]]; then
parse_short_opt "$word" parse_short_opt "$word"
# The last option takes an argument... # The last option takes an argument...
if [[ "$state" != 'normal' ]]; then if [[ "$state" != 'normal' ]]; then
@@ -102,25 +103,25 @@ _rgbfix_completions() {
# Parse current word # Parse current word
# Careful that it might look like an option, so use `--` aggressively! # Careful that it might look like an option, so use `--` aggressively!
local cur_word="${COMP_WORDS[$i]}" local cur_word="${COMP_WORDS[$COMP_CWORD]}"
# Process options, as short ones may change the state # Process options, as short ones may change the state
if $opt_ena && [[ "$state" = 'normal' && "$cur_word" = '-'* ]]; then if $opt_ena && [[ "$state" = 'normal' && "${cur_word:0:1}" = '-' ]]; then
# We might want to complete to an option or an arg to that option # We might want to complete to an option or an arg to that option
# Parse the option word to check # Parse the option word to check
# There's no whitespace in the option names, so we can ride a little dirty... # There's no whitespace in the option names, so we can ride a little dirty...
# Is this a long option? # Is this a long option?
if [[ "$cur_word" = '--'* ]]; then if [[ "${cur_word:1:1}" = '-' ]]; then
# It is, try to complete one # It is, try to complete one
mapfile -t COMPREPLY < <(compgen -W "${opts[*]%%:*}" -P '--' -- "${cur_word#--}") COMPREPLY+=( $(compgen -W "${opts[*]%%:*}" -P '--' -- "${cur_word#--}") )
return 0 return 0
else else
# Short options may be grouped, parse them to determine what to complete # Short options may be grouped, parse them to determine what to complete
parse_short_opt "$cur_word" parse_short_opt "$cur_word"
if [[ "$state" = 'normal' ]]; then if [[ "$state" = 'normal' ]]; then
mapfile -t COMPREPLY < <(compgen -W "${!opts[*]}" -P "$cur_word" '') COMPREPLY+=( $(compgen -W "${!opts[*]}" -P "$cur_word" '') )
return 0 return 0
elif [[ "$optlen" = "${#cur_word}" && "$state" != "warning" ]]; then elif [[ "$optlen" = "${#cur_word}" && "$state" != "warning" ]]; then
# This short option group only awaits its argument! # This short option group only awaits its argument!
@@ -128,25 +129,22 @@ _rgbfix_completions() {
# so that the next completion request switches to the argument # so that the next completion request switches to the argument
# An exception is made for warnings, since it's idiomatic to stick them to the # An exception is made for warnings, since it's idiomatic to stick them to the
# `-W`, and it doesn't break anything. # `-W`, and it doesn't break anything.
COMPREPLY=( "$cur_word" ) COMPREPLY+=( "$cur_word" )
return 0 return 0
fi fi
fi fi
fi fi
COMPREPLY=()
case "$state" in case "$state" in
unk) # Return with no replies: no idea what to complete! unk) # Return with no replies: no idea what to complete!
;; ;;
fix-spec) fix-spec)
COMPREPLY=( "${cur_word}"{l,h,g,L,H,G} ) COMPREPLY+=( "${cur_word}"{l,h,g,L,H,G} )
;; ;;
mbc) mbc)
local cur_arg="${cur_word:$optlen}" local cur_arg="${cur_word:$optlen}"
cur_arg="${cur_arg@U}" cur_arg="${cur_arg@U}"
compopt -o nosort # Keep `help` first in the list, mainly COMPREPLY=( $(compgen -W "
mapfile -t COMPREPLY < <(compgen -W "help" -P "${cur_word:0:$optlen}" -- "${cur_word:$optlen}")
mapfile -t COMPREPLY -O ${#COMPREPLY} < <(compgen -W "
ROM_ONLY ROM_ONLY
MBC1{,+RAM,+RAM+BATTERY} MBC1{,+RAM,+RAM+BATTERY}
MBC2{,+BATTERY} MBC2{,+BATTERY}
@@ -159,7 +157,8 @@ _rgbfix_completions() {
BANDAI_TAMA5 BANDAI_TAMA5
HUC3 HUC3
HUC1+RAM+BATTERY HUC1+RAM+BATTERY
TPP1_1.0{,+BATTERY}{,+RTC}{,+RUMBLE,+MULTIRUMBLE}" -P "${cur_word:0:$optlen}" -- "${cur_word/ /_}") TPP1_1.0{,+BATTERY}{,+RTC}{,+RUMBLE,+MULTIRUMBLE}" -P "${cur_word:0:$optlen}" -- "`tr 'a-z ' 'A-Z_' <<<"${cur_word/ /_}"`") )
COMPREPLY+=( $(compgen -W "help" -P "${cur_word:0:$optlen}" -- "${cur_word:$optlen}") )
;; ;;
normal) # Acts like a glob... normal) # Acts like a glob...
state="glob-*.gb *.gbc *.sgb" state="glob-*.gb *.gbc *.sgb"
@@ -176,10 +175,6 @@ _rgbfix_completions() {
done < <(compgen -A directory -- "${cur_word:$optlen}") done < <(compgen -A directory -- "${cur_word:$optlen}")
compopt -o filenames compopt -o filenames
;; ;;
*)
echo >&2 "Internal completion error: invalid state \"$state\", please report this bug"
return 1
;;
esac esac
} }

View File

@@ -1,39 +1,31 @@
#!/usr/bin/env bash #/usr/bin/env bash
# Same notes as RGBASM # Same notes as RGBASM
_rgbgfx_completions() { _rgbgfx_completions() {
COMPREPLY=()
# Format: "long_opt:state_after" # Format: "long_opt:state_after"
# Empty long opt = it doesn't exit # Empty long opt = it doesn't exit
# See the `state` variable below for info about `state_after` # See the `state` variable below for info about `state_after`
declare -A opts=( declare -A opts=(
[V]="version:normal" [V]="version:normal"
[C]="color-curve:normal" [C]="color-curve:normal"
[D]="debug:normal"
[h]="horizontal:normal"
[m]="mirror-tiles:normal" [m]="mirror-tiles:normal"
[O]="group-outputs:normal"
[u]="unique-tiles:normal" [u]="unique-tiles:normal"
[v]="verbose:normal" [v]="verbose:normal"
[X]="mirror-x:normal" [f]="fix:normal"
[Y]="mirror-y:normal" [F]="fix-and-save:normal"
[Z]="columns:normal" [a]="attr-map:*.attrmap"
[a]="attr-map:glob-*.attrmap" [A]="output-attr-map:normal"
[A]="auto-attr-map:normal"
[b]="base-tiles:unk"
[c]="colors:unk"
[d]="depth:unk" [d]="depth:unk"
[i]="input-tileset:glob-*.2bpp" [o]="output:glob *.2bpp"
[L]="slice:unk" [p]="palette:glob *.pal"
[N]="nb-tiles:unk" [P]="output-palette:normal"
[n]="nb-palettes:unk" [t]="tilemap:glob *.tilemap"
[o]="output:glob-*.2bpp" [T]="output-tilemap:normal"
[p]="palette:glob-*.pal"
[P]="auto-palette:normal"
[q]="palette-map:glob-*.palmap"
[Q]="auto-palette-map:normal"
[r]="reverse:unk"
[s]="palette-size:unk"
[t]="tilemap:glob-*.tilemap"
[T]="auto-tilemap:normal"
[x]="trim-end:unk" [x]="trim-end:unk"
) )
# Parse command-line up to current word # Parse command-line up to current word
@@ -65,7 +57,7 @@ _rgbgfx_completions() {
optlen=0 optlen=0
} }
for (( i = 1; i < COMP_CWORD; i++ )); do for (( i = 1; i < $COMP_CWORD; i++ )); do
local word="${COMP_WORDS[$i]}" local word="${COMP_WORDS[$i]}"
# If currently processing an argument, skip this word # If currently processing an argument, skip this word
@@ -81,7 +73,7 @@ _rgbgfx_completions() {
fi fi
# Check if it's a long option # Check if it's a long option
if [[ "$word" = '--'* ]]; then if [[ "${word:0:2}" = '--' ]]; then
# If the option is unknown, assume it takes no arguments: keep the state at "normal" # If the option is unknown, assume it takes no arguments: keep the state at "normal"
for long_opt in "${opts[@]}"; do for long_opt in "${opts[@]}"; do
if [[ "$word" = "--${long_opt%%:*}" ]]; then if [[ "$word" = "--${long_opt%%:*}" ]]; then
@@ -97,7 +89,7 @@ _rgbgfx_completions() {
fi fi
done done
# Check if it's a short option # Check if it's a short option
elif [[ "$word" = '-'* ]]; then elif [[ "${word:0:1}" = '-' ]]; then
parse_short_opt "$word" parse_short_opt "$word"
# The last option takes an argument... # The last option takes an argument...
if [[ "$state" != 'normal' ]]; then if [[ "$state" != 'normal' ]]; then
@@ -114,25 +106,25 @@ _rgbgfx_completions() {
# Parse current word # Parse current word
# Careful that it might look like an option, so use `--` aggressively! # Careful that it might look like an option, so use `--` aggressively!
local cur_word="${COMP_WORDS[$i]}" local cur_word="${COMP_WORDS[$COMP_CWORD]}"
# Process options, as short ones may change the state # Process options, as short ones may change the state
if $opt_ena && [[ "$state" = 'normal' && "$cur_word" = '-'* ]]; then if $opt_ena && [[ "$state" = 'normal' && "${cur_word:0:1}" = '-' ]]; then
# We might want to complete to an option or an arg to that option # We might want to complete to an option or an arg to that option
# Parse the option word to check # Parse the option word to check
# There's no whitespace in the option names, so we can ride a little dirty... # There's no whitespace in the option names, so we can ride a little dirty...
# Is this a long option? # Is this a long option?
if [[ "$cur_word" = '--'* ]]; then if [[ "${cur_word:1:1}" = '-' ]]; then
# It is, try to complete one # It is, try to complete one
mapfile -t COMPREPLY < <(compgen -W "${opts[*]%%:*}" -P '--' -- "${cur_word#--}") COMPREPLY+=( $(compgen -W "${opts[*]%%:*}" -P '--' -- "${cur_word#--}") )
return 0 return 0
else else
# Short options may be grouped, parse them to determine what to complete # Short options may be grouped, parse them to determine what to complete
parse_short_opt "$cur_word" parse_short_opt "$cur_word"
if [[ "$state" = 'normal' ]]; then if [[ "$state" = 'normal' ]]; then
mapfile -t COMPREPLY < <(compgen -W "${!opts[*]}" -P "$cur_word" '') COMPREPLY+=( $(compgen -W "${!opts[*]}" -P "$cur_word" '') )
return 0 return 0
elif [[ "$optlen" = "${#cur_word}" && "$state" != "warning" ]]; then elif [[ "$optlen" = "${#cur_word}" && "$state" != "warning" ]]; then
# This short option group only awaits its argument! # This short option group only awaits its argument!
@@ -140,13 +132,12 @@ _rgbgfx_completions() {
# so that the next completion request switches to the argument # so that the next completion request switches to the argument
# An exception is made for warnings, since it's idiomatic to stick them to the # An exception is made for warnings, since it's idiomatic to stick them to the
# `-W`, and it doesn't break anything. # `-W`, and it doesn't break anything.
COMPREPLY=( "$cur_word" ) COMPREPLY+=( "$cur_word" )
return 0 return 0
fi fi
fi fi
fi fi
COMPREPLY=()
case "$state" in case "$state" in
unk) # Return with no replies: no idea what to complete! unk) # Return with no replies: no idea what to complete!
;; ;;
@@ -165,10 +156,6 @@ _rgbgfx_completions() {
done < <(compgen -A directory -- "${cur_word:$optlen}") done < <(compgen -A directory -- "${cur_word:$optlen}")
compopt -o filenames compopt -o filenames
;; ;;
*)
echo >&2 "Internal completion error: invalid state \"$state\", please report this bug"
return 1
;;
esac esac
} }

View File

@@ -1,8 +1,10 @@
#!/usr/bin/env bash #/usr/bin/env bash
# Same notes as RGBASM # Same notes as RGBASM
_rgblink_completions() { _rgblink_completions() {
COMPREPLY=()
# Format: "long_opt:state_after" # Format: "long_opt:state_after"
# Empty long opt = it doesn't exit # Empty long opt = it doesn't exit
# See the `state` variable below for info about `state_after` # See the `state` variable below for info about `state_after`
@@ -14,12 +16,12 @@ _rgblink_completions() {
[w]="wramx:normal" [w]="wramx:normal"
[x]="nopad:normal" [x]="nopad:normal"
[l]="linkerscript:glob-*" [l]="linkerscript:glob-*"
[M]="no-sym-in-map:normal"
[m]="map:glob-*.map" [m]="map:glob-*.map"
[n]="sym:glob-*.sym" [n]="sym:glob-*.sym"
[O]="overlay:glob-*.gb *.gbc *.sgb" [O]="overlay:glob-*.gb *.gbc *.sgb"
[o]="output:glob-*.gb *.gbc *.sgb" [o]="output:glob-*.gb *.gbc *.sgb"
[p]="pad:unk" [p]="pad:unk"
[s]="smart:unk"
) )
# Parse command-line up to current word # Parse command-line up to current word
local opt_ena=true local opt_ena=true
@@ -50,7 +52,7 @@ _rgblink_completions() {
optlen=0 optlen=0
} }
for (( i = 1; i < COMP_CWORD; i++ )); do for (( i = 1; i < $COMP_CWORD; i++ )); do
local word="${COMP_WORDS[$i]}" local word="${COMP_WORDS[$i]}"
# If currently processing an argument, skip this word # If currently processing an argument, skip this word
@@ -66,7 +68,7 @@ _rgblink_completions() {
fi fi
# Check if it's a long option # Check if it's a long option
if [[ "$word" = '--'* ]]; then if [[ "${word:0:2}" = '--' ]]; then
# If the option is unknown, assume it takes no arguments: keep the state at "normal" # If the option is unknown, assume it takes no arguments: keep the state at "normal"
for long_opt in "${opts[@]}"; do for long_opt in "${opts[@]}"; do
if [[ "$word" = "--${long_opt%%:*}" ]]; then if [[ "$word" = "--${long_opt%%:*}" ]]; then
@@ -82,7 +84,7 @@ _rgblink_completions() {
fi fi
done done
# Check if it's a short option # Check if it's a short option
elif [[ "$word" = '-'* ]]; then elif [[ "${word:0:1}" = '-' ]]; then
parse_short_opt "$word" parse_short_opt "$word"
# The last option takes an argument... # The last option takes an argument...
if [[ "$state" != 'normal' ]]; then if [[ "$state" != 'normal' ]]; then
@@ -99,25 +101,25 @@ _rgblink_completions() {
# Parse current word # Parse current word
# Careful that it might look like an option, so use `--` aggressively! # Careful that it might look like an option, so use `--` aggressively!
local cur_word="${COMP_WORDS[$i]}" local cur_word="${COMP_WORDS[$COMP_CWORD]}"
# Process options, as short ones may change the state # Process options, as short ones may change the state
if $opt_ena && [[ "$state" = 'normal' && "$cur_word" = '-'* ]]; then if $opt_ena && [[ "$state" = 'normal' && "${cur_word:0:1}" = '-' ]]; then
# We might want to complete to an option or an arg to that option # We might want to complete to an option or an arg to that option
# Parse the option word to check # Parse the option word to check
# There's no whitespace in the option names, so we can ride a little dirty... # There's no whitespace in the option names, so we can ride a little dirty...
# Is this a long option? # Is this a long option?
if [[ "$cur_word" = '--'* ]]; then if [[ "${cur_word:1:1}" = '-' ]]; then
# It is, try to complete one # It is, try to complete one
mapfile -t COMPREPLY < <(compgen -W "${opts[*]%%:*}" -P '--' -- "${cur_word#--}") COMPREPLY+=( $(compgen -W "${opts[*]%%:*}" -P '--' -- "${cur_word#--}") )
return 0 return 0
else else
# Short options may be grouped, parse them to determine what to complete # Short options may be grouped, parse them to determine what to complete
parse_short_opt "$cur_word" parse_short_opt "$cur_word"
if [[ "$state" = 'normal' ]]; then if [[ "$state" = 'normal' ]]; then
mapfile -t COMPREPLY < <(compgen -W "${!opts[*]}" -P "$cur_word" '') COMPREPLY+=( $(compgen -W "${!opts[*]}" -P "$cur_word" '') )
return 0 return 0
elif [[ "$optlen" = "${#cur_word}" && "$state" != "warning" ]]; then elif [[ "$optlen" = "${#cur_word}" && "$state" != "warning" ]]; then
# This short option group only awaits its argument! # This short option group only awaits its argument!
@@ -125,13 +127,12 @@ _rgblink_completions() {
# so that the next completion request switches to the argument # so that the next completion request switches to the argument
# An exception is made for warnings, since it's idiomatic to stick them to the # An exception is made for warnings, since it's idiomatic to stick them to the
# `-W`, and it doesn't break anything. # `-W`, and it doesn't break anything.
COMPREPLY=( "$cur_word" ) COMPREPLY+=( "$cur_word" )
return 0 return 0
fi fi
fi fi
fi fi
COMPREPLY=()
case "$state" in case "$state" in
unk) # Return with no replies: no idea what to complete! unk) # Return with no replies: no idea what to complete!
;; ;;
@@ -150,10 +151,6 @@ _rgblink_completions() {
done < <(compgen -A directory -- "${cur_word:$optlen}") done < <(compgen -A directory -- "${cur_word:$optlen}")
compopt -o filenames compopt -o filenames
;; ;;
*)
echo >&2 "Internal completion error: invalid state \"$state\", please report this bug"
return 1
;;
esac esac
} }

View File

@@ -1,11 +1,31 @@
#!/usr/bin/env bash #!/bin/bash
# SPDX-License-Identifier: MIT # SPDX-License-Identifier: MIT
#
# Copyright (c) 2021 Rangi
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
declare -A FILES declare -A FILES
while read -r -d '' file; do while read -r -d '' file; do
FILES["$file"]="true" FILES["$file"]="true"
done < <(git diff --name-only -z "$1" HEAD) done < <(git diff --name-only -z $1 HEAD)
edited () { edited () {
${FILES["$1"]:-"false"} ${FILES["$1"]:-"false"}
@@ -20,62 +40,46 @@ dependency () {
# Pull requests that edit the first file without the second may be correct, # Pull requests that edit the first file without the second may be correct,
# but are suspicious enough to require review. # but are suspicious enough to require review.
dependency include/linkdefs.hpp man/rgbds.5 \ dependency include/linkdefs.h src/rgbds.5 \
"Was the object file format changed?" "Was the object file format changed?"
dependency src/asm/parser.y man/rgbasm.5 \ dependency src/asm/parser.y src/asm/rgbasm.5 \
"Was the rgbasm grammar changed?" "Was the rgbasm grammar changed?"
dependency src/link/script.y man/rgblink.5 \ dependency include/asm/warning.h src/asm/rgbasm.1 \
"Was the linker script grammar changed?"
dependency include/asm/warning.hpp man/rgbasm.1 \
"Were the rgbasm warnings changed?" "Were the rgbasm warnings changed?"
dependency src/asm/object.cpp include/linkdefs.hpp \ dependency src/asm/object.c include/linkdefs.h \
"Should the object file revision be bumped?" "Should the object file revision be bumped?"
dependency src/link/object.cpp include/linkdefs.hpp \ dependency src/link/object.c include/linkdefs.h \
"Should the object file revision be bumped?" "Should the object file revision be bumped?"
dependency Makefile CMakeLists.txt \ dependency Makefile CMakeLists.txt \
"Did the build process change?" "Did the build process change?"
dependency Makefile src/CMakeLists.txt \ dependency Makefile src/CMakeLists.txt \
"Did the build process change?" "Did the build process change?"
dependency src/asm/main.cpp man/rgbasm.1 \ dependency src/asm/main.c src/asm/rgbasm.1 \
"Did the rgbasm CLI change?" "Did the rgbasm CLI change?"
dependency src/asm/main.cpp contrib/zsh_compl/_rgbasm \ dependency src/asm/main.c contrib/zsh_compl/_rgbasm \
"Did the rgbasm CLI change?" "Did the rgbasm CLI change?"
dependency src/asm/main.cpp contrib/bash_compl/_rgbasm.bash \ dependency src/asm/main.c contrib/bash_compl/_rgbasm.bash \
"Did the rgbasm CLI change?" "Did the rgbasm CLI change?"
dependency src/link/main.cpp man/rgblink.1 \ dependency src/link/main.c src/link/rgblink.1 \
"Did the rgblink CLI change?" "Did the rgblink CLI change?"
dependency src/link/main.cpp contrib/zsh_compl/_rgblink \ dependency src/link/main.c contrib/zsh_compl/_rgblink \
"Did the rgblink CLI change?" "Did the rgblink CLI change?"
dependency src/link/main.cpp contrib/bash_compl/_rgblink.bash \ dependency src/link/main.c contrib/bash_compl/_rgblink.bash \
"Did the rgblink CLI change?" "Did the rgblink CLI change?"
dependency src/fix/main.cpp man/rgbfix.1 \ dependency src/fix/main.c src/fix/rgbfix.1 \
"Did the rgbfix CLI change?" "Did the rgbfix CLI change?"
dependency src/fix/main.cpp contrib/zsh_compl/_rgbfix \ dependency src/fix/main.c contrib/zsh_compl/_rgbfix \
"Did the rgbfix CLI change?" "Did the rgbfix CLI change?"
dependency src/fix/main.cpp contrib/bash_compl/_rgbfix.bash \ dependency src/fix/main.c contrib/bash_compl/_rgbfix.bash \
"Did the rgbfix CLI change?" "Did the rgbfix CLI change?"
dependency src/gfx/main.cpp man/rgbgfx.1 \ dependency src/gfx/main.c src/gfx/rgbgfx.1 \
"Did the rgbgfx CLI change?" "Did the rgbgfx CLI change?"
dependency src/gfx/main.cpp contrib/zsh_compl/_rgbgfx \ dependency src/gfx/main.c contrib/zsh_compl/_rgbgfx \
"Did the rgbgfx CLI change?" "Did the rgbgfx CLI change?"
dependency src/gfx/main.cpp contrib/bash_compl/_rgbgfx.bash \ dependency src/gfx/main.c contrib/bash_compl/_rgbgfx.bash \
"Did the rgbgfx CLI change?" "Did the rgbgfx CLI change?"
dependency test/fetch-test-deps.sh CONTRIBUTING.md \
"Did the test protocol change?"
dependency test/run-tests.sh CONTRIBUTING.md \
"Did the test protocol change?"
dependency test/asm/test.sh CONTRIBUTING.md \
"Did the RGBASM test protocol change?"
dependency test/link/test.sh CONTRIBUTING.md \
"Did the RGBLINK test protocol change?"
dependency test/fix/test.sh CONTRIBUTING.md \
"Did the RGBFIX test protocol change?"
dependency test/gfx/test.sh CONTRIBUTING.md \
"Did the RGBGFX test protocol change?"

View File

@@ -1,26 +0,0 @@
#!/usr/bin/env bash
set -e
# Build RGBDS with gcov support
make coverage -j
# Run the tests
pushd test
./fetch-test-deps.sh
./run-tests.sh
popd
# Generate coverage logs
gcov src/**/*.cpp
mkdir -p coverage
# Generate coverage report
lcov -c --no-external -d . -o coverage/coverage.info
genhtml -f -s -o coverage/ coverage/coverage.info
# Open report in web browser
if [ "$(uname)" == "Darwin" ]; then
open coverage/index.html
else
xdg-open coverage/index.html
fi

View File

@@ -1,53 +1,73 @@
#!/usr/bin/env bash #!/bin/bash
# SPDX-License-Identifier: MIT # SPDX-License-Identifier: MIT
#
# Copyright (c) 2020 Eldred Habert
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
STATE=0 STATE=0
diff <(xxd "$1") <(xxd "$2") | while read -r LINE; do diff <(xxd $1) <(xxd $2) | while read -r LINE; do
if [[ $STATE -eq 0 ]]; then if [ $STATE -eq 0 ]; then
# Discard first line (line info) # Discard first line (line info)
STATE=1 STATE=1
elif [[ "$LINE" = '---' ]]; then elif [ "$LINE" = '---' ]; then
# Separator between files switches states # Separator between files switches states
echo "$LINE" echo $LINE
STATE=3 STATE=3
elif grep -Eq '^[0-9]+(,[0-9]+)?[cd][0-9]+(,[0-9]+)?' <<< "$LINE"; then elif grep -Eq '^[0-9]+(,[0-9]+)?[cd][0-9]+(,[0-9]+)?' <<< "$LINE"; then
# Line info resets the whole thing # Line info resets the whole thing
STATE=1 STATE=1
elif [[ $STATE -eq 1 || $STATE -eq 3 ]]; then elif [ $STATE -eq 1 -o $STATE -eq 3 ]; then
# Compute the GB address from the ROM offset # Compute the GB address from the ROM offset
OFS=$(cut -d ' ' -f 2 <<< "$LINE" | tr -d ':') OFS=$(cut -d ' ' -f 2 <<< "$LINE" | tr -d ':')
BANK=$((0x$OFS / 0x4000)) BANK=$((0x$OFS / 0x4000))
ADDR=$((0x$OFS % 0x4000 + (BANK != 0) * 0x4000)) ADDR=$((0x$OFS % 0x4000 + ($BANK != 0) * 0x4000))
# Try finding the preceding symbol closest to the diff # Try finding the preceding symbol closest to the diff
if [[ $STATE -eq 1 ]]; then if [ $STATE -eq 1 ]; then
STATE=2 STATE=2
SYMFILE=${1%.*}.sym SYMFILE=${1%.*}.sym
else else
STATE=4 STATE=4
SYMFILE=${2%.*}.sym SYMFILE=${2%.*}.sym
fi fi
EXTRA=$(if [[ -f "$SYMFILE" ]]; then EXTRA=$(if [ -f "$SYMFILE" ]; then
# Read the sym file for such a symbol # Read the sym file for such a symbol
# Ignore comment lines, only pick matching bank # Ignore comment lines, only pick matching bank
# (The bank regex ignores comments already, make `cut` and `tr` process less lines) # (The bank regex ignores comments already, make `cut` and `tr` process less lines)
grep -Ei "$(printf "^%02x:" $BANK)" "$SYMFILE" | grep -Ei $(printf "^%02x:" $BANK) "$SYMFILE" |
cut -d ';' -f 1 | cut -d ';' -f 1 |
tr -d "\r" | tr -d "\r" |
while read -r SYMADDR SYM; do while read -r SYMADDR SYM; do
SYMADDR=$((0x${SYMADDR#*:})) SYMADDR=$((0x${SYMADDR#*:}))
if [[ $SYMADDR -le $ADDR ]]; then if [ $SYMADDR -le $ADDR ]; then
printf " (%s+0x%x)\n" "$SYM" $((ADDR - SYMADDR)) printf " (%s+%#x)\n" "$SYM" $(($ADDR - $SYMADDR))
fi fi
# TODO: assumes sorted sym files # TODO: assumes sorted sym files
done | tail -n 1 done | tail -n 1
fi) fi)
printf "%02x:%04x %s\n" $BANK $ADDR "$EXTRA" printf "%02x:%04x %s\n" $BANK $ADDR $EXTRA
fi fi
if [[ $STATE -eq 2 || $STATE -eq 4 ]]; then if [ $STATE -eq 2 -o $STATE -eq 4 ]; then
OFS=$(cut -d ' ' -f 2 <<< "$LINE" | tr -d ':') OFS=$(cut -d ' ' -f 2 <<< "$LINE" | tr -d ':')
BANK=$((0x$OFS / 0x4000)) BANK=$((0x$OFS / 0x4000))
ADDR=$((0x$OFS % 0x4000 + (BANK != 0) * 0x4000)) ADDR=$((0x$OFS % 0x4000 + ($BANK != 0) * 0x4000))
printf "%s %02x:%04x: %s\n" "${LINE:0:1}" $BANK $ADDR "${LINE#*: }" printf "%s %02x:%04x: %s\n" "${LINE:0:1}" $BANK $ADDR "${LINE#*: }"
fi fi
done done

View File

@@ -1,25 +0,0 @@
#!/bin/bash
set -euo pipefail
if [[ $# -ne 2 ]]; then
cat <<EOF >&2
Usage: $0 <palettes.pal> <output.png>
EOF
exit 1
fi
TMP=$(mktemp -d)
readonly TMP
trap 'rm -rf "$TMP"' EXIT
tile() { for i in {0..7}; do printf "$1"; done }
{ tile '\x00\x00' && tile '\xFF\x00' && tile '\x00\xFF' && tile '\xFF\xFF'; } >"$TMP/tmp.2bpp"
NB_BYTES=$(wc -c <"$1")
(( NB_PALS = NB_BYTES / 8 ))
for (( i = 0; i < NB_PALS; i++ )); do
printf '\0\1\2\3' >>"$TMP/tmp.tilemap"
printf $(printf '\\x%x' $i{,,,}) >> "$TMP/tmp.palmap"
done
"${RGBGFX:-${RGBDS+$RGBDS/}rgbgfx}" -r 4 "$2" -o "$TMP/tmp.2bpp" -OTQ -p "$1" -n "$NB_PALS"

View File

@@ -17,21 +17,18 @@ _rgbasm_warnings() {
'empty-macro-arg:Warn on empty macro arg' 'empty-macro-arg:Warn on empty macro arg'
'empty-strrpl:Warn on calling STRRPL with empty pattern' 'empty-strrpl:Warn on calling STRRPL with empty pattern'
'large-constant:Warn on constants too large for a signed 32-bit int' 'large-constant:Warn on constants too large for a signed 32-bit int'
'long-string:Warn on strings too long'
'macro-shift:Warn when shifting macro args part their limits' 'macro-shift:Warn when shifting macro args part their limits'
'nested-comment:Warn on "/*" inside block comments' 'nested-comment:Warn on "/*" inside block comments'
'numeric-string:Warn when a multi-character string is treated as a number' 'numeric-string:Warn when a multi-character string is treated as a number'
'obsolete:Warn when using deprecated features' 'obsolete:Warn when using deprecated features'
'purge:Warn when purging exported symbols or labels'
'shift:Warn when shifting negative values' 'shift:Warn when shifting negative values'
'shift-amount:Warn when a shift'\''s operand it negative or \> 32' 'shift-amount:Warn when a shift'\''s operand it negative or \> 32'
'truncation:Warn when implicit truncation loses bits' 'truncation:Warn when implicit truncation loses bits'
'unmapped-char:Warn on unmapped character'
'unmatched-directive:Warn on unmatched directive pair'
'unterminated-load:Warn on LOAD without ENDL'
'user:Warn when executing the WARN built-in' 'user:Warn when executing the WARN built-in'
) )
# TODO: handle `no-` and `error=` somehow? # TODO: handle `no-` and `error=` somehow?
# TODO: handle `=0|1|2` levels for `numeric-string`, `purge`, `truncation`, and `unmapped-char`? # TODO: handle `=0|1|2` levels for `numeric-string` and `truncation`?
_describe warning warnings _describe warning warnings
} }
@@ -40,26 +37,24 @@ local args=(
'(- : * options)'{-V,--version}'[Print version number]' '(- : * options)'{-V,--version}'[Print version number]'
'(-E --export-all)'{-E,--export-all}'[Export all symbols]' '(-E --export-all)'{-E,--export-all}'[Export all symbols]'
'(-h --halt-without-nop)'{-h,--halt-without-nop}'[Avoid outputting a `nop` after `halt`]'
'(-L ---preserve-ld)'{-L,--preserve-ld}'[Prevent auto-optimizing `ld` into `ldh`]'
'(-v --verbose)'{-v,--verbose}'[Print additional messages regarding progression]' '(-v --verbose)'{-v,--verbose}'[Print additional messages regarding progression]'
-w'[Disable all warnings]' -w'[Disable all warnings]'
'(-b --binary-digits)'{-b,--binary-digits}'+[Change chars for binary constants]:digit spec:' '(-b --binary-digits)'{-b,--binary-digits}'+[Change chars for binary constants]:digit spec:'
'*'{-D,--define}'+[Define a string symbol]:name + value (default 1):' '*'{-D,--define}'+[Define a string symbol]:name + value (default 1):'
'(-g --gfx-chars)'{-g,--gfx-chars}'+[Change chars for gfx constants]:chars spec:' '(-g --gfx-chars)'{-g,--gfx-chars}'+[Change chars for gfx constants]:chars spec:'
'(-I --include)'{-I,--include}'+[Add an include directory]:include path:_files -/' '(-i --include)'{-i,--include}'+[Add an include directory]:include path:_files -/'
'(-M --dependfile)'{-M,--dependfile}"+[Write deps in make format]:output file:_files -g '*.{d,mk}'" '(-M --dependfile)'{-M,--dependfile}"+[List deps in make format]:output file:_files -g '*.{d,mk}'"
-MG'[Assume missing files should be generated]' -MG'[Assume missing files should be generated]'
-MP'[Add phony targets to all deps]' -MP'[Add phony targets to all deps]'
'*'-MT"+[Add a target to the rules]:target:_files -g '*.{d,mk,o}'" '*'-MT"+[Add a target to the rules]:target:_files -g '*.{d,mk,o}'"
'*'-MQ"+[Add a target to the rules]:target:_files -g '*.{d,mk,o}'" '*'-MQ"+[Add a target to the rules]:target:_files -g '*.{d,mk,o}'"
'(-o --output)'{-o,--output}'+[Output file]:output file:_files' '(-o --output)'{-o,--output}'+[Output file]:output file:_files'
'(-P --preinclude)'{-P,--preinclude}"+[Pre-include a file]:include file:_files -g '*.{asm,inc}'"
'(-p --pad-value)'{-p,--pad-value}'+[Set padding byte]:padding byte:' '(-p --pad-value)'{-p,--pad-value}'+[Set padding byte]:padding byte:'
'(-Q --q-precision)'{-Q,--q-precision}'+[Set fixed-point precision]:precision:'
'(-r --recursion-depth)'{-r,--recursion-depth}'+[Set maximum recursion depth]:depth:' '(-r --recursion-depth)'{-r,--recursion-depth}'+[Set maximum recursion depth]:depth:'
'(-s --state)'{-s,--state}"+[Write features of final state]:state file:_files -g '*.dump.asm'"
'(-W --warning)'{-W,--warning}'+[Toggle warning flags]:warning flag:_rgbasm_warnings' '(-W --warning)'{-W,--warning}'+[Toggle warning flags]:warning flag:_rgbasm_warnings'
'(-X --max-errors)'{-X,--max-errors}'+[Set maximum errors before aborting]:maximum errors:'
":assembly sources:_files -g '*.asm'" ":assembly sources:_files -g '*.asm'"
) )

View File

@@ -49,7 +49,6 @@ local args=(
'(-i --game-id)'{-i,--game-id}'+[Set game ID string]:4-char game ID:' '(-i --game-id)'{-i,--game-id}'+[Set game ID string]:4-char game ID:'
'(-k --new-licensee)'{-k,--new-licensee}'+[Set new licensee string]:2-char licensee ID:' '(-k --new-licensee)'{-k,--new-licensee}'+[Set new licensee string]:2-char licensee ID:'
'(-l --old-licensee)'{-l,--old-licensee}'+[Set old licensee ID]:licensee number:' '(-l --old-licensee)'{-l,--old-licensee}'+[Set old licensee ID]:licensee number:'
'(-L --logo)'{-L,--logo}'+[Set custom logo]:1bpp image:'
'(-m --mbc-type)'{-m,--mbc-type}"+[Set MBC flags]:mbc name:_mbc_names" '(-m --mbc-type)'{-m,--mbc-type}"+[Set MBC flags]:mbc name:_mbc_names"
'(-n --rom-version)'{-n,--rom-version}'+[Set ROM version]:rom version byte:' '(-n --rom-version)'{-n,--rom-version}'+[Set ROM version]:rom version byte:'
'(-p --pad-value)'{-p,--pad-value}'+[Pad to next valid size using this byte as padding]:padding byte:' '(-p --pad-value)'{-p,--pad-value}'+[Pad to next valid size using this byte as padding]:padding byte:'

View File

@@ -13,33 +13,23 @@ local args=(
# Arguments are listed here in the same order as in the manual, except for the version # Arguments are listed here in the same order as in the manual, except for the version
'(- : * options)'{-V,--version}'[Print version number]' '(- : * options)'{-V,--version}'[Print version number]'
'(-a --attr-map -A --auto-attr-map)'{-A,--auto-attr-map}'[Shortcut for -a <file>.attrmap]' '(-a --attr-map -A --output-attr-map)'{-A,--output-attr-map}'[Shortcut for -a <file>.attrmap]'
'(-C --color-curve)'{-C,--color-curve}'[Generate palettes using GBC color curve]' '(-C --color-curve)'{-C,--color-curve}'[Generate palettes using GBC color curve]'
'(-D --debug)'{-D,--debug}'[Enable debug features]'
'(-f --fix -F --fix-and-save)'{-f,--fix}'[Fix input PNG into an indexed image]'
'(-f --fix -F --fix-and-save)'{-F,--fix-and-save}'[Like -f but also save CLI params within the PNG]'
'(-h --horizontal)'{-h,--horizontal}'[Lay out tiles horizontally instead of vertically]'
'(-m --mirror-tiles)'{-m,--mirror-tiles}'[Eliminate mirrored tiles from output]' '(-m --mirror-tiles)'{-m,--mirror-tiles}'[Eliminate mirrored tiles from output]'
'(-O --group-outputs)'{-O,--group-outputs}'[Base "shortcut" options on the output path, not input]' '(-p --palette -P --output-palette)'{-P,--output-palette}'[Shortcut for -p <file>.pal]'
'(-p --palette -P --auto-palette)'{-P,--auto-palette}'[Shortcut for -p <file>.pal]' '(-t --tilemap -T --output-tilemap)'{-T,--output-tilemap}'[Shortcut for -t <file>.tilemap]'
'(-q --palette-map -Q --auto-palette-map)'{-Q,--auto-palette-map}'[Shortcut for -p <file>.palmap]'
'(-t --tilemap -T --auto-tilemap)'{-T,--auto-tilemap}'[Shortcut for -t <file>.tilemap]'
'(-u --unique-tiles)'{-u,--unique-tiles}'[Eliminate redundant tiles]' '(-u --unique-tiles)'{-u,--unique-tiles}'[Eliminate redundant tiles]'
{-v,--verbose}'[Enable verbose output]' '(-v --verbose)'{-v,--verbose}'[Enable verbose output]'
'(-X --mirror-x)'{-X,--mirror-x}'[Eliminate horizontally mirrored tiles from output]'
'(-Y --mirror-y)'{-Y,--mirror-y}'[Eliminate vertically mirrored tiles from output]'
'(-Z --columns)'{-Z,--columns}'[Read the image in column-major order]'
'(-a --attr-map -A --auto-attr-map)'{-a,--attr-map}'+[Generate a map of tile attributes (mirroring)]:attrmap file:_files' '(-a --attr-map -A --output-attr-map)'{-a,--attr-map}'+[Generate a map of tile attributes (mirroring)]:attrmap file:_files'
'(-b --base-tiles)'{-b,--base-tiles}'+[Base tile IDs for tile map output]:base tile IDs:'
'(-c --colors)'{-c,--colors}'+[Specify color palettes]:palette spec:'
'(-d --depth)'{-d,--depth}'+[Set bit depth]:bit depth:_depths' '(-d --depth)'{-d,--depth}'+[Set bit depth]:bit depth:_depths'
'(-i --input-tileset)'{-i,--input-tileset}'+[Use specific tiles]:tileset file:_files -g "*.2bpp"'
'(-L --slice)'{-L,--slice}'+[Only process a portion of the image]:input slice:'
'(-N --nb-tiles)'{-N,--nb-tiles}'+[Limit number of tiles]:tile count:'
'(-n --nb-palettes)'{-n,--nb-palettes}'+[Limit number of palettes]:palette count:'
'(-o --output)'{-o,--output}'+[Set output file]:output file:_files' '(-o --output)'{-o,--output}'+[Set output file]:output file:_files'
'(-p --palette -P --auto-palette)'{-p,--palette}"+[Output the image's palette in little-endian native RGB555 format]:palette file:_files" '(-p --palette -P --output-palette)'{-p,--palette}"+[Output the image's palette in little-endian native RGB555 format]:palette file:_files"
'(-q --palette-map -Q --auto-palette-map)'{-q,--palette-map}"+[Output the image's palette map]:palette map file:_files" '(-t --tilemap -T --output-tilemap)'{-t,--tilemap}'+[Generate a map of tile indices]:tilemap file:_files'
'(-r --reverse)'{-r,--reverse}'+[Yield an image from binary data]:image width (in tiles):'
'(-s --palette-size)'{-s,--palette-size}'+[Limit palette size]:palette size:'
'(-t --tilemap -T --auto-tilemap)'{-t,--tilemap}'+[Generate a map of tile indices]:tilemap file:_files'
'(-x --trim-end)'{-x,--trim-end}'+[Trim end of output by this many tiles]:tile count:' '(-x --trim-end)'{-x,--trim-end}'+[Trim end of output by this many tiles]:tile count:'
":input png file:_files -g '*.png'" ":input png file:_files -g '*.png'"

View File

@@ -11,13 +11,13 @@ local args=(
'(-x --nopad)'{-x,--nopad}'[Disable padding the end of the final file]' '(-x --nopad)'{-x,--nopad}'[Disable padding the end of the final file]'
'(-l --linkerscript)'{-l,--linkerscript}"+[Use a linker script]:linker script:_files -g '*.link'" '(-l --linkerscript)'{-l,--linkerscript}"+[Use a linker script]:linker script:_files -g '*.link'"
'(-M --no-sym-in-map)'{-M,--no-sym-in-map}'[Do not output symbol names in map file]'
'(-m --map)'{-m,--map}"+[Produce a map file]:map file:_files -g '*.map'" '(-m --map)'{-m,--map}"+[Produce a map file]:map file:_files -g '*.map'"
'(-n --sym)'(-n,--sym)"+[Produce a symbol file]:sym file:_files -g '*.sym'" '(-n --sym)'(-n,--sym)"+[Produce a symbol file]:sym file:_files -g '*.sym'"
'(-O --overlay)'{-O,--overlay}'+[Overlay sections over on top of bin file]:base overlay:_files' '(-O --overlay)'{-O,--overlay}'+[Overlay sections over on top of bin file]:base overlay:_files'
'(-o --output)'{-o,--output}"+[Write ROM image to this file]:rom file:_files -g '*.{gb,sgb,gbc}'" '(-o --output)'{-o,--output}"+[Write ROM image to this file]:rom file:_files -g '*.{gb,sgb,gbc}'"
'(-p --pad-value)'{-p,--pad-value}'+[Set padding byte]:padding byte:' '(-p --pad-value)'{-p,--pad-value}'+[Set padding byte]:padding byte:'
'(-S --scramble)'{-s,--scramble}'+[Activate scrambling]:scramble spec' '(-S --scramble)'{-s,--scramble}'+[Activate scrambling]:scramble spec'
'(-s --smart)'{-s,--smart}'+[!BROKEN! Perform smart linking from this symbol]:symbol name:'
'*'":object files:_files -g '*.o'" '*'":object files:_files -g '*.o'"
) )

23
include/asm/charmap.h Normal file
View File

@@ -0,0 +1,23 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#ifndef RGBDS_ASM_CHARMAP_H
#define RGBDS_ASM_CHARMAP_H
#include <stdint.h>
struct Charmap *charmap_New(char const *name, char const *baseName);
void charmap_Delete(struct Charmap *charmap);
void charmap_Set(char const *name);
void charmap_Push(void);
void charmap_Pop(void);
void charmap_Add(char *mapping, uint8_t value);
size_t charmap_Convert(char const *input, uint8_t *output);
size_t charmap_ConvertNext(char const **input, uint8_t **output);
#endif /* RGBDS_ASM_CHARMAP_H */

View File

@@ -1,27 +0,0 @@
/* SPDX-License-Identifier: MIT */
#ifndef RGBDS_ASM_CHARMAP_HPP
#define RGBDS_ASM_CHARMAP_HPP
#include <stdint.h>
#include <string>
#include <string_view>
#include <vector>
#define DEFAULT_CHARMAP_NAME "main"
bool charmap_ForEach(
void (*mapFunc)(std::string const &),
void (*charFunc)(std::string const &, std::vector<int32_t>)
);
void charmap_New(std::string const &name, std::string const *baseName);
void charmap_Set(std::string const &name);
void charmap_Push();
void charmap_Pop();
void charmap_CheckStack();
void charmap_Add(std::string const &mapping, std::vector<int32_t> &&value);
bool charmap_HasChar(std::string const &input);
std::vector<int32_t> charmap_Convert(std::string const &input);
size_t charmap_ConvertNext(std::string_view &input, std::vector<int32_t> *output);
#endif // RGBDS_ASM_CHARMAP_HPP

31
include/asm/fixpoint.h Normal file
View File

@@ -0,0 +1,31 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 1997-2021, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#ifndef RGBDS_ASM_FIXPOINT_H
#define RGBDS_ASM_FIXPOINT_H
#include <stdint.h>
int32_t fix_Callback_PI(void);
void fix_Print(int32_t i);
int32_t fix_Sin(int32_t i);
int32_t fix_Cos(int32_t i);
int32_t fix_Tan(int32_t i);
int32_t fix_ASin(int32_t i);
int32_t fix_ACos(int32_t i);
int32_t fix_ATan(int32_t i);
int32_t fix_ATan2(int32_t i, int32_t j);
int32_t fix_Mul(int32_t i, int32_t j);
int32_t fix_Div(int32_t i, int32_t j);
int32_t fix_Pow(int32_t i, int32_t j);
int32_t fix_Log(int32_t i, int32_t j);
int32_t fix_Round(int32_t i);
int32_t fix_Ceil(int32_t i);
int32_t fix_Floor(int32_t i);
#endif /* RGBDS_ASM_FIXPOINT_H */

View File

@@ -1,28 +0,0 @@
/* SPDX-License-Identifier: MIT */
#ifndef RGBDS_ASM_FIXPOINT_HPP
#define RGBDS_ASM_FIXPOINT_HPP
#include <stdint.h>
extern uint8_t fixPrecision;
uint8_t fix_Precision();
double fix_PrecisionFactor();
int32_t fix_Sin(int32_t i, int32_t q);
int32_t fix_Cos(int32_t i, int32_t q);
int32_t fix_Tan(int32_t i, int32_t q);
int32_t fix_ASin(int32_t i, int32_t q);
int32_t fix_ACos(int32_t i, int32_t q);
int32_t fix_ATan(int32_t i, int32_t q);
int32_t fix_ATan2(int32_t i, int32_t j, int32_t q);
int32_t fix_Mul(int32_t i, int32_t j, int32_t q);
int32_t fix_Mod(int32_t i, int32_t j, int32_t q);
int32_t fix_Div(int32_t i, int32_t j, int32_t q);
int32_t fix_Pow(int32_t i, int32_t j, int32_t q);
int32_t fix_Log(int32_t i, int32_t j, int32_t q);
int32_t fix_Round(int32_t i, int32_t q);
int32_t fix_Ceil(int32_t i, int32_t q);
int32_t fix_Floor(int32_t i, int32_t q);
#endif // RGBDS_ASM_FIXPOINT_HPP

63
include/asm/format.h Normal file
View File

@@ -0,0 +1,63 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 2020, RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#ifndef RGBDS_FORMAT_SPEC_H
#define RGBDS_FORMAT_SPEC_H
#include <stdbool.h>
#include <stdint.h>
enum FormatState {
FORMAT_SIGN, // expects '+' or ' ' (optional)
FORMAT_PREFIX, // expects '#' (optional)
FORMAT_ALIGN, // expects '-' (optional)
FORMAT_WIDTH, // expects '0'-'9', max 255 (optional) (leading '0' indicates pad)
FORMAT_FRAC, // got '.', expects '0'-'9', max 255 (optional)
FORMAT_DONE, // got [duXxbofs] (required)
FORMAT_INVALID, // got unexpected character
};
struct FormatSpec {
enum FormatState state;
int sign;
bool prefix;
bool alignLeft;
bool padZero;
size_t width;
bool hasFrac;
size_t fracWidth;
int type;
bool valid;
};
struct StrFmtArg {
union {
uint32_t number;
char *string;
};
bool isNumeric;
};
#define INITIAL_STRFMT_ARG_SIZE 4
struct StrFmtArgList {
char *format;
size_t nbArgs;
size_t capacity;
struct StrFmtArg *args;
};
struct FormatSpec fmt_NewSpec(void);
bool fmt_IsEmpty(struct FormatSpec const *fmt);
bool fmt_IsValid(struct FormatSpec const *fmt);
bool fmt_IsFinished(struct FormatSpec const *fmt);
void fmt_UseCharacter(struct FormatSpec *fmt, int c);
void fmt_FinishCharacters(struct FormatSpec *fmt);
void fmt_PrintString(char *buf, size_t bufLen, struct FormatSpec const *fmt, char const *value);
void fmt_PrintNumber(char *buf, size_t bufLen, struct FormatSpec const *fmt, uint32_t value);
#endif /* RGBDS_FORMAT_SPEC_H */

View File

@@ -1,47 +0,0 @@
/* SPDX-License-Identifier: MIT */
#ifndef RGBDS_ASM_FORMAT_HPP
#define RGBDS_ASM_FORMAT_HPP
#include <stddef.h>
#include <stdint.h>
#include <string>
enum FormatState {
FORMAT_SIGN, // expects '+' or ' ' (optional)
FORMAT_EXACT, // expects '#' (optional)
FORMAT_ALIGN, // expects '-' (optional)
FORMAT_WIDTH, // expects '0'-'9', max 255 (optional) (leading '0' indicates pad)
FORMAT_FRAC, // got '.', expects '0'-'9', max 255 (optional)
FORMAT_PREC, // got 'q', expects '0'-'9', range 1-31 (optional)
FORMAT_DONE, // got [duXxbofs] (required)
FORMAT_INVALID, // got unexpected character
};
class FormatSpec {
FormatState state;
int sign;
bool exact;
bool alignLeft;
bool padZero;
size_t width;
bool hasFrac;
size_t fracWidth;
bool hasPrec;
size_t precision;
int type;
bool valid;
public:
bool isEmpty() const { return !state; }
bool isValid() const { return valid || state == FORMAT_DONE; }
bool isFinished() const { return state >= FORMAT_DONE; }
void useCharacter(int c);
void finishCharacters();
void appendString(std::string &str, std::string const &value) const;
void appendNumber(std::string &str, uint32_t value) const;
};
#endif // RGBDS_ASM_FORMAT_HPP

83
include/asm/fstack.h Normal file
View File

@@ -0,0 +1,83 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
/*
* Contains some assembler-wide defines and externs
*/
#ifndef RGBDS_ASM_FSTACK_H
#define RGBDS_ASM_FSTACK_H
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include "asm/lexer.h"
struct FileStackNode {
struct FileStackNode *parent; /* Pointer to parent node, for error reporting */
/* Line at which the parent context was exited; meaningless for the root level */
uint32_t lineNo;
struct FileStackNode *next; /* Next node in the output linked list */
bool referenced; /* If referenced, don't free! */
uint32_t ID; /* Set only if referenced: ID within the object file, -1 if not output yet */
enum {
NODE_REPT,
NODE_FILE,
NODE_MACRO,
} type;
};
struct FileStackReptNode { /* NODE_REPT */
struct FileStackNode node;
uint32_t reptDepth;
/* WARNING: if changing this type, change overflow check in `fstk_Init` */
uint32_t iters[]; /* REPT iteration counts since last named node, in reverse depth order */
};
struct FileStackNamedNode { /* NODE_FILE, NODE_MACRO */
struct FileStackNode node;
char name[]; /* File name for files, file::macro name for macros */
};
extern size_t maxRecursionDepth;
struct MacroArgs;
void fstk_Dump(struct FileStackNode const *node, uint32_t lineNo);
void fstk_DumpCurrent(void);
struct FileStackNode *fstk_GetFileStack(void);
/* The lifetime of the returned chars is until reaching the end of that file */
char const *fstk_GetFileName(void);
void fstk_AddIncludePath(char const *s);
/**
* @param path The user-provided file name
* @param fullPath The address of a pointer, which will be made to point at the full path
* The pointer's value must be a valid argument to `realloc`, including NULL
* @param size Current size of the buffer, or 0 if the pointer is NULL
* @return True if the file was found, false if no path worked
*/
bool fstk_FindFile(char const *path, char **fullPath, size_t *size);
bool yywrap(void);
void fstk_RunInclude(char const *path);
void fstk_RunMacro(char const *macroName, struct MacroArgs *args);
void fstk_RunRept(uint32_t count, int32_t reptLineNo, char *body, size_t size);
void fstk_RunFor(char const *symName, int32_t start, int32_t stop, int32_t step,
int32_t reptLineNo, char *body, size_t size);
void fstk_StopRept(void);
bool fstk_Break(void);
void fstk_NewRecursionDepth(size_t newDepth);
void fstk_Init(char const *mainPath, size_t maxDepth);
#endif /* RGBDS_ASM_FSTACK_H */

View File

@@ -1,84 +0,0 @@
/* SPDX-License-Identifier: MIT */
// Contains some assembler-wide defines and externs
#ifndef RGBDS_ASM_FSTACK_HPP
#define RGBDS_ASM_FSTACK_HPP
#include <memory>
#include <optional>
#include <stdint.h>
#include <stdio.h>
#include <string>
#include <vector>
#include "either.hpp"
#include "linkdefs.hpp"
#include "asm/lexer.hpp"
struct FileStackNode {
FileStackNodeType type;
Either<
std::vector<uint32_t>, // NODE_REPT
std::string // NODE_FILE, NODE_MACRO
>
data;
std::shared_ptr<FileStackNode> parent; // Pointer to parent node, for error reporting
// Line at which the parent context was exited
// Meaningless at the root level, but gets written to the object file anyway, so init it
uint32_t lineNo = 0;
// Set only if referenced: ID within the object file, `UINT32_MAX` if not output yet
uint32_t ID = UINT32_MAX;
// REPT iteration counts since last named node, in reverse depth order
std::vector<uint32_t> &iters() { return data.get<std::vector<uint32_t>>(); }
std::vector<uint32_t> const &iters() const { return data.get<std::vector<uint32_t>>(); }
// File name for files, file::macro name for macros
std::string &name() { return data.get<std::string>(); }
std::string const &name() const { return data.get<std::string>(); }
FileStackNode(FileStackNodeType type_, Either<std::vector<uint32_t>, std::string> data_)
: type(type_), data(data_){};
std::string const &dump(uint32_t curLineNo) const;
// If true, entering this context generates a new unique ID.
bool generatesUniqueID() const { return type == NODE_REPT || type == NODE_MACRO; }
};
#define DEFAULT_MAX_DEPTH 64
extern size_t maxRecursionDepth;
struct MacroArgs;
void fstk_DumpCurrent();
std::shared_ptr<FileStackNode> fstk_GetFileStack();
std::shared_ptr<std::string> fstk_GetUniqueIDStr();
MacroArgs *fstk_GetCurrentMacroArgs();
void fstk_AddIncludePath(std::string const &path);
void fstk_SetPreIncludeFile(std::string const &path);
std::optional<std::string> fstk_FindFile(std::string const &path);
bool yywrap();
void fstk_RunInclude(std::string const &path, bool updateStateNow);
void fstk_RunMacro(std::string const &macroName, std::shared_ptr<MacroArgs> macroArgs);
void fstk_RunRept(uint32_t count, int32_t reptLineNo, ContentSpan const &span);
void fstk_RunFor(
std::string const &symName,
int32_t start,
int32_t stop,
int32_t step,
int32_t reptLineNo,
ContentSpan const &span
);
void fstk_StopRept();
bool fstk_Break();
void fstk_NewRecursionDepth(size_t newDepth);
void fstk_Init(std::string const &mainPath, size_t maxDepth);
#endif // RGBDS_ASM_FSTACK_HPP

102
include/asm/lexer.h Normal file
View File

@@ -0,0 +1,102 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#ifndef RGBDS_ASM_LEXER_H
#define RGBDS_ASM_LEXER_H
#include <stdbool.h>
#define MAXSTRLEN 255
struct LexerState;
extern struct LexerState *lexerState;
extern struct LexerState *lexerStateEOL;
static inline struct LexerState *lexer_GetState(void)
{
return lexerState;
}
static inline void lexer_SetState(struct LexerState *state)
{
lexerState = state;
}
static inline void lexer_SetStateAtEOL(struct LexerState *state)
{
lexerStateEOL = state;
}
extern char binDigits[2];
extern char gfxDigits[4];
static inline void lexer_SetBinDigits(char const digits[2])
{
binDigits[0] = digits[0];
binDigits[1] = digits[1];
}
static inline void lexer_SetGfxDigits(char const digits[4])
{
gfxDigits[0] = digits[0];
gfxDigits[1] = digits[1];
gfxDigits[2] = digits[2];
gfxDigits[3] = digits[3];
}
/*
* `path` is referenced, but not held onto..!
*/
struct LexerState *lexer_OpenFile(char const *path);
struct LexerState *lexer_OpenFileView(char const *path, char *buf, size_t size, uint32_t lineNo);
void lexer_RestartRept(uint32_t lineNo);
void lexer_DeleteState(struct LexerState *state);
void lexer_Init(void);
enum LexerMode {
LEXER_NORMAL,
LEXER_RAW,
LEXER_SKIP_TO_ELIF,
LEXER_SKIP_TO_ENDC,
LEXER_SKIP_TO_ENDR
};
void lexer_SetMode(enum LexerMode mode);
void lexer_ToggleStringExpansion(bool enable);
uint32_t lexer_GetIFDepth(void);
void lexer_IncIFDepth(void);
void lexer_DecIFDepth(void);
bool lexer_RanIFBlock(void);
bool lexer_ReachedELSEBlock(void);
void lexer_RunIFBlock(void);
void lexer_ReachELSEBlock(void);
struct CaptureBody {
uint32_t lineNo;
char *body;
size_t size;
};
void lexer_CheckRecursionDepth(void);
char const *lexer_GetFileName(void);
uint32_t lexer_GetLineNo(void);
uint32_t lexer_GetColNo(void);
void lexer_DumpStringExpansions(void);
int yylex(void);
bool lexer_CaptureRept(struct CaptureBody *capture);
bool lexer_CaptureMacroBody(struct CaptureBody *capture);
#define INITIAL_DS_ARG_SIZE 2
struct DsArgList {
size_t nbArgs;
size_t capacity;
struct Expression *args;
};
#endif /* RGBDS_ASM_LEXER_H */

View File

@@ -1,161 +0,0 @@
/* SPDX-License-Identifier: MIT */
#ifndef RGBDS_ASM_LEXER_HPP
#define RGBDS_ASM_LEXER_HPP
#include <deque>
#include <memory>
#include <optional>
#include <stdint.h>
#include <string>
#include <vector>
#include "either.hpp"
#include "platform.hpp" // SSIZE_MAX
// This value is a compromise between `LexerState` allocation performance when `mmap` works, and
// buffering performance when it doesn't/can't (e.g. when piping a file into RGBASM).
#define LEXER_BUF_SIZE 64
// The buffer needs to be large enough for the maximum `lexerState->peek()` lookahead distance
static_assert(LEXER_BUF_SIZE > 1, "Lexer buffer size is too small");
// This caps the size of buffer reads, and according to POSIX, passing more than SSIZE_MAX is UB
static_assert(LEXER_BUF_SIZE <= SSIZE_MAX, "Lexer buffer size is too large");
enum LexerMode {
LEXER_NORMAL,
LEXER_RAW,
LEXER_SKIP_TO_ELIF,
LEXER_SKIP_TO_ENDC,
LEXER_SKIP_TO_ENDR,
NB_LEXER_MODES
};
struct Expansion {
std::optional<std::string> name;
std::shared_ptr<std::string> contents;
size_t offset; // Cursor into `contents`
size_t size() const { return contents->size(); }
bool advance(); // Increment `offset`; return whether it then exceeds `contents`
};
struct ContentSpan {
std::shared_ptr<char[]> ptr;
size_t size;
};
struct ViewedContent {
ContentSpan span; // Span of chars
size_t offset = 0; // Cursor into `span.ptr`
ViewedContent(ContentSpan const &span_) : span(span_) {}
ViewedContent(std::shared_ptr<char[]> ptr, size_t size) : span({.ptr = ptr, .size = size}) {}
std::shared_ptr<char[]> makeSharedContentPtr() const {
return std::shared_ptr<char[]>(span.ptr, &span.ptr[offset]);
}
};
struct BufferedContent {
int fd; // File from which to read chars
char buf[LEXER_BUF_SIZE] = {}; // Circular buffer of chars
size_t offset = 0; // Cursor into `buf`
size_t size = 0; // Number of "fresh" chars in `buf`
BufferedContent(int fd_) : fd(fd_) {}
~BufferedContent();
void advance(); // Increment `offset` circularly, decrement `size`
void refill(); // Read from `fd` to fill `buf`
private:
size_t readMore(size_t startIndex, size_t nbChars);
};
struct IfStackEntry {
bool ranIfBlock; // Whether an IF/ELIF/ELSE block ran already
bool reachedElseBlock; // Whether an ELSE block ran already
};
struct LexerState {
std::string path;
LexerMode mode;
bool atLineStart;
uint32_t lineNo;
uint32_t colNo;
int lastToken;
std::deque<IfStackEntry> ifStack;
bool capturing; // Whether the text being lexed should be captured
size_t captureSize; // Amount of text captured
std::shared_ptr<std::vector<char>> captureBuf; // Buffer to send the captured text to if set
bool disableMacroArgs;
bool disableInterpolation;
size_t macroArgScanDistance; // Max distance already scanned for macro args
bool expandStrings;
std::deque<Expansion> expansions; // Front is the innermost current expansion
Either<ViewedContent, BufferedContent> content;
~LexerState();
int peekChar();
int peekCharAhead();
std::shared_ptr<char[]> makeSharedCaptureBufPtr() const {
return std::shared_ptr<char[]>(captureBuf, captureBuf->data());
}
void setAsCurrentState();
bool setFileAsNextState(std::string const &filePath, bool updateStateNow);
void setViewAsNextState(char const *name, ContentSpan const &span, uint32_t lineNo_);
void clear(uint32_t lineNo_);
};
extern char binDigits[2];
extern char gfxDigits[4];
static inline void lexer_SetBinDigits(char const digits[2]) {
binDigits[0] = digits[0];
binDigits[1] = digits[1];
}
static inline void lexer_SetGfxDigits(char const digits[4]) {
gfxDigits[0] = digits[0];
gfxDigits[1] = digits[1];
gfxDigits[2] = digits[2];
gfxDigits[3] = digits[3];
}
bool lexer_AtTopLevel();
void lexer_RestartRept(uint32_t lineNo);
void lexer_Init();
void lexer_SetMode(LexerMode mode);
void lexer_ToggleStringExpansion(bool enable);
uint32_t lexer_GetIFDepth();
void lexer_IncIFDepth();
void lexer_DecIFDepth();
bool lexer_RanIFBlock();
bool lexer_ReachedELSEBlock();
void lexer_RunIFBlock();
void lexer_ReachELSEBlock();
void lexer_CheckRecursionDepth();
uint32_t lexer_GetLineNo();
uint32_t lexer_GetColNo();
void lexer_DumpStringExpansions();
struct Capture {
uint32_t lineNo;
ContentSpan span;
};
Capture lexer_CaptureRept();
Capture lexer_CaptureMacro();
#endif // RGBDS_ASM_LEXER_HPP

37
include/asm/macro.h Normal file
View File

@@ -0,0 +1,37 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 2020, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#ifndef RGBDS_MACRO_H
#define RGBDS_MACRO_H
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include "asm/warning.h"
#include "helpers.h"
struct MacroArgs;
struct MacroArgs *macro_GetCurrentArgs(void);
struct MacroArgs *macro_NewArgs(void);
void macro_AppendArg(struct MacroArgs **args, char *s);
void macro_UseNewArgs(struct MacroArgs *args);
void macro_FreeArgs(struct MacroArgs *args);
char const *macro_GetArg(uint32_t i);
char const *macro_GetAllArgs(void);
uint32_t macro_GetUniqueID(void);
char const *macro_GetUniqueIDStr(void);
void macro_SetUniqueID(uint32_t id);
uint32_t macro_UseNewUniqueID(void);
void macro_ShiftCurrentArgs(int32_t count);
uint32_t macro_NbArgs(void);
#endif

View File

@@ -1,23 +0,0 @@
/* SPDX-License-Identifier: MIT */
#ifndef RGBDS_ASM_MACRO_HPP
#define RGBDS_ASM_MACRO_HPP
#include <memory>
#include <stdint.h>
#include <string>
#include <vector>
struct MacroArgs {
unsigned int shift;
std::vector<std::shared_ptr<std::string>> args;
uint32_t nbArgs() const { return args.size() - shift; }
std::shared_ptr<std::string> getArg(uint32_t i) const;
std::shared_ptr<std::string> getAllArgs() const;
void appendArg(std::shared_ptr<std::string> arg);
void shiftArgs(int32_t count);
};
#endif // RGBDS_ASM_MACRO_HPP

29
include/asm/main.h Normal file
View File

@@ -0,0 +1,29 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 1997-2021, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#ifndef RGBDS_MAIN_H
#define RGBDS_MAIN_H
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include "helpers.h"
extern bool haltnop;
extern bool optimizeLoads;
extern bool verbose;
extern bool warnings; /* True to enable warnings, false to disable them. */
extern FILE *dependfile;
extern char *targetFileName;
extern bool generatedMissingIncludes;
extern bool failedOnMissingInclude;
extern bool generatePhonyDeps;
#endif /* RGBDS_MAIN_H */

View File

@@ -1,18 +0,0 @@
/* SPDX-License-Identifier: MIT */
#ifndef RGBDS_ASM_MAIN_HPP
#define RGBDS_ASM_MAIN_HPP
#include <stdio.h>
#include <string>
extern bool verbose;
extern bool warnings; // True to enable warnings, false to disable them.
extern FILE *dependFile;
extern std::string targetFileName;
extern bool generatedMissingIncludes;
extern bool failedOnMissingInclude;
extern bool generatePhonyDeps;
#endif // RGBDS_ASM_MAIN_HPP

25
include/asm/opt.h Normal file
View File

@@ -0,0 +1,25 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 2021, Eldred Habert and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#ifndef RGBDS_OPT_H
#define RGBDS_OPT_H
#include <stdbool.h>
#include <stdint.h>
void opt_B(char const chars[2]);
void opt_G(char const chars[4]);
void opt_P(uint8_t fill);
void opt_L(bool optimize);
void opt_W(char const *flag);
void opt_Parse(char const *option);
void opt_Push(void);
void opt_Pop(void);
#endif

View File

@@ -1,19 +0,0 @@
/* SPDX-License-Identifier: MIT */
#ifndef RGBDS_ASM_OPT_HPP
#define RGBDS_ASM_OPT_HPP
#include <stdint.h>
void opt_B(char const chars[2]);
void opt_G(char const chars[4]);
void opt_P(uint8_t padByte);
void opt_Q(uint8_t precision);
void opt_W(char const *flag);
void opt_Parse(char const *option);
void opt_Push();
void opt_Pop();
void opt_CheckStack();
#endif // RGBDS_ASM_OPT_HPP

30
include/asm/output.h Normal file
View File

@@ -0,0 +1,30 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#ifndef RGBDS_ASM_OUTPUT_H
#define RGBDS_ASM_OUTPUT_H
#include <stdint.h>
#include "linkdefs.h"
struct Expression;
struct FileStackNode;
extern char *objectName;
extern struct Section *sectionList;
void out_RegisterNode(struct FileStackNode *node);
void out_ReplaceNode(struct FileStackNode *node);
void out_SetFileName(char *s);
void out_CreatePatch(uint32_t type, struct Expression const *expr, uint32_t ofs, uint32_t pcShift);
bool out_CreateAssert(enum AssertionType type, struct Expression const *expr,
char const *message, uint32_t ofs);
void out_WriteObject(void);
#endif /* RGBDS_ASM_OUTPUT_H */

View File

@@ -1,37 +0,0 @@
/* SPDX-License-Identifier: MIT */
#ifndef RGBDS_ASM_OUTPUT_HPP
#define RGBDS_ASM_OUTPUT_HPP
#include <memory>
#include <stdint.h>
#include <string>
#include <unordered_map>
#include <vector>
#include "linkdefs.hpp"
struct Expression;
struct FileStackNode;
enum StateFeature {
STATE_EQU,
STATE_VAR,
STATE_EQUS,
STATE_CHAR,
STATE_MACRO,
NB_STATE_FEATURES
};
extern std::string objectFileName;
void out_RegisterNode(std::shared_ptr<FileStackNode> node);
void out_SetFileName(std::string const &name);
void out_CreatePatch(uint32_t type, Expression const &expr, uint32_t ofs, uint32_t pcShift);
void out_CreateAssert(
AssertionType type, Expression const &expr, std::string const &message, uint32_t ofs
);
void out_WriteObject();
void out_WriteState(std::string name, std::vector<StateFeature> const &features);
#endif // RGBDS_ASM_OUTPUT_HPP

70
include/asm/rpn.h Normal file
View File

@@ -0,0 +1,70 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#ifndef RGBDS_ASM_RPN_H
#define RGBDS_ASM_RPN_H
#include <stdint.h>
#include <stdbool.h>
#include "linkdefs.h"
#define MAXRPNLEN 1048576
struct Expression {
int32_t val; // If the expression's value is known, it's here
char *reason; // Why the expression is not known, if it isn't
bool isKnown; // Whether the expression's value is known
bool isSymbol; // Whether the expression represents a symbol
uint8_t *rpn; // Array of bytes serializing the RPN expression
uint32_t rpnCapacity; // Size of the `rpn` buffer
uint32_t rpnLength; // Used size of the `rpn` buffer
uint32_t rpnPatchSize; // Size the expression will take in the object file
};
/*
* Determines if an expression is known at assembly time
*/
static inline bool rpn_isKnown(struct Expression const *expr)
{
return expr->isKnown;
}
/*
* Determines if an expression is a symbol suitable for const diffing
*/
static inline bool rpn_isSymbol(const struct Expression *expr)
{
return expr->isSymbol;
}
void rpn_Symbol(struct Expression *expr, char const *symName);
void rpn_Number(struct Expression *expr, uint32_t i);
void rpn_LOGNOT(struct Expression *expr, const struct Expression *src);
struct Symbol const *rpn_SymbolOf(struct Expression const *expr);
bool rpn_IsDiffConstant(struct Expression const *src, struct Symbol const *symName);
void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr,
const struct Expression *src1,
const struct Expression *src2);
void rpn_HIGH(struct Expression *expr, const struct Expression *src);
void rpn_LOW(struct Expression *expr, const struct Expression *src);
void rpn_ISCONST(struct Expression *expr, const struct Expression *src);
void rpn_UNNEG(struct Expression *expr, const struct Expression *src);
void rpn_UNNOT(struct Expression *expr, const struct Expression *src);
void rpn_BankSymbol(struct Expression *expr, char const *symName);
void rpn_BankSection(struct Expression *expr, char const *sectionName);
void rpn_BankSelf(struct Expression *expr);
void rpn_SizeOfSection(struct Expression *expr, char const *sectionName);
void rpn_StartOfSection(struct Expression *expr, char const *sectionName);
void rpn_Free(struct Expression *expr);
void rpn_CheckHRAM(struct Expression *expr, const struct Expression *src);
void rpn_CheckRST(struct Expression *expr, const struct Expression *src);
void rpn_CheckNBit(struct Expression const *expr, uint8_t n);
int32_t rpn_GetConstVal(struct Expression const *expr);
#endif /* RGBDS_ASM_RPN_H */

View File

@@ -1,69 +0,0 @@
/* SPDX-License-Identifier: MIT */
#ifndef RGBDS_ASM_RPN_HPP
#define RGBDS_ASM_RPN_HPP
#include <stdint.h>
#include <string>
#include <vector>
#include "either.hpp"
#include "linkdefs.hpp"
struct Symbol;
struct Expression {
Either<
int32_t, // If the expression's value is known, it's here
std::string // Why the expression is not known, if it isn't
>
data = 0;
bool isSymbol = false; // Whether the expression represents a symbol suitable for const diffing
std::vector<uint8_t> rpn{}; // Bytes serializing the RPN expression
uint32_t rpnPatchSize = 0; // Size the expression will take in the object file
Expression() = default;
Expression(Expression &&) = default;
#ifdef _MSC_VER
// MSVC and WinFlexBison won't build without this...
Expression(Expression const &) = default;
#endif
Expression &operator=(Expression &&) = default;
bool isKnown() const {
return data.holds<int32_t>();
}
int32_t value() const {
return data.get<int32_t>();
}
int32_t getConstVal() const;
Symbol const *symbolOf() const;
bool isDiffConstant(Symbol const *symName) const;
void makeNumber(uint32_t value);
void makeSymbol(std::string const &symName);
void makeBankSymbol(std::string const &symName);
void makeBankSection(std::string const &sectName);
void makeSizeOfSection(std::string const &sectName);
void makeStartOfSection(std::string const &sectName);
void makeSizeOfSectionType(SectionType type);
void makeStartOfSectionType(SectionType type);
void makeUnaryOp(RPNCommand op, Expression &&src);
void makeBinaryOp(RPNCommand op, Expression &&src1, Expression const &src2);
bool makeCheckHRAM();
void makeCheckRST();
void checkNBit(uint8_t n) const;
private:
void clear();
uint8_t *reserveSpace(uint32_t size);
uint8_t *reserveSpace(uint32_t size, uint32_t patchSize);
};
bool checkNBit(int32_t v, uint8_t n, char const *name);
#endif // RGBDS_ASM_RPN_HPP

82
include/asm/section.h Normal file
View File

@@ -0,0 +1,82 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 2020, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#ifndef RGBDS_SECTION_H
#define RGBDS_SECTION_H
#include <stdint.h>
#include <stdbool.h>
#include "linkdefs.h"
#include "platform.h" // NONNULL
extern uint8_t fillByte;
struct Expression;
struct Section {
char *name;
enum SectionType type;
enum SectionModifier modifier;
struct FileStackNode *src; /* Where the section was defined */
uint32_t fileLine; /* Line where the section was defined */
uint32_t size;
uint32_t org;
uint32_t bank;
uint8_t align; // Exactly as specified in `ALIGN[]`
uint16_t alignOfs;
struct Section *next;
struct Patch *patches;
uint8_t *data;
};
struct SectionSpec {
uint32_t bank;
uint8_t alignment;
uint16_t alignOfs;
};
extern struct Section *currentSection;
struct Section *sect_FindSectionByName(char const *name);
void sect_NewSection(char const *name, uint32_t secttype, uint32_t org,
struct SectionSpec const *attributes, enum SectionModifier mod);
void sect_SetLoadSection(char const *name, uint32_t secttype, uint32_t org,
struct SectionSpec const *attributes, enum SectionModifier mod);
void sect_EndLoadSection(void);
struct Section *sect_GetSymbolSection(void);
uint32_t sect_GetSymbolOffset(void);
uint32_t sect_GetOutputOffset(void);
void sect_AlignPC(uint8_t alignment, uint16_t offset);
void sect_StartUnion(void);
void sect_NextUnionMember(void);
void sect_EndUnion(void);
void sect_CheckUnionClosed(void);
void sect_AbsByte(uint8_t b);
void sect_AbsByteGroup(uint8_t const *s, size_t length);
void sect_AbsWordGroup(uint8_t const *s, size_t length);
void sect_AbsLongGroup(uint8_t const *s, size_t length);
void sect_Skip(uint32_t skip, bool ds);
void sect_String(char const *s);
void sect_RelByte(struct Expression *expr, uint32_t pcShift);
void sect_RelBytes(uint32_t n, struct Expression *exprs, size_t size);
void sect_RelWord(struct Expression *expr, uint32_t pcShift);
void sect_RelLong(struct Expression *expr, uint32_t pcShift);
void sect_PCRelByte(struct Expression *expr, uint32_t pcShift);
void sect_BinaryFile(char const *s, int32_t startPos);
void sect_BinaryFileSlice(char const *s, int32_t start_pos, int32_t length);
void sect_PushSection(void);
void sect_PopSection(void);
bool sect_IsSizeKnown(struct Section const NONNULL(name));
#endif

View File

@@ -1,107 +0,0 @@
/* SPDX-License-Identifier: MIT */
#ifndef RGBDS_ASM_SECTION_HPP
#define RGBDS_ASM_SECTION_HPP
#include <deque>
#include <memory>
#include <stdint.h>
#include <string>
#include <unordered_map>
#include <vector>
#include "linkdefs.hpp"
extern uint8_t fillByte;
struct Expression;
struct FileStackNode;
struct Section;
struct Patch {
std::shared_ptr<FileStackNode> src;
uint32_t lineNo;
uint32_t offset;
Section *pcSection;
uint32_t pcOffset;
uint8_t type;
std::vector<uint8_t> rpn;
};
struct Section {
std::string name;
SectionType type;
SectionModifier modifier;
std::shared_ptr<FileStackNode> src; // Where the section was defined
uint32_t fileLine; // Line where the section was defined
uint32_t size;
uint32_t org;
uint32_t bank;
uint8_t align; // Exactly as specified in `ALIGN[]`
uint16_t alignOfs;
std::deque<Patch> patches;
std::vector<uint8_t> data;
bool isSizeKnown() const;
};
struct SectionSpec {
uint32_t bank;
uint8_t alignment;
uint16_t alignOfs;
};
extern std::deque<Section> sectionList;
extern std::unordered_map<std::string, size_t> sectionMap; // Indexes into `sectionList`
extern Section *currentSection;
Section *sect_FindSectionByName(std::string const &name);
void sect_NewSection(
std::string const &name,
SectionType type,
uint32_t org,
SectionSpec const &attrs,
SectionModifier mod
);
void sect_SetLoadSection(
std::string const &name,
SectionType type,
uint32_t org,
SectionSpec const &attrs,
SectionModifier mod
);
void sect_EndLoadSection(char const *cause);
void sect_CheckLoadClosed();
Section *sect_GetSymbolSection();
uint32_t sect_GetSymbolOffset();
uint32_t sect_GetOutputOffset();
uint32_t sect_GetAlignBytes(uint8_t alignment, uint16_t offset);
void sect_AlignPC(uint8_t alignment, uint16_t offset);
void sect_CheckSizes();
void sect_StartUnion();
void sect_NextUnionMember();
void sect_EndUnion();
void sect_CheckUnionClosed();
void sect_ConstByte(uint8_t byte);
void sect_ByteString(std::vector<int32_t> const &string);
void sect_WordString(std::vector<int32_t> const &string);
void sect_LongString(std::vector<int32_t> const &string);
void sect_Skip(uint32_t skip, bool ds);
void sect_RelByte(Expression &expr, uint32_t pcShift);
void sect_RelBytes(uint32_t n, std::vector<Expression> &exprs);
void sect_RelWord(Expression &expr, uint32_t pcShift);
void sect_RelLong(Expression &expr, uint32_t pcShift);
void sect_PCRelByte(Expression &expr, uint32_t pcShift);
void sect_BinaryFile(std::string const &name, int32_t startPos);
void sect_BinaryFileSlice(std::string const &name, int32_t startPos, int32_t length);
void sect_EndSection();
void sect_PushSection();
void sect_PopSection();
void sect_CheckStack();
#endif // RGBDS_ASM_SECTION_HPP

150
include/asm/symbol.h Normal file
View File

@@ -0,0 +1,150 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 1997-2020, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#ifndef RGBDS_SYMBOL_H
#define RGBDS_SYMBOL_H
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <time.h>
#include "asm/section.h"
#include "platform.h" // MIN_NB_ELMS
#define MAXSYMLEN 255
enum SymbolType {
SYM_LABEL,
SYM_EQU,
SYM_VAR,
SYM_MACRO,
SYM_EQUS,
SYM_REF // Forward reference to a label
};
struct Symbol {
char name[MAXSYMLEN + 1];
enum SymbolType type;
bool isExported; /* Whether the symbol is to be exported */
bool isBuiltin; /* Whether the symbol is a built-in */
struct Section *section;
struct FileStackNode *src; /* Where the symbol was defined */
uint32_t fileLine; /* Line where the symbol was defined */
bool hasCallback;
union {
/* If sym_IsNumeric */
int32_t value;
int32_t (*numCallback)(void);
/* For SYM_MACRO and SYM_EQUS; TODO: have separate fields */
struct {
size_t macroSize;
char *macro;
};
/* For SYM_EQUS */
char const *(*strCallback)(void);
};
uint32_t ID; /* ID of the symbol in the object file (-1 if none) */
struct Symbol *next; /* Next object to output in the object file */
};
bool sym_IsPC(struct Symbol const *sym);
static inline bool sym_IsDefined(struct Symbol const *sym)
{
return sym->type != SYM_REF;
}
static inline struct Section *sym_GetSection(struct Symbol const *sym)
{
return sym_IsPC(sym) ? sect_GetSymbolSection() : sym->section;
}
static inline bool sym_IsConstant(struct Symbol const *sym)
{
if (sym->type == SYM_LABEL) {
struct Section const *sect = sym_GetSection(sym);
return sect && sect->org != (uint32_t)-1;
}
return sym->type == SYM_EQU || sym->type == SYM_VAR;
}
static inline bool sym_IsNumeric(struct Symbol const *sym)
{
return sym->type == SYM_LABEL || sym->type == SYM_EQU || sym->type == SYM_VAR;
}
static inline bool sym_IsLabel(struct Symbol const *sym)
{
return sym->type == SYM_LABEL || sym->type == SYM_REF;
}
static inline bool sym_IsLocal(struct Symbol const *sym)
{
return sym_IsLabel(sym) && strchr(sym->name, '.');
}
static inline bool sym_IsExported(struct Symbol const *sym)
{
return sym->isExported;
}
/*
* Get a string equate's value
*/
static inline char const *sym_GetStringValue(struct Symbol const *sym)
{
if (sym->hasCallback)
return sym->strCallback();
return sym->macro;
}
void sym_ForEach(void (*func)(struct Symbol *, void *), void *arg);
int32_t sym_GetValue(struct Symbol const *sym);
void sym_SetExportAll(bool set);
struct Symbol *sym_AddLocalLabel(char const *symName);
struct Symbol *sym_AddLabel(char const *symName);
struct Symbol *sym_AddAnonLabel(void);
void sym_WriteAnonLabelName(char buf[MIN_NB_ELMS(MAXSYMLEN + 1)], uint32_t ofs, bool neg);
void sym_Export(char const *symName);
struct Symbol *sym_AddEqu(char const *symName, int32_t value);
struct Symbol *sym_RedefEqu(char const *symName, int32_t value);
struct Symbol *sym_AddVar(char const *symName, int32_t value);
uint32_t sym_GetPCValue(void);
uint32_t sym_GetConstantSymValue(struct Symbol const *sym);
uint32_t sym_GetConstantValue(char const *symName);
/*
* Find a symbol by exact name, bypassing expansion checks
*/
struct Symbol *sym_FindExactSymbol(char const *symName);
/*
* Find a symbol by exact name; may not be scoped, produces an error if it is
*/
struct Symbol *sym_FindUnscopedSymbol(char const *symName);
/*
* Find a symbol, possibly scoped, by name
*/
struct Symbol *sym_FindScopedSymbol(char const *symName);
struct Symbol const *sym_GetPC(void);
struct Symbol *sym_AddMacro(char const *symName, int32_t defLineNo, char *body, size_t size);
struct Symbol *sym_Ref(char const *symName);
struct Symbol *sym_AddString(char const *symName, char const *value);
struct Symbol *sym_RedefString(char const *symName, char const *value);
void sym_Purge(char const *symName);
void sym_Init(time_t now);
/* Functions to save and restore the current symbol scope. */
char const *sym_GetCurrentSymbolScope(void);
void sym_SetCurrentSymbolScope(char const *newScope);
#endif /* RGBDS_SYMBOL_H */

View File

@@ -1,107 +0,0 @@
/* SPDX-License-Identifier: MIT */
#ifndef RGBDS_ASM_SYMBOL_HPP
#define RGBDS_ASM_SYMBOL_HPP
#include <memory>
#include <stdint.h>
#include <string.h>
#include <string>
#include <string_view>
#include <time.h>
#include <utility>
#include <variant>
#include "asm/lexer.hpp"
#include "asm/section.hpp"
enum SymbolType {
SYM_LABEL,
SYM_EQU,
SYM_VAR,
SYM_MACRO,
SYM_EQUS,
SYM_REF // Forward reference to a label
};
struct Symbol; // For the `sym_IsPC` forward declaration
bool sym_IsPC(Symbol const *sym); // For the inline `getSection` method
struct Symbol {
std::string name;
SymbolType type;
bool isExported; // Whether the symbol is to be exported
bool isBuiltin; // Whether the symbol is a built-in
Section *section;
std::shared_ptr<FileStackNode> src; // Where the symbol was defined
uint32_t fileLine; // Line where the symbol was defined
std::variant<
int32_t, // If isNumeric()
int32_t (*)(), // If isNumeric() via a callback
ContentSpan, // For SYM_MACRO
std::shared_ptr<std::string>, // For SYM_EQUS
std::shared_ptr<std::string> (*)() // For SYM_EQUS via a callback
>
data;
uint32_t ID; // ID of the symbol in the object file (`UINT32_MAX` if none)
uint32_t defIndex; // Ordering of the symbol in the state file
bool isDefined() const { return type != SYM_REF; }
bool isNumeric() const { return type == SYM_LABEL || type == SYM_EQU || type == SYM_VAR; }
bool isLabel() const { return type == SYM_LABEL || type == SYM_REF; }
bool isConstant() const {
if (type == SYM_LABEL) {
Section const *sect = getSection();
return sect && sect->org != UINT32_MAX;
}
return type == SYM_EQU || type == SYM_VAR;
}
Section *getSection() const { return sym_IsPC(this) ? sect_GetSymbolSection() : section; }
int32_t getValue() const;
int32_t getOutputValue() const;
ContentSpan const &getMacro() const;
std::shared_ptr<std::string> getEqus() const;
uint32_t getConstantValue() const;
};
void sym_ForEach(void (*callback)(Symbol &));
void sym_SetExportAll(bool set);
Symbol *sym_AddLocalLabel(std::string const &symName);
Symbol *sym_AddLabel(std::string const &symName);
Symbol *sym_AddAnonLabel();
std::string sym_MakeAnonLabelName(uint32_t ofs, bool neg);
void sym_Export(std::string const &symName);
Symbol *sym_AddEqu(std::string const &symName, int32_t value);
Symbol *sym_RedefEqu(std::string const &symName, int32_t value);
Symbol *sym_AddVar(std::string const &symName, int32_t value);
int32_t sym_GetRSValue();
void sym_SetRSValue(int32_t value);
uint32_t sym_GetConstantValue(std::string const &symName);
// Find a symbol by exact name, bypassing expansion checks
Symbol *sym_FindExactSymbol(std::string const &symName);
// Find a symbol, possibly scoped, by name
Symbol *sym_FindScopedSymbol(std::string const &symName);
// Find a scoped symbol by name; do not return `@` or `_NARG` when they have no value
Symbol *sym_FindScopedValidSymbol(std::string const &symName);
Symbol const *sym_GetPC();
Symbol *sym_AddMacro(std::string const &symName, int32_t defLineNo, ContentSpan const &span);
Symbol *sym_Ref(std::string const &symName);
Symbol *sym_AddString(std::string const &symName, std::shared_ptr<std::string> value);
Symbol *sym_RedefString(std::string const &symName, std::shared_ptr<std::string> value);
void sym_Purge(std::string const &symName);
bool sym_IsPurgedExact(std::string const &symName);
bool sym_IsPurgedScoped(std::string const &symName);
void sym_Init(time_t now);
// Functions to save and restore the current label scopes.
std::pair<Symbol const *, Symbol const *> sym_GetCurrentLabelScopes();
void sym_SetCurrentLabelScopes(std::pair<Symbol const *, Symbol const *> newScopes);
void sym_ResetCurrentLabelScopes();
#endif // RGBDS_ASM_SYMBOL_HPP

21
include/asm/util.h Normal file
View File

@@ -0,0 +1,21 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 1997-2019, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#ifndef RGBDS_UTIL_H
#define RGBDS_UTIL_H
#include <stdint.h>
char const *printChar(int c);
/*
* @return The number of bytes read, or 0 if invalid data was found
*/
size_t readUTF8Char(uint8_t *dest, char const *src);
#endif /* RGBDS_UTIL_H */

93
include/asm/warning.h Normal file
View File

@@ -0,0 +1,93 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 2019, Eldred Habert and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#ifndef WARNING_H
#define WARNING_H
#include "helpers.h"
extern unsigned int nbErrors;
enum WarningState {
WARNING_DEFAULT,
WARNING_DISABLED,
WARNING_ENABLED,
WARNING_ERROR
};
enum WarningID {
WARNING_ASSERT, // Assertions
WARNING_BACKWARDS_FOR, // `for` loop with backwards range
WARNING_BUILTIN_ARG, // Invalid args to builtins
WARNING_CHARMAP_REDEF, // Charmap entry re-definition
WARNING_DIV, // Division undefined behavior
WARNING_EMPTY_DATA_DIRECTIVE, // `db`, `dw` or `dl` directive without data in ROM
WARNING_EMPTY_MACRO_ARG, // Empty macro argument
WARNING_EMPTY_STRRPL, // Empty second argument in `STRRPL`
WARNING_LARGE_CONSTANT, // Constants too large
WARNING_LONG_STR, // String too long for internal buffers
WARNING_MACRO_SHIFT, // Shift past available arguments in macro
WARNING_NESTED_COMMENT, // Comment-start delimiter in a block comment
WARNING_OBSOLETE, // Obsolete things
WARNING_SHIFT, // Shifting undefined behavior
WARNING_SHIFT_AMOUNT, // Strange shift amount
WARNING_USER, // User warnings
NB_PLAIN_WARNINGS,
// Warnings past this point are "parametric" warnings, only mapping to a single flag
#define PARAM_WARNINGS_START NB_PLAIN_WARNINGS
// Treating string as number may lose some bits
WARNING_NUMERIC_STRING_1 = PARAM_WARNINGS_START,
WARNING_NUMERIC_STRING_2,
// Implicit truncation loses some bits
WARNING_TRUNCATION_1,
WARNING_TRUNCATION_2,
NB_PLAIN_AND_PARAM_WARNINGS,
#define NB_PARAM_WARNINGS (NB_PLAIN_AND_PARAM_WARNINGS - PARAM_WARNINGS_START)
// Warnings past this point are "meta" warnings
#define META_WARNINGS_START NB_PLAIN_AND_PARAM_WARNINGS
WARNING_ALL = META_WARNINGS_START,
WARNING_EXTRA,
WARNING_EVERYTHING,
NB_WARNINGS,
#define NB_META_WARNINGS (NB_WARNINGS - META_WARNINGS_START)
};
extern enum WarningState warningStates[NB_PLAIN_AND_PARAM_WARNINGS];
extern bool warningsAreErrors;
void processWarningFlag(char *flag);
/*
* Used to warn the user about problems that don't prevent the generation of
* valid code.
*/
void warning(enum WarningID id, char const *fmt, ...) format_(printf, 2, 3);
/*
* Used for errors that compromise the whole assembly process by affecting the
* following code, potencially making the assembler generate errors caused by
* the first one and unrelated to the code that the assembler complains about.
* It is also used when the assembler goes into an invalid state (for example,
* when it fails to allocate memory).
*/
_Noreturn void fatalerror(char const *fmt, ...) format_(printf, 1, 2);
/*
* Used for errors that make it impossible to assemble correctly, but don't
* affect the following code. The code will fail to assemble but the user will
* get a list of all errors at the end, making it easier to fix all of them at
* once.
*/
void error(char const *fmt, ...) format_(printf, 1, 2);
#endif

View File

@@ -1,88 +0,0 @@
/* SPDX-License-Identifier: MIT */
#ifndef RGBDS_ASM_WARNING_HPP
#define RGBDS_ASM_WARNING_HPP
extern unsigned int nbErrors, maxErrors;
enum WarningID {
WARNING_ASSERT, // Assertions
WARNING_BACKWARDS_FOR, // `FOR` loop with backwards range
WARNING_BUILTIN_ARG, // Invalid args to builtins
WARNING_CHARMAP_REDEF, // Charmap entry re-definition
WARNING_DIV, // Undefined division behavior
WARNING_EMPTY_DATA_DIRECTIVE, // `db`, `dw` or `dl` directive without data in ROM
WARNING_EMPTY_MACRO_ARG, // Empty macro argument
WARNING_EMPTY_STRRPL, // Empty second argument in `STRRPL`
WARNING_LARGE_CONSTANT, // Constants too large
WARNING_MACRO_SHIFT, // `SHIFT` past available arguments in macro
WARNING_NESTED_COMMENT, // Comment-start delimiter in a block comment
WARNING_OBSOLETE, // Obsolete/deprecated things
WARNING_SHIFT, // Undefined `SHIFT` behavior
WARNING_SHIFT_AMOUNT, // Strange `SHIFT` amount
WARNING_UNMATCHED_DIRECTIVE, // `PUSH[C|O|S]` without `POP[C|O|S]`
WARNING_UNTERMINATED_LOAD, // `LOAD` without `ENDL`
WARNING_USER, // User-defined `WARN`ings
NB_PLAIN_WARNINGS,
// Warnings past this point are "parametric" warnings, only mapping to a single flag
// Treating string as number may lose some bits
WARNING_NUMERIC_STRING_1 = NB_PLAIN_WARNINGS,
WARNING_NUMERIC_STRING_2,
// Purging an exported symbol or label
WARNING_PURGE_1,
WARNING_PURGE_2,
// Implicit truncation loses some bits
WARNING_TRUNCATION_1,
WARNING_TRUNCATION_2,
// Character without charmap entry
WARNING_UNMAPPED_CHAR_1,
WARNING_UNMAPPED_CHAR_2,
NB_WARNINGS,
};
enum WarningAbled { WARNING_DEFAULT, WARNING_ENABLED, WARNING_DISABLED };
struct WarningState {
WarningAbled state;
WarningAbled error;
void update(WarningState other);
};
struct Diagnostics {
WarningState flagStates[NB_WARNINGS];
WarningState metaStates[NB_WARNINGS];
};
extern Diagnostics warningStates;
extern bool warningsAreErrors;
void processWarningFlag(char const *flag);
/*
* Used to warn the user about problems that don't prevent the generation of
* valid code.
*/
[[gnu::format(printf, 2, 3)]] void warning(WarningID id, char const *fmt, ...);
/*
* Used for errors that compromise the whole assembly process by affecting the
* following code, potencially making the assembler generate errors caused by
* the first one and unrelated to the code that the assembler complains about.
* It is also used when the assembler goes into an invalid state (for example,
* when it fails to allocate memory).
*/
[[gnu::format(printf, 1, 2), noreturn]] void fatalerror(char const *fmt, ...);
/*
* Used for errors that make it impossible to assemble correctly, but don't
* affect the following code. The code will fail to assemble but the user will
* get a list of all errors at the end, making it easier to fix all of them at
* once.
*/
[[gnu::format(printf, 1, 2)]] void error(char const *fmt, ...);
#endif // RGBDS_ASM_WARNING_HPP

View File

@@ -1,41 +0,0 @@
/* SPDX-License-Identifier: MIT */
#ifndef RGBDS_DEFAULT_INIT_ALLOC_HPP
#define RGBDS_DEFAULT_INIT_ALLOC_HPP
#include <memory>
#include <vector>
/*
* Allocator adaptor that interposes construct() calls to convert value-initialization
* (which is what you get with e.g. `vector::resize`) into default-initialization (which does not
* zero out non-class types).
* From
* https://stackoverflow.com/questions/21028299/is-this-behavior-of-vectorresizesize-type-n-under-c11-and-boost-container/21028912#21028912
*/
template<typename T, typename A = std::allocator<T>>
class default_init_allocator : public A {
using a_t = std::allocator_traits<A>;
public:
template<typename U>
struct rebind {
using other = default_init_allocator<U, typename a_t::template rebind_alloc<U>>;
};
using A::A; // Inherit the allocator's constructors
template<typename U>
void construct(U *ptr) noexcept(std::is_nothrow_default_constructible_v<U>) {
::new (static_cast<void *>(ptr)) U;
}
template<typename U, typename... Args>
void construct(U *ptr, Args &&...args) {
a_t::construct(static_cast<A &>(*this), ptr, std::forward<Args>(args)...);
}
};
template<typename T>
using DefaultInitVec = std::vector<T, default_init_allocator<T>>;
#endif // RGBDS_DEFAULT_INIT_ALLOC_HPP

View File

@@ -1,176 +0,0 @@
/* SPDX-License-Identifier: MIT */
#ifndef RGBDS_EITHER_HPP
#define RGBDS_EITHER_HPP
#include <type_traits>
#include <utility>
#include "helpers.hpp" // assume
template<typename T1, typename T2>
union Either {
typedef T1 type1;
typedef T2 type2;
private:
template<typename T, unsigned V>
struct Field {
constexpr static unsigned tag_value = V;
unsigned tag = tag_value;
T value;
Field() : value() {}
Field(T &value_) : value(value_) {}
Field(T const &value_) : value(value_) {}
Field(T &&value_) : value(std::move(value_)) {}
};
// The `_tag` unifies with the first `tag` member of each `struct`.
constexpr static unsigned nulltag = 0;
unsigned _tag = nulltag;
Field<T1, 1> _t1;
Field<T2, 2> _t2;
// Value accessors; the function parameters are dummies for overload resolution.
// Only used to implement `field()` below.
auto &pick(T1 *) { return _t1; }
auto const &pick(T1 *) const { return _t1; }
auto &pick(T2 *) { return _t2; }
auto const &pick(T2 *) const { return _t2; }
// Generic field accessors; for internal use only.
template<typename T>
auto &field() {
return pick(static_cast<T *>(nullptr));
}
template<typename T>
auto const &field() const {
return pick(static_cast<T *>(nullptr));
}
public:
// Equivalent of `std::monostate` for `std::variant`s.
Either() : _tag() {}
// These constructors cannot be generic over the value type, because that would prevent
// constructible values from being inferred, e.g. a `const char *` string literal for an
// `std::string` field value.
Either(T1 &value) : _t1(value) {}
Either(T2 &value) : _t2(value) {}
Either(T1 const &value) : _t1(value) {}
Either(T2 const &value) : _t2(value) {}
Either(T1 &&value) : _t1(std::move(value)) {}
Either(T2 &&value) : _t2(std::move(value)) {}
// Destructor manually calls the appropriate value destructor.
~Either() {
if (_tag == _t1.tag_value) {
_t1.value.~T1();
} else if (_tag == _t2.tag_value) {
_t2.value.~T2();
}
}
// Copy assignment operators for each possible value.
Either &operator=(T1 const &value) {
_t1.tag = _t1.tag_value;
new (&_t1.value) T1(value);
return *this;
}
Either &operator=(T2 const &value) {
_t2.tag = _t2.tag_value;
new (&_t2.value) T2(value);
return *this;
}
// Move assignment operators for each possible value.
Either &operator=(T1 &&value) {
_t1.tag = _t1.tag_value;
new (&_t1.value) T1(std::move(value));
return *this;
}
Either &operator=(T2 &&value) {
_t2.tag = _t2.tag_value;
new (&_t2.value) T2(std::move(value));
return *this;
}
// Copy assignment operator from another `Either`.
Either &operator=(Either other) {
if (other._tag == other._t1.tag_value) {
*this = other._t1.value;
} else if (other._tag == other._t2.tag_value) {
*this = other._t2.value;
} else {
_tag = nulltag;
}
return *this;
}
// Copy constructor from another `Either`; implemented in terms of value assignment operators.
Either(Either const &other) {
if (other._tag == other._t1.tag_value) {
*this = other._t1.value;
} else if (other._tag == other._t2.tag_value) {
*this = other._t2.value;
} else {
_tag = nulltag;
}
}
// Move constructor from another `Either`; implemented in terms of value assignment operators.
Either(Either &&other) {
if (other._tag == other._t1.tag_value) {
*this = std::move(other._t1.value);
} else if (other._tag == other._t2.tag_value) {
*this = std::move(other._t2.value);
} else {
_tag = nulltag;
}
}
// Equivalent of `.emplace<T>()` for `std::variant`s.
template<typename T, typename... Args>
void emplace(Args &&...args) {
this->~Either();
if constexpr (std::is_same_v<T, T1>) {
_t1.tag = _t1.tag_value;
new (&_t1.value) T1(std::forward<Args>(args)...);
} else if constexpr (std::is_same_v<T, T2>) {
_t2.tag = _t2.tag_value;
new (&_t2.value) T2(std::forward<Args>(args)...);
} else {
_tag = nulltag;
}
}
// Equivalent of `std::holds_alternative<std::monostate>()` for `std::variant`s.
bool empty() const { return _tag == nulltag; }
// Equivalent of `std::holds_alternative<T>()` for `std::variant`s.
template<typename T>
bool holds() const {
if constexpr (std::is_same_v<T, T1>) {
return _tag == _t1.tag_value;
} else if constexpr (std::is_same_v<T, T2>) {
return _tag == _t2.tag_value;
} else {
return false;
}
}
// Equivalent of `std::get<T>()` for `std::variant`s.
template<typename T>
auto &get() {
assume(holds<T>());
return field<T>().value;
}
template<typename T>
auto const &get() const {
assume(holds<T>());
return field<T>().value;
}
};
#endif // RGBDS_EITHER_HPP

21
include/error.h Normal file
View File

@@ -0,0 +1,21 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 1997-2021, RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#ifndef RGBDS_ERROR_H
#define RGBDS_ERROR_H
#include "helpers.h"
#include "platform.h"
void warn(char const NONNULL(fmt), ...) format_(printf, 1, 2);
void warnx(char const NONNULL(fmt), ...) format_(printf, 1, 2);
_Noreturn void err(char const NONNULL(fmt), ...) format_(printf, 1, 2);
_Noreturn void errx(char const NONNULL(fmt), ...) format_(printf, 1, 2);
#endif /* RGBDS_ERROR_H */

View File

@@ -1,15 +0,0 @@
/* SPDX-License-Identifier: MIT */
#ifndef RGBDS_ERROR_HPP
#define RGBDS_ERROR_HPP
extern "C" {
[[gnu::format(printf, 1, 2)]] void warn(char const *fmt...);
[[gnu::format(printf, 1, 2)]] void warnx(char const *fmt, ...);
[[gnu::format(printf, 1, 2), noreturn]] void err(char const *fmt, ...);
[[gnu::format(printf, 1, 2), noreturn]] void errx(char const *fmt, ...);
}
#endif // RGBDS_ERROR_HPP

46
include/extern/getopt.h vendored Normal file
View File

@@ -0,0 +1,46 @@
/*
* Copyright © 2005-2020 Rich Felker, et al.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/* This implementation was taken from musl and modified for RGBDS */
#ifndef RGBDS_EXTERN_GETOPT_H
#define RGBDS_EXTERN_GETOPT_H
extern char *musl_optarg;
extern int musl_optind, musl_opterr, musl_optopt, musl_optreset;
struct option {
char const *name;
int has_arg;
int *flag;
int val;
};
int musl_getopt_long_only(int argc, char **argv, char const *optstring,
const struct option *longopts, int *idx);
#define no_argument 0
#define required_argument 1
#define optional_argument 2
#endif

View File

@@ -1,30 +0,0 @@
/* SPDX-License-Identifier: MIT */
/* This implementation was taken from musl and modified for RGBDS */
#ifndef RGBDS_EXTERN_GETOPT_HPP
#define RGBDS_EXTERN_GETOPT_HPP
extern "C" {
extern char *musl_optarg;
extern int musl_optind, musl_opterr, musl_optopt, musl_optreset;
struct option {
char const *name;
int has_arg;
int *flag;
int val;
};
int musl_getopt_long_only(
int argc, char **argv, char const *optstring, option const *longopts, int *idx
);
#define no_argument 0
#define required_argument 1
#define optional_argument 2
} // extern "C"
#endif // RGBDS_EXTERN_GETOPT_HPP

14
include/extern/utf8decoder.h vendored Normal file
View File

@@ -0,0 +1,14 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 2018, Antonio Nino Diaz and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#ifndef EXTERN_UTF8DECODER_H
#define EXTERN_UTF8DECODER_H
uint32_t decode(uint32_t *state, uint32_t *codep, uint8_t byte);
#endif /* EXTERN_UTF8DECODER_H */

View File

@@ -1,10 +0,0 @@
/* SPDX-License-Identifier: MIT */
#ifndef RGBDS_EXTERN_UTF8DECODER_HPP
#define RGBDS_EXTERN_UTF8DECODER_HPP
#include <stdint.h>
uint32_t decode(uint32_t *state, uint32_t *codep, uint8_t byte);
#endif // RGBDS_EXTERN_UTF8DECODER_HPP

View File

@@ -1,87 +0,0 @@
/* SPDX-License-Identifier: MIT */
#ifndef RGBDS_FILE_HPP
#define RGBDS_FILE_HPP
#include <fcntl.h>
#include <fstream>
#include <ios>
#include <iostream>
#include <streambuf>
#include <string.h>
#include <string>
#include "either.hpp"
#include "helpers.hpp" // assume
#include "platform.hpp"
#include "gfx/main.hpp"
class File {
// Construct a `std::streambuf *` by default, since it's probably lighter than a `filebuf`.
Either<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 != "-") {
_file.emplace<std::filebuf>();
return _file.get<std::filebuf>().open(path, mode) ? this : nullptr;
} else if (mode & std::ios_base::in) {
assume(!(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 {
assume(mode & std::ios_base::out);
_file.emplace<std::streambuf *>(std::cout.rdbuf());
}
return this;
}
std::streambuf &operator*() {
return _file.holds<std::filebuf>() ? _file.get<std::filebuf>()
: *_file.get<std::streambuf *>();
}
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() {
if (_file.holds<std::filebuf>()) {
// This is called by the destructor, and an explicit `close` shouldn't close twice.
std::filebuf fileBuf = std::move(_file.get<std::filebuf>());
_file.emplace<std::streambuf *>(nullptr);
if (fileBuf.close() != nullptr) {
return this;
}
} else if (_file.get<std::streambuf *>() != nullptr) {
return this;
}
return nullptr;
}
char const *c_str(std::string const &path) const {
return _file.holds<std::filebuf>() ? path.c_str()
: _file.get<std::streambuf *>() == std::cin.rdbuf() ? "<stdin>"
: "<stdout>";
}
};
#endif // RGBDS_FILE_HPP

36
include/gfx/gb.h Normal file
View File

@@ -0,0 +1,36 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 2013-2018, stag019 and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#ifndef RGBDS_GFX_GB_H
#define RGBDS_GFX_GB_H
#include <stdint.h>
#include "gfx/main.h"
#define XFLIP 0x40
#define YFLIP 0x20
void raw_to_gb(const struct RawIndexedImage *raw_image, struct GBImage *gb);
void output_file(const struct Options *opts, const struct GBImage *gb);
int get_tile_index(uint8_t *tile, uint8_t **tiles, int num_tiles,
int tile_size);
uint8_t reverse_bits(uint8_t b);
void xflip(uint8_t *tile, uint8_t *tile_xflip, int tile_size);
void yflip(uint8_t *tile, uint8_t *tile_yflip, int tile_size);
int get_mirrored_tile_index(uint8_t *tile, uint8_t **tiles, int num_tiles,
int tile_size, int *flags);
void create_mapfiles(const struct Options *opts, struct GBImage *gb,
struct Mapfile *tilemap, struct Mapfile *attrmap);
void output_tilemap_file(const struct Options *opts,
const struct Mapfile *tilemap);
void output_attrmap_file(const struct Options *opts,
const struct Mapfile *attrmap);
void output_palette_file(const struct Options *opts,
const struct RawIndexedImage *raw_image);
#endif

91
include/gfx/main.h Normal file
View File

@@ -0,0 +1,91 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 2013-2018, stag019 and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#ifndef RGBDS_GFX_MAIN_H
#define RGBDS_GFX_MAIN_H
#include <png.h>
#include <stdbool.h>
#include <stdint.h>
#include "error.h"
struct Options {
bool debug;
bool verbose;
bool hardfix;
bool fix;
bool horizontal;
bool mirror;
bool unique;
bool colorcurve;
unsigned int trim;
char *tilemapfile;
bool tilemapout;
char *attrmapfile;
bool attrmapout;
char *palfile;
bool palout;
char *outfile;
char *infile;
};
struct RGBColor {
uint8_t red;
uint8_t green;
uint8_t blue;
};
struct ImageOptions {
bool horizontal;
unsigned int trim;
char *tilemapfile;
bool tilemapout;
char *attrmapfile;
bool attrmapout;
char *palfile;
bool palout;
};
struct PNGImage {
png_struct *png;
png_info *info;
png_byte **data;
int width;
int height;
png_byte depth;
png_byte type;
};
struct RawIndexedImage {
uint8_t **data;
struct RGBColor *palette;
int num_colors;
unsigned int width;
unsigned int height;
};
struct GBImage {
uint8_t *data;
int size;
bool horizontal;
int trim;
};
struct Mapfile {
uint8_t *data;
int size;
};
extern int depth, colors;
#include "gfx/makepng.h"
#include "gfx/gb.h"
#endif /* RGBDS_GFX_MAIN_H */

View File

@@ -1,124 +0,0 @@
/* SPDX-License-Identifier: MIT */
#ifndef RGBDS_GFX_MAIN_HPP
#define RGBDS_GFX_MAIN_HPP
#include <array>
#include <optional>
#include <stdint.h>
#include <string>
#include <utility>
#include <vector>
#include "gfx/rgba.hpp"
struct Options {
bool useColorCurve = false; // -C
bool allowDedup = false; // -u
bool allowMirroringX = false; // -X, -m
bool allowMirroringY = false; // -Y, -m
bool columnMajor = false; // -Z
uint8_t verbosity = 0; // -v
std::string attrmap{}; // -a, -A
std::array<uint8_t, 2> baseTileIDs{0, 0}; // -b
enum {
NO_SPEC,
EXPLICIT,
EMBEDDED,
} palSpecType = NO_SPEC; // -c
std::vector<std::array<std::optional<Rgba>, 4>> palSpec{};
uint8_t bitDepth = 2; // -d
std::string inputTileset{}; // -i
struct {
uint16_t left;
uint16_t top;
uint16_t width;
uint16_t height;
} inputSlice{0, 0, 0, 0}; // -L (margins in clockwise order, like CSS)
std::array<uint16_t, 2> maxNbTiles{UINT16_MAX, 0}; // -N
uint16_t nbPalettes = 8; // -n
std::string output{}; // -o
std::string palettes{}; // -p, -P
std::string palmap{}; // -q, -Q
uint16_t reversedWidth = 0; // -r, in tiles
uint8_t nbColorsPerPal = 0; // -s; 0 means "auto" = 1 << bitDepth;
std::string tilemap{}; // -t, -T
uint64_t trim = 0; // -x
std::string input{}; // positional arg
static constexpr uint8_t VERB_NONE = 0; // Normal, no extra output
static constexpr uint8_t VERB_CFG = 1; // Print configuration after parsing options
static constexpr uint8_t VERB_LOG_ACT = 2; // Log actions before doing them
static constexpr uint8_t VERB_INTERM = 3; // Print some intermediate results
static constexpr uint8_t VERB_DEBUG = 4; // Internals are logged
static constexpr uint8_t VERB_TRACE = 5; // Step-by-step algorithm details
static constexpr uint8_t VERB_VVVVVV = 6; // What, can't I have a little fun?
[[gnu::format(printf, 3, 4)]] void verbosePrint(uint8_t level, char const *fmt, ...) const;
mutable bool hasTransparentPixels = false;
uint8_t maxOpaqueColors() const { return nbColorsPerPal - hasTransparentPixels; }
};
extern Options options;
/*
* Prints the error count, and exits with failure
*/
[[noreturn]] void giveUp();
/*
* If any error has been emitted thus far, calls `giveUp()`.
*/
void requireZeroErrors();
/*
* Prints a warning, and does not change the error count
*/
[[gnu::format(printf, 1, 2)]] void warning(char const *fmt, ...);
/*
* Prints an error, and increments the error count
*/
[[gnu::format(printf, 1, 2)]] void error(char const *fmt, ...);
/*
* Prints an error, and increments the error count
* Does not take format arguments so `format_` and `-Wformat-security` won't complain about
* calling `errorMessage(msg)`.
*/
void errorMessage(char const *msg);
/*
* Prints a fatal error, increments the error count, and gives up
*/
[[gnu::format(printf, 1, 2), noreturn]] void fatal(char const *fmt, ...);
struct Palette {
// An array of 4 GBC-native (RGB555) colors
std::array<uint16_t, 4> colors{UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX};
void addColor(uint16_t color);
uint8_t indexOf(uint16_t color) const;
uint16_t &operator[](size_t index) { return colors[index]; }
uint16_t const &operator[](size_t index) const { return colors[index]; }
decltype(colors)::iterator begin();
decltype(colors)::iterator end();
decltype(colors)::const_iterator begin() const;
decltype(colors)::const_iterator end() const;
uint8_t size() const;
};
// Flipping tends to happen fairly often, so take a bite out of dcache to speed it up
static constexpr auto flipTable = ([]() constexpr {
std::array<uint16_t, 256> table{};
for (uint16_t i = 0; i < table.size(); i++) {
// To flip all the bits, we'll flip both nibbles, then each nibble half, etc.
uint16_t byte = i;
byte = (byte & 0b0000'1111) << 4 | (byte & 0b1111'0000) >> 4;
byte = (byte & 0b0011'0011) << 2 | (byte & 0b1100'1100) >> 2;
byte = (byte & 0b0101'0101) << 1 | (byte & 0b1010'1010) >> 1;
table[i] = byte;
}
return table;
})();
#endif // RGBDS_GFX_MAIN_HPP

21
include/gfx/makepng.h Normal file
View File

@@ -0,0 +1,21 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 2013-2018, stag019 and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#ifndef RGBDS_GFX_PNG_H
#define RGBDS_GFX_PNG_H
#include "gfx/main.h"
struct RawIndexedImage *input_png_file(const struct Options *opts,
struct ImageOptions *png_options);
void output_png_file(const struct Options *opts,
const struct ImageOptions *png_options,
const struct RawIndexedImage *raw_image);
void destroy_raw_image(struct RawIndexedImage **raw_image_ptr_ptr);
#endif /* RGBDS_GFX_PNG_H */

View File

@@ -1,20 +0,0 @@
/* SPDX-License-Identifier: MIT */
#ifndef RGBDS_GFX_PAL_PACKING_HPP
#define RGBDS_GFX_PAL_PACKING_HPP
#include <tuple>
#include <vector>
#include "defaultinitvec.hpp"
struct Palette;
class ProtoPalette;
/*
* Returns which palette each proto-palette maps to, and how many palettes are necessary
*/
std::tuple<DefaultInitVec<size_t>, size_t>
overloadAndRemove(std::vector<ProtoPalette> const &protoPalettes);
#endif // RGBDS_GFX_PAL_PACKING_HPP

View File

@@ -1,27 +0,0 @@
/* SPDX-License-Identifier: MIT */
#ifndef RGBDS_GFX_PAL_SORTING_HPP
#define RGBDS_GFX_PAL_SORTING_HPP
#include <array>
#include <optional>
#include <png.h>
#include <vector>
#include "gfx/rgba.hpp"
struct Palette;
void sortIndexed(
std::vector<Palette> &palettes,
int palSize,
png_color const *palRGB,
int palAlphaSize,
png_byte *palAlpha
);
void sortGrayscale(
std::vector<Palette> &palettes, std::array<std::optional<Rgba>, 0x8001> const &colors
);
void sortRgb(std::vector<Palette> &palettes);
#endif // RGBDS_GFX_PAL_SORTING_HPP

View File

@@ -1,9 +0,0 @@
/* SPDX-License-Identifier: MIT */
#ifndef RGBDS_GFX_PAL_SPEC_HPP
#define RGBDS_GFX_PAL_SPEC_HPP
void parseInlinePalSpec(char const * const arg);
void parseExternalPalSpec(char const *arg);
#endif // RGBDS_GFX_PAL_SPEC_HPP

View File

@@ -1,9 +0,0 @@
/* SPDX-License-Identifier: MIT */
#ifndef RGBDS_GFX_PROCESS_HPP
#define RGBDS_GFX_PROCESS_HPP
void processPalettes();
void process();
#endif // RGBDS_GFX_PROCESS_HPP

View File

@@ -1,38 +0,0 @@
/* SPDX-License-Identifier: MIT */
#ifndef RGBDS_GFX_PROTO_PALETTE_HPP
#define RGBDS_GFX_PROTO_PALETTE_HPP
#include <array>
#include <stddef.h>
#include <stdint.h>
class ProtoPalette {
public:
static constexpr size_t capacity = 4;
private:
// Up to 4 colors, sorted, and where SIZE_MAX means the slot is empty
// (OK because it's not a valid color index)
// Sorting is done on the raw numerical values to lessen `compare`'s complexity
std::array<uint16_t, capacity> _colorIndices{UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX};
public:
// Adds the specified color to the set, or **silently drops it** if the set is full.
void add(uint16_t color);
enum ComparisonResult {
NEITHER,
WE_BIGGER,
THEY_BIGGER = -1,
};
ComparisonResult compare(ProtoPalette const &other) const;
size_t size() const;
bool empty() const;
decltype(_colorIndices)::const_iterator begin() const;
decltype(_colorIndices)::const_iterator end() const;
};
#endif // RGBDS_GFX_PROTO_PALETTE_HPP

View File

@@ -1,8 +0,0 @@
/* SPDX-License-Identifier: MIT */
#ifndef RGBDS_GFX_REVERSE_HPP
#define RGBDS_GFX_REVERSE_HPP
void reverse();
#endif // RGBDS_GFX_REVERSE_HPP

View File

@@ -1,65 +0,0 @@
/* SPDX-License-Identifier: MIT */
#ifndef RGBDS_GFX_RGBA_HPP
#define RGBDS_GFX_RGBA_HPP
#include <stdint.h>
struct Rgba {
uint8_t red;
uint8_t green;
uint8_t blue;
uint8_t alpha;
constexpr Rgba(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
: red(r), green(g), blue(b), alpha(a) {}
/*
* Constructs the color from a "packed" RGBA representation (0xRRGGBBAA)
*/
explicit constexpr Rgba(uint32_t rgba = 0)
: red(rgba >> 24), green(rgba >> 16), blue(rgba >> 8), alpha(rgba) {}
static constexpr Rgba fromCGBColor(uint16_t cgbColor) {
constexpr auto _5to8 = [](uint8_t fiveBpp) -> uint8_t {
fiveBpp &= 0b11111; // For caller's convenience
return fiveBpp << 3 | fiveBpp >> 2;
};
return {
_5to8(cgbColor),
_5to8(cgbColor >> 5),
_5to8(cgbColor >> 10),
static_cast<uint8_t>(cgbColor & 0x8000 ? 0x00 : 0xFF),
};
}
/*
* Returns this RGBA as a 32-bit number that can be printed in hex (`%08x`) to yield its CSS
* representation
*/
uint32_t toCSS() const {
auto shl = [](uint8_t val, unsigned shift) { return static_cast<uint32_t>(val) << shift; };
return shl(red, 24) | shl(green, 16) | shl(blue, 8) | shl(alpha, 0);
}
bool operator==(Rgba const &rhs) const { return toCSS() == rhs.toCSS(); }
bool operator!=(Rgba const &rhs) const { return toCSS() != rhs.toCSS(); }
/*
* CGB colors are RGB555, so we use bit 15 to signify that the color is transparent instead
* Since the rest of the bits don't matter then, we return 0x8000 exactly.
*/
static constexpr uint16_t transparent = 0b1'00000'00000'00000;
static constexpr uint8_t transparency_threshold = 0x10;
bool isTransparent() const { return alpha < transparency_threshold; }
static constexpr uint8_t opacity_threshold = 0xF0;
bool isOpaque() const { return alpha >= opacity_threshold; }
/*
* Computes the equivalent CGB color, respects the color curve depending on options
*/
uint16_t cgbColor() const;
bool isGray() const { return red == green && green == blue; }
uint8_t grayIndex() const;
};
#endif // RGBDS_GFX_RGBA_HPP

77
include/hashmap.h Normal file
View File

@@ -0,0 +1,77 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 1997-2019, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
/* Generic hashmap implementation (C++ templates are calling...) */
#ifndef RGBDS_LINK_HASHMAP_H
#define RGBDS_LINK_HASHMAP_H
#include <assert.h>
#include <stdbool.h>
#define HASH_NB_BITS 32
#define HALF_HASH_NB_BITS 16
static_assert(HALF_HASH_NB_BITS * 2 == HASH_NB_BITS, "");
#define HASHMAP_NB_BUCKETS (1 << HALF_HASH_NB_BITS)
/* HashMapEntry is internal, please do not attempt to use it */
typedef struct HashMapEntry *HashMap[HASHMAP_NB_BUCKETS];
/**
* Adds an element to a hashmap.
* @warning Adding a new element with an already-present key will not cause an
* error, this must be handled externally.
* @warning Inserting a NULL will make `hash_GetElement`'s return ambiguous!
* @param map The HashMap to add the element to
* @param key The key with which the element will be stored and retrieved
* @param element The element to add
* @return A pointer to the pointer to the element.
*/
void **hash_AddElement(HashMap map, char const *key, void *element);
/**
* Removes an element from a hashmap.
* @param map The HashMap to remove the element from
* @param key The key to search the element with
* @return True if the element was found and removed
*/
bool hash_RemoveElement(HashMap map, char const *key);
/**
* Finds an element in a hashmap, and returns a pointer to its value field.
* @param map The map to consider the elements of
* @param key The key to search an element for
* @return A pointer to the pointer to the element, or NULL if not found.
*/
void **hash_GetNode(HashMap const map, char const *key);
/**
* Finds an element in a hashmap.
* @param map The map to consider the elements of
* @param key The key to search an element for
* @return A pointer to the element, or NULL if not found. (NULL can be returned
* if such an element was added, but that sounds pretty silly.)
*/
void *hash_GetElement(HashMap const map, char const *key);
/**
* Executes a function on each element in a hashmap.
* @param map The map to consider the elements of
* @param func The function to run. The first argument will be the element,
* the second will be `arg`.
* @param arg An argument to be passed to all function calls
*/
void hash_ForEach(HashMap const map, void (*func)(void *, void *), void *arg);
/**
* Cleanly empties a hashmap from its contents.
* This does not `free` the data structure itself!
* @param map The map to empty
*/
void hash_EmptyMap(HashMap map);
#endif /* RGBDS_LINK_HASHMAP_H */

96
include/helpers.h Normal file
View File

@@ -0,0 +1,96 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 2014-2020, RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#ifndef HELPERS_H
#define HELPERS_H
// Of course, MSVC does not support C11, so no _Noreturn there...
#ifdef _MSC_VER
#define _Noreturn __declspec(noreturn)
#endif
// Ideally, we'd use `__has_attribute` and `__has_builtin`, but these were only introduced in GCC 9
#ifdef __GNUC__ // GCC or compatible
#define format_(archetype, str_index, first_arg) \
__attribute__ ((format (archetype, str_index, first_arg)))
#define attr_(...) __attribute__ ((__VA_ARGS__))
// In release builds, define "unreachable" as such, but trap in debug builds
#ifdef NDEBUG
#define unreachable_ __builtin_unreachable
#else
#define unreachable_ __builtin_trap
#endif
#else
// Unsupported, but no need to throw a fit
#define format_(archetype, str_index, first_arg)
#define attr_(...)
// This seems to generate similar code to __builtin_unreachable, despite different semantics
// Note that executing this is undefined behavior (declared _Noreturn, but does return)
static inline _Noreturn unreachable_(void) {}
#endif
// Use builtins whenever possible, and shim them otherwise
#ifdef __GNUC__ // GCC or compatible
#define ctz __builtin_ctz
#define clz __builtin_clz
#elif defined(_MSC_VER)
#include <assert.h>
#include <intrin.h>
#pragma intrinsic(_BitScanReverse, _BitScanForward)
static inline int ctz(unsigned int x)
{
unsigned long cnt;
assert(x != 0);
_BitScanForward(&cnt, x);
return cnt;
}
static inline int clz(unsigned int x)
{
unsigned long cnt;
assert(x != 0);
_BitScanReverse(&cnt, x);
return 31 - cnt;
}
#else
#include <limits.h>
static inline int ctz(unsigned int x)
{
int cnt = 0;
while (!(x & 1)) {
x >>= 1;
cnt++;
}
return cnt;
}
static inline int clz(unsigned int x)
{
int cnt = 0;
while (x <= UINT_MAX / 2) {
x <<= 1;
cnt++;
}
return cnt;
}
#endif
// Macros for stringification
#define STR(x) #x
#define EXPAND_AND_STR(x) STR(x)
// Obtaining the size of an array; `arr` must be an expression, not a type!
// (Having two instances of `arr` is OK because the contents of `sizeof` are not evaluated.)
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof *(arr))
#endif /* HELPERS_H */

Some files were not shown because too many files have changed in this diff Show More