mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 10:12:06 +00:00
Use colored/styled text output for diagnostics and usage info (#1775)
This commit is contained in:
1
Makefile
1
Makefile
@@ -52,6 +52,7 @@ all: rgbasm rgblink rgbfix rgbgfx
|
|||||||
common_obj := \
|
common_obj := \
|
||||||
src/extern/getopt.o \
|
src/extern/getopt.o \
|
||||||
src/diagnostics.o \
|
src/diagnostics.o \
|
||||||
|
src/style.o \
|
||||||
src/usage.o
|
src/usage.o
|
||||||
|
|
||||||
rgbasm_obj := \
|
rgbasm_obj := \
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
#define STDERR_FILENO 2
|
#define STDERR_FILENO 2
|
||||||
#define ssize_t int
|
#define ssize_t int
|
||||||
#define SSIZE_MAX INT_MAX
|
#define SSIZE_MAX INT_MAX
|
||||||
|
#define isatty _isatty
|
||||||
#else
|
#else
|
||||||
#include <fcntl.h> // IWYU pragma: export
|
#include <fcntl.h> // IWYU pragma: export
|
||||||
#include <limits.h> // IWYU pragma: export
|
#include <limits.h> // IWYU pragma: export
|
||||||
|
|||||||
42
include/style.hpp
Normal file
42
include/style.hpp
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#ifndef RGBDS_STYLE_HPP
|
||||||
|
#define RGBDS_STYLE_HPP
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) || defined(__MINGW32__) || defined(__CYGWIN__)
|
||||||
|
#define STYLE_ANSI 0
|
||||||
|
#else
|
||||||
|
#define STYLE_ANSI 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum StyleColor {
|
||||||
|
#if STYLE_ANSI
|
||||||
|
// Values analogous to ANSI foreground and background SGR colors
|
||||||
|
STYLE_BLACK,
|
||||||
|
STYLE_RED,
|
||||||
|
STYLE_GREEN,
|
||||||
|
STYLE_YELLOW,
|
||||||
|
STYLE_BLUE,
|
||||||
|
STYLE_MAGENTA,
|
||||||
|
STYLE_CYAN,
|
||||||
|
STYLE_GRAY,
|
||||||
|
#else
|
||||||
|
// Values analogous to `FOREGROUND_*` constants from `windows.h`
|
||||||
|
STYLE_BLACK,
|
||||||
|
STYLE_BLUE, // bit 0
|
||||||
|
STYLE_GREEN, // bit 1
|
||||||
|
STYLE_CYAN, // STYLE_BLUE | STYLE_GREEN
|
||||||
|
STYLE_RED, // bit 2
|
||||||
|
STYLE_MAGENTA, // STYLE_BLUE | STYLE_RED
|
||||||
|
STYLE_YELLOW, // STYLE_GREEN | STYLE_RED
|
||||||
|
STYLE_GRAY, // STYLE_BLUE | STYLE_GREEN | STYLE_RED
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
void style_Enable(bool enable);
|
||||||
|
void style_Set(FILE *file, StyleColor color, bool bold);
|
||||||
|
void style_Reset(FILE *file);
|
||||||
|
|
||||||
|
#endif // RGBDS_STYLE_HPP
|
||||||
@@ -4,12 +4,14 @@
|
|||||||
#define RGBDS_USAGE_HPP
|
#define RGBDS_USAGE_HPP
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
class Usage {
|
struct Usage {
|
||||||
char const *usage;
|
std::string name;
|
||||||
|
std::vector<std::string> flags;
|
||||||
public:
|
std::vector<std::pair<std::vector<std::string>, std::vector<std::string>>> options;
|
||||||
Usage(char const *usage_) : usage(usage_) {}
|
|
||||||
|
|
||||||
[[noreturn]]
|
[[noreturn]]
|
||||||
void printAndExit(int code) const;
|
void printAndExit(int code) const;
|
||||||
|
|||||||
13
man/rgbasm.1
13
man/rgbasm.1
@@ -10,6 +10,7 @@
|
|||||||
.Nm
|
.Nm
|
||||||
.Op Fl EhVvw
|
.Op Fl EhVvw
|
||||||
.Op Fl b Ar chars
|
.Op Fl b Ar chars
|
||||||
|
.Op Fl \-color Ar when
|
||||||
.Op Fl D Ar name Ns Op = Ns Ar value
|
.Op Fl D Ar name Ns Op = Ns Ar value
|
||||||
.Op Fl g Ar chars
|
.Op Fl g Ar chars
|
||||||
.Op Fl I Ar path
|
.Op Fl I Ar path
|
||||||
@@ -65,6 +66,18 @@ letters,
|
|||||||
.Sq # ,
|
.Sq # ,
|
||||||
or
|
or
|
||||||
.Sq @ .
|
.Sq @ .
|
||||||
|
.It Fl \-color Ar when
|
||||||
|
Specify when to highlight warning and error messages with color:
|
||||||
|
.Ql always ,
|
||||||
|
.Ql never ,
|
||||||
|
or
|
||||||
|
.Ql auto .
|
||||||
|
.Ql auto
|
||||||
|
determines whether to use colors based on the
|
||||||
|
.Ql Lk https://no-color.org/ NO_COLOR
|
||||||
|
or
|
||||||
|
.Ql Lk https://force-color.org/ FORCE_COLOR
|
||||||
|
environment variables, or whether the output is to a TTY.
|
||||||
.It Fl D Ar name Ns Oo = Ns Ar value Oc , Fl \-define Ar name Ns Oo = Ns Ar value Oc
|
.It Fl D Ar name Ns Oo = Ns Ar value Oc , Fl \-define Ar name Ns Oo = Ns Ar value Oc
|
||||||
Add a string symbol to the compiled source code.
|
Add a string symbol to the compiled source code.
|
||||||
This is equivalent to
|
This is equivalent to
|
||||||
|
|||||||
21
man/rgbfix.1
21
man/rgbfix.1
@@ -10,6 +10,7 @@
|
|||||||
.Nm
|
.Nm
|
||||||
.Op Fl hjOsVvw
|
.Op Fl hjOsVvw
|
||||||
.Op Fl C | c
|
.Op Fl C | c
|
||||||
|
.Op Fl \-color Ar when
|
||||||
.Op Fl f Ar fix_spec
|
.Op Fl f Ar fix_spec
|
||||||
.Op Fl i Ar game_id
|
.Op Fl i Ar game_id
|
||||||
.Op Fl k Ar licensee_str
|
.Op Fl k Ar licensee_str
|
||||||
@@ -46,13 +47,13 @@ can be a path to a file, or
|
|||||||
to read from standard input.
|
to read from standard input.
|
||||||
.Pp
|
.Pp
|
||||||
Note that options can be abbreviated as long as the abbreviation is unambiguous:
|
Note that options can be abbreviated as long as the abbreviation is unambiguous:
|
||||||
.Fl \-color-o
|
.Fl \-verb
|
||||||
is
|
is
|
||||||
.Fl \-color-only ,
|
.Fl \-verbose ,
|
||||||
but
|
but
|
||||||
.Fl \-color
|
.Fl \-ver
|
||||||
is invalid because it could also be
|
is invalid because it could also be
|
||||||
.Fl \-color-compatible .
|
.Fl \-version .
|
||||||
Options later in the command line override those set earlier.
|
Options later in the command line override those set earlier.
|
||||||
Accepted options are as follows:
|
Accepted options are as follows:
|
||||||
.Bl -tag -width Ds
|
.Bl -tag -width Ds
|
||||||
@@ -70,6 +71,18 @@ to 0x80.
|
|||||||
This overrides
|
This overrides
|
||||||
.Fl c
|
.Fl c
|
||||||
if it was set prior.
|
if it was set prior.
|
||||||
|
.It Fl \-color Ar when
|
||||||
|
Specify when to highlight warning and error messages with color:
|
||||||
|
.Ql always ,
|
||||||
|
.Ql never ,
|
||||||
|
or
|
||||||
|
.Ql auto .
|
||||||
|
.Ql auto
|
||||||
|
determines whether to use colors based on the
|
||||||
|
.Ql Lk https://no-color.org/ NO_COLOR
|
||||||
|
or
|
||||||
|
.Ql Lk https://force-color.org/ FORCE_COLOR
|
||||||
|
environment variables, or whether the output is to a TTY.
|
||||||
.It Fl f Ar fix_spec , Fl \-fix-spec Ar fix_spec
|
.It Fl f Ar fix_spec , Fl \-fix-spec Ar fix_spec
|
||||||
Fix certain header values that the Game Boy checks for correctness.
|
Fix certain header values that the Game Boy checks for correctness.
|
||||||
Alternatively, intentionally trash these values by writing their binary inverse instead.
|
Alternatively, intentionally trash these values by writing their binary inverse instead.
|
||||||
|
|||||||
13
man/rgbgfx.1
13
man/rgbgfx.1
@@ -15,6 +15,7 @@
|
|||||||
.Op Fl a Ar attrmap | Fl A
|
.Op Fl a Ar attrmap | Fl A
|
||||||
.Op Fl b Ar base_ids
|
.Op Fl b Ar base_ids
|
||||||
.Op Fl c Ar pal_spec
|
.Op Fl c Ar pal_spec
|
||||||
|
.Op Fl \-color Ar when
|
||||||
.Op Fl d Ar depth
|
.Op Fl d Ar depth
|
||||||
.Op Fl i Ar input_tiles
|
.Op Fl i Ar input_tiles
|
||||||
.Op Fl L Ar slice
|
.Op Fl L Ar slice
|
||||||
@@ -195,6 +196,18 @@ See
|
|||||||
.Sx PALETTE SPECIFICATION FORMATS
|
.Sx PALETTE SPECIFICATION FORMATS
|
||||||
for a list of formats and their descriptions.
|
for a list of formats and their descriptions.
|
||||||
.El
|
.El
|
||||||
|
.It Fl \-color Ar when
|
||||||
|
Specify when to highlight warning and error messages with color:
|
||||||
|
.Ql always ,
|
||||||
|
.Ql never ,
|
||||||
|
or
|
||||||
|
.Ql auto .
|
||||||
|
.Ql auto
|
||||||
|
determines whether to use colors based on the
|
||||||
|
.Ql Lk https://no-color.org/ NO_COLOR
|
||||||
|
or
|
||||||
|
.Ql Lk https://force-color.org/ FORCE_COLOR
|
||||||
|
environment variables, or whether the output is to a TTY.
|
||||||
.It Fl d Ar depth , Fl \-depth Ar depth
|
.It Fl d Ar depth , Fl \-depth Ar depth
|
||||||
Set the bit depth of the output tile data, in bits per pixel (bpp), either 1 or 2 (the default).
|
Set the bit depth of the output tile data, in bits per pixel (bpp), either 1 or 2 (the default).
|
||||||
This changes how tile data is output, and the maximum number of colors per palette (2 and 4 respectively).
|
This changes how tile data is output, and the maximum number of colors per palette (2 and 4 respectively).
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
.Sh SYNOPSIS
|
.Sh SYNOPSIS
|
||||||
.Nm
|
.Nm
|
||||||
.Op Fl dhMtVvwx
|
.Op Fl dhMtVvwx
|
||||||
|
.Op Fl \-color Ar when
|
||||||
.Op Fl l Ar linker_script
|
.Op Fl l Ar linker_script
|
||||||
.Op Fl m Ar map_file
|
.Op Fl m Ar map_file
|
||||||
.Op Fl n Ar sym_file
|
.Op Fl n Ar sym_file
|
||||||
@@ -63,6 +64,18 @@ is invalid because it could also be
|
|||||||
.Fl \-version .
|
.Fl \-version .
|
||||||
The arguments are as follows:
|
The arguments are as follows:
|
||||||
.Bl -tag -width Ds
|
.Bl -tag -width Ds
|
||||||
|
.It Fl \-color Ar when
|
||||||
|
Specify when to highlight warning and error messages with color:
|
||||||
|
.Ql always ,
|
||||||
|
.Ql never ,
|
||||||
|
or
|
||||||
|
.Ql auto .
|
||||||
|
.Ql auto
|
||||||
|
determines whether to use colors based on the
|
||||||
|
.Ql Lk https://no-color.org/ NO_COLOR
|
||||||
|
or
|
||||||
|
.Ql Lk https://force-color.org/ FORCE_COLOR
|
||||||
|
environment variables, or whether the output is to a TTY.
|
||||||
.It Fl d , Fl \-dmg
|
.It Fl d , Fl \-dmg
|
||||||
Enable DMG mode.
|
Enable DMG mode.
|
||||||
Prohibit the use of sections that doesn't exist on a DMG, such as VRAM bank 1.
|
Prohibit the use of sections that doesn't exist on a DMG, such as VRAM bank 1.
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ configure_file(version.cpp _version.cpp ESCAPE_QUOTES)
|
|||||||
set(common_src
|
set(common_src
|
||||||
"extern/getopt.cpp"
|
"extern/getopt.cpp"
|
||||||
"diagnostics.cpp"
|
"diagnostics.cpp"
|
||||||
|
"style.cpp"
|
||||||
"usage.cpp"
|
"usage.cpp"
|
||||||
"_version.cpp"
|
"_version.cpp"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ bool charmap_ForEach(
|
|||||||
});
|
});
|
||||||
|
|
||||||
mapFunc(charmap.name);
|
mapFunc(charmap.name);
|
||||||
for (auto [nodeIdx, mapping] : mappings) {
|
for (auto const &[nodeIdx, mapping] : mappings) {
|
||||||
charFunc(mapping, charmap.nodes[nodeIdx].value);
|
charFunc(mapping, charmap.nodes[nodeIdx].value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
#include "helpers.hpp"
|
#include "helpers.hpp"
|
||||||
#include "linkdefs.hpp"
|
#include "linkdefs.hpp"
|
||||||
#include "platform.hpp" // S_ISDIR (stat macro)
|
#include "platform.hpp" // S_ISDIR (stat macro)
|
||||||
|
#include "style.hpp"
|
||||||
#include "verbosity.hpp"
|
#include "verbosity.hpp"
|
||||||
|
|
||||||
#include "asm/lexer.hpp"
|
#include "asm/lexer.hpp"
|
||||||
@@ -63,19 +64,27 @@ std::string const &FileStackNode::dump(uint32_t curLineNo) const {
|
|||||||
if (std::holds_alternative<std::vector<uint32_t>>(data)) {
|
if (std::holds_alternative<std::vector<uint32_t>>(data)) {
|
||||||
assume(parent); // REPT nodes use their parent's name
|
assume(parent); // REPT nodes use their parent's name
|
||||||
std::string const &lastName = parent->dump(lineNo);
|
std::string const &lastName = parent->dump(lineNo);
|
||||||
|
style_Set(stderr, STYLE_CYAN, false);
|
||||||
fputs(" -> ", stderr);
|
fputs(" -> ", stderr);
|
||||||
|
style_Set(stderr, STYLE_CYAN, true);
|
||||||
fputs(lastName.c_str(), stderr);
|
fputs(lastName.c_str(), stderr);
|
||||||
fputs(reptChain().c_str(), stderr);
|
fputs(reptChain().c_str(), stderr);
|
||||||
|
style_Set(stderr, STYLE_CYAN, false);
|
||||||
fprintf(stderr, "(%" PRIu32 ")", curLineNo);
|
fprintf(stderr, "(%" PRIu32 ")", curLineNo);
|
||||||
|
style_Reset(stderr);
|
||||||
return lastName;
|
return lastName;
|
||||||
} else {
|
} else {
|
||||||
if (parent) {
|
if (parent) {
|
||||||
parent->dump(lineNo);
|
parent->dump(lineNo);
|
||||||
|
style_Set(stderr, STYLE_CYAN, false);
|
||||||
fputs(" -> ", stderr);
|
fputs(" -> ", stderr);
|
||||||
}
|
}
|
||||||
std::string const &nodeName = name();
|
std::string const &nodeName = name();
|
||||||
|
style_Set(stderr, STYLE_CYAN, true);
|
||||||
fputs(nodeName.c_str(), stderr);
|
fputs(nodeName.c_str(), stderr);
|
||||||
|
style_Set(stderr, STYLE_CYAN, false);
|
||||||
fprintf(stderr, "(%" PRIu32 ")", curLineNo);
|
fprintf(stderr, "(%" PRIu32 ")", curLineNo);
|
||||||
|
style_Reset(stderr);
|
||||||
return nodeName;
|
return nodeName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
#include "helpers.hpp"
|
#include "helpers.hpp"
|
||||||
|
#include "style.hpp"
|
||||||
#include "util.hpp"
|
#include "util.hpp"
|
||||||
#include "verbosity.hpp"
|
#include "verbosity.hpp"
|
||||||
|
|
||||||
@@ -845,9 +846,15 @@ void lexer_DumpStringExpansions() {
|
|||||||
for (Expansion &exp : lexerState->expansions) {
|
for (Expansion &exp : lexerState->expansions) {
|
||||||
// Only register EQUS expansions, not string args
|
// Only register EQUS expansions, not string args
|
||||||
if (exp.name) {
|
if (exp.name) {
|
||||||
fprintf(stderr, "while expanding symbol \"%s\"\n", exp.name->c_str());
|
style_Set(stderr, STYLE_CYAN, false);
|
||||||
|
fputs("while expanding symbol \"", stderr);
|
||||||
|
style_Set(stderr, STYLE_CYAN, true);
|
||||||
|
fputs(exp.name->c_str(), stderr);
|
||||||
|
style_Set(stderr, STYLE_CYAN, false);
|
||||||
|
fputs("\"\n", stderr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
style_Reset(stderr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Functions to discard non-tokenized characters
|
// Functions to discard non-tokenized characters
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
#include "extern/getopt.hpp"
|
#include "extern/getopt.hpp"
|
||||||
#include "helpers.hpp"
|
#include "helpers.hpp"
|
||||||
#include "parser.hpp" // Generated from parser.y
|
#include "parser.hpp" // Generated from parser.y
|
||||||
|
#include "style.hpp"
|
||||||
#include "usage.hpp"
|
#include "usage.hpp"
|
||||||
#include "util.hpp" // UpperMap
|
#include "util.hpp" // UpperMap
|
||||||
#include "verbosity.hpp"
|
#include "verbosity.hpp"
|
||||||
@@ -36,7 +37,7 @@ static std::unordered_map<std::string, std::vector<StateFeature>> stateFileSpecs
|
|||||||
static char const *optstring = "b:D:Eg:hI:M:o:P:p:Q:r:s:VvW:wX:";
|
static char const *optstring = "b:D:Eg:hI:M:o:P:p:Q:r:s:VvW:wX:";
|
||||||
|
|
||||||
// Variables for the long-only options
|
// Variables for the long-only options
|
||||||
static int depType; // Variants of `-M`
|
static int longOpt; // `--color` and variants of `-M`
|
||||||
|
|
||||||
// Equivalent long options
|
// Equivalent long options
|
||||||
// Please keep in the same order as short opts.
|
// Please keep in the same order as short opts.
|
||||||
@@ -53,11 +54,6 @@ static option const longopts[] = {
|
|||||||
{"help", no_argument, nullptr, 'h'},
|
{"help", no_argument, nullptr, 'h'},
|
||||||
{"include", required_argument, nullptr, 'I'},
|
{"include", required_argument, nullptr, 'I'},
|
||||||
{"dependfile", required_argument, nullptr, 'M'},
|
{"dependfile", required_argument, nullptr, 'M'},
|
||||||
{"MC", no_argument, &depType, 'C'},
|
|
||||||
{"MG", no_argument, &depType, 'G'},
|
|
||||||
{"MP", no_argument, &depType, 'P'},
|
|
||||||
{"MQ", required_argument, &depType, 'Q'},
|
|
||||||
{"MT", required_argument, &depType, 'T'},
|
|
||||||
{"output", required_argument, nullptr, 'o'},
|
{"output", required_argument, nullptr, 'o'},
|
||||||
{"preinclude", required_argument, nullptr, 'P'},
|
{"preinclude", required_argument, nullptr, 'P'},
|
||||||
{"pad-value", required_argument, nullptr, 'p'},
|
{"pad-value", required_argument, nullptr, 'p'},
|
||||||
@@ -68,27 +64,34 @@ static option const longopts[] = {
|
|||||||
{"verbose", no_argument, nullptr, 'v'},
|
{"verbose", no_argument, nullptr, 'v'},
|
||||||
{"warning", required_argument, nullptr, 'W'},
|
{"warning", required_argument, nullptr, 'W'},
|
||||||
{"max-errors", required_argument, nullptr, 'X'},
|
{"max-errors", required_argument, nullptr, 'X'},
|
||||||
{nullptr, no_argument, nullptr, 0 }
|
{"color", required_argument, &longOpt, 'c'},
|
||||||
|
{"MC", no_argument, &longOpt, 'C'},
|
||||||
|
{"MG", no_argument, &longOpt, 'G'},
|
||||||
|
{"MP", no_argument, &longOpt, 'P'},
|
||||||
|
{"MQ", required_argument, &longOpt, 'Q'},
|
||||||
|
{"MT", required_argument, &longOpt, 'T'},
|
||||||
|
{nullptr, no_argument, nullptr, 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
// clang-format off: long string literal
|
// clang-format off: nested initializers
|
||||||
static Usage usage(
|
static Usage usage = {
|
||||||
"Usage: rgbasm [-EhVvw] [-b chars] [-D name[=value]] [-g chars] [-I path]\n"
|
.name = "rgbasm",
|
||||||
" [-M depend_file] [-MC] [-MG] [-MP] [-MT target_file] [-MQ target_file]\n"
|
.flags = {
|
||||||
" [-o out_file] [-P include_file] [-p pad_value] [-Q precision]\n"
|
"[-EhVvw]", "[-b chars]", "[-D name[=value]]", "[-g chars]", "[-I path]",
|
||||||
" [-r depth] [-s features:state_file] [-W warning] [-X max_errors]\n"
|
"[-M depend_file]", "[-MC]", "[-MG]", "[-MP]", "[-MT target_file]", "[-MQ target_file]",
|
||||||
" <file>\n"
|
"[-o out_file]", "[-P include_file]", "[-p pad_value]", "[-Q precision]", "[-r depth]",
|
||||||
"Useful options:\n"
|
"[-s features:state_file]", "[-W warning]", "[-X max_errors]", "<file>",
|
||||||
" -E, --export-all export all labels\n"
|
},
|
||||||
" -M, --dependfile <path> set the output dependency file\n"
|
.options = {
|
||||||
" -o, --output <path> set the output object file\n"
|
{{"-E", "--export-all"}, {"export all labels"}},
|
||||||
" -p, --pad-value <value> set the value to use for `ds'\n"
|
{{"-M", "--dependfile <path>"}, {"set the output dependency file"}},
|
||||||
" -s, --state <features>:<path> set an output state file\n"
|
{{"-o", "--output <path>"}, {"set the output object file"}},
|
||||||
" -V, --version print RGBASM version and exit\n"
|
{{"-p", "--pad-value <value>"}, {"set the value to use for `ds'"}},
|
||||||
" -W, --warning <warning> enable or disable warnings\n"
|
{{"-s", "--state <features>:<path>"}, {"set an output state file"}},
|
||||||
"\n"
|
{{"-V", "--version"}, {"print RGBASM version and exit"}},
|
||||||
"For help, use `man rgbasm' or go to https://rgbds.gbdev.io/docs/\n"
|
{{"-W", "--warning <warning>"}, {"enable or disable warnings"}},
|
||||||
);
|
},
|
||||||
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
// LCOV_EXCL_START
|
// LCOV_EXCL_START
|
||||||
@@ -160,7 +163,7 @@ static void verboseOutputConfig(int argc, char *argv[]) {
|
|||||||
"char",
|
"char",
|
||||||
"macro",
|
"macro",
|
||||||
};
|
};
|
||||||
for (auto [name, features] : stateFileSpecs) {
|
for (auto const &[name, features] : stateFileSpecs) {
|
||||||
fprintf(stderr, "\t - %s: ", name == "-" ? "<stdout>" : name.c_str());
|
fprintf(stderr, "\t - %s: ", name == "-" ? "<stdout>" : name.c_str());
|
||||||
for (size_t i = 0; i < features.size(); ++i) {
|
for (size_t i = 0; i < features.size(); ++i) {
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
@@ -449,7 +452,17 @@ int main(int argc, char *argv[]) {
|
|||||||
|
|
||||||
// Long-only options
|
// Long-only options
|
||||||
case 0:
|
case 0:
|
||||||
switch (depType) {
|
switch (longOpt) {
|
||||||
|
case 'c':
|
||||||
|
if (!strcasecmp(musl_optarg, "always")) {
|
||||||
|
style_Enable(true);
|
||||||
|
} else if (!strcasecmp(musl_optarg, "never")) {
|
||||||
|
style_Enable(false);
|
||||||
|
} else if (strcasecmp(musl_optarg, "auto")) {
|
||||||
|
fatal("Invalid argument for option '--color'");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case 'C':
|
case 'C':
|
||||||
options.missingIncludeState = GEN_CONTINUE;
|
options.missingIncludeState = GEN_CONTINUE;
|
||||||
break;
|
break;
|
||||||
@@ -465,7 +478,7 @@ int main(int argc, char *argv[]) {
|
|||||||
case 'Q':
|
case 'Q':
|
||||||
case 'T': {
|
case 'T': {
|
||||||
std::string newTarget = musl_optarg;
|
std::string newTarget = musl_optarg;
|
||||||
if (depType == 'Q') {
|
if (longOpt == 'Q') {
|
||||||
newTarget = escapeMakeChars(newTarget);
|
newTarget = escapeMakeChars(newTarget);
|
||||||
}
|
}
|
||||||
if (!options.targetFileName.empty()) {
|
if (!options.targetFileName.empty()) {
|
||||||
@@ -549,7 +562,7 @@ int main(int argc, char *argv[]) {
|
|||||||
|
|
||||||
out_WriteObject();
|
out_WriteObject();
|
||||||
|
|
||||||
for (auto [name, features] : stateFileSpecs) {
|
for (auto const &[name, features] : stateFileSpecs) {
|
||||||
out_WriteState(name, features);
|
out_WriteState(name, features);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
#include "diagnostics.hpp"
|
#include "diagnostics.hpp"
|
||||||
#include "helpers.hpp"
|
#include "helpers.hpp"
|
||||||
#include "itertools.hpp"
|
#include "itertools.hpp"
|
||||||
|
#include "style.hpp"
|
||||||
|
|
||||||
#include "asm/fstack.hpp"
|
#include "asm/fstack.hpp"
|
||||||
#include "asm/lexer.hpp"
|
#include "asm/lexer.hpp"
|
||||||
@@ -64,14 +65,24 @@ Diagnostics<WarningLevel, WarningID> warnings = {
|
|||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
static void printDiag(
|
static void printDiag(
|
||||||
char const *fmt, va_list args, char const *type, char const *flagfmt, char const *flag
|
char const *fmt,
|
||||||
|
va_list args,
|
||||||
|
char const *type,
|
||||||
|
StyleColor color,
|
||||||
|
char const *flagfmt,
|
||||||
|
char const *flag
|
||||||
) {
|
) {
|
||||||
fputs(type, stderr);
|
style_Set(stderr, color, true);
|
||||||
fputs(": ", stderr);
|
fprintf(stderr, "%s: ", type);
|
||||||
if (fstk_DumpCurrent()) {
|
if (fstk_DumpCurrent()) {
|
||||||
fprintf(stderr, flagfmt, flag);
|
putc(':', stderr);
|
||||||
|
if (flagfmt) {
|
||||||
|
style_Set(stderr, color, true);
|
||||||
|
fprintf(stderr, flagfmt, flag);
|
||||||
|
}
|
||||||
fputs("\n ", stderr);
|
fputs("\n ", stderr);
|
||||||
}
|
}
|
||||||
|
style_Reset(stderr);
|
||||||
vfprintf(stderr, fmt, args);
|
vfprintf(stderr, fmt, args);
|
||||||
putc('\n', stderr);
|
putc('\n', stderr);
|
||||||
|
|
||||||
@@ -82,13 +93,16 @@ static void incrementErrors() {
|
|||||||
// This intentionally makes 0 act as "unlimited"
|
// This intentionally makes 0 act as "unlimited"
|
||||||
warnings.incrementErrors();
|
warnings.incrementErrors();
|
||||||
if (warnings.nbErrors == options.maxErrors) {
|
if (warnings.nbErrors == options.maxErrors) {
|
||||||
|
style_Set(stderr, STYLE_RED, true);
|
||||||
fprintf(
|
fprintf(
|
||||||
stderr,
|
stderr,
|
||||||
"Assembly aborted after the maximum of %" PRIu64 " error%s! (configure with "
|
"Assembly aborted after the maximum of %" PRIu64 " error%s!",
|
||||||
"'-X/--max-errors')\n",
|
|
||||||
warnings.nbErrors,
|
warnings.nbErrors,
|
||||||
warnings.nbErrors == 1 ? "" : "s"
|
warnings.nbErrors == 1 ? "" : "s"
|
||||||
);
|
);
|
||||||
|
style_Set(stderr, STYLE_RED, false);
|
||||||
|
fputs(" (configure with '-X/--max-errors')\n", stderr);
|
||||||
|
style_Reset(stderr);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -97,17 +111,19 @@ void error(char const *fmt, ...) {
|
|||||||
va_list args;
|
va_list args;
|
||||||
|
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
printDiag(fmt, args, "error", ":", nullptr);
|
printDiag(fmt, args, "error", STYLE_RED, nullptr, nullptr);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
incrementErrors();
|
incrementErrors();
|
||||||
}
|
}
|
||||||
|
|
||||||
void error(std::function<void()> callback) {
|
void error(std::function<void()> callback) {
|
||||||
|
style_Set(stderr, STYLE_RED, true);
|
||||||
fputs("error: ", stderr);
|
fputs("error: ", stderr);
|
||||||
if (fstk_DumpCurrent()) {
|
if (fstk_DumpCurrent()) {
|
||||||
fputs(":\n ", stderr);
|
fputs(":\n ", stderr);
|
||||||
}
|
}
|
||||||
|
style_Reset(stderr);
|
||||||
callback();
|
callback();
|
||||||
putc('\n', stderr);
|
putc('\n', stderr);
|
||||||
lexer_DumpStringExpansions();
|
lexer_DumpStringExpansions();
|
||||||
@@ -120,7 +136,7 @@ void fatal(char const *fmt, ...) {
|
|||||||
va_list args;
|
va_list args;
|
||||||
|
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
printDiag(fmt, args, "FATAL", ":", nullptr);
|
printDiag(fmt, args, "FATAL", STYLE_RED, nullptr, nullptr);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
exit(1);
|
exit(1);
|
||||||
@@ -128,12 +144,14 @@ void fatal(char const *fmt, ...) {
|
|||||||
|
|
||||||
void requireZeroErrors() {
|
void requireZeroErrors() {
|
||||||
if (warnings.nbErrors != 0) {
|
if (warnings.nbErrors != 0) {
|
||||||
|
style_Set(stderr, STYLE_RED, true);
|
||||||
fprintf(
|
fprintf(
|
||||||
stderr,
|
stderr,
|
||||||
"Assembly aborted with %" PRIu64 " error%s!\n",
|
"Assembly aborted with %" PRIu64 " error%s!\n",
|
||||||
warnings.nbErrors,
|
warnings.nbErrors,
|
||||||
warnings.nbErrors == 1 ? "" : "s"
|
warnings.nbErrors == 1 ? "" : "s"
|
||||||
);
|
);
|
||||||
|
style_Reset(stderr);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -149,11 +167,11 @@ void warning(WarningID id, char const *fmt, ...) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case WarningBehavior::ENABLED:
|
case WarningBehavior::ENABLED:
|
||||||
printDiag(fmt, args, "warning", ": [-W%s]", flag);
|
printDiag(fmt, args, "warning", STYLE_YELLOW, " [-W%s]", flag);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WarningBehavior::ERROR:
|
case WarningBehavior::ERROR:
|
||||||
printDiag(fmt, args, "error", ": [-Werror=%s]", flag);
|
printDiag(fmt, args, "error", STYLE_RED, " [-Werror=%s]", flag);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
#include "diagnostics.hpp"
|
#include "diagnostics.hpp"
|
||||||
|
|
||||||
void warnx(char const *fmt, ...) {
|
void warnx(char const *fmt, ...) {
|
||||||
|
|||||||
102
src/fix/main.cpp
102
src/fix/main.cpp
@@ -16,6 +16,7 @@
|
|||||||
#include "extern/getopt.hpp"
|
#include "extern/getopt.hpp"
|
||||||
#include "helpers.hpp"
|
#include "helpers.hpp"
|
||||||
#include "platform.hpp"
|
#include "platform.hpp"
|
||||||
|
#include "style.hpp"
|
||||||
#include "usage.hpp"
|
#include "usage.hpp"
|
||||||
#include "version.hpp"
|
#include "version.hpp"
|
||||||
|
|
||||||
@@ -27,6 +28,9 @@ static constexpr off_t BANK_SIZE = 0x4000;
|
|||||||
// Short options
|
// Short options
|
||||||
static char const *optstring = "Ccf:hi:jk:L:l:m:n:Oo:p:r:st:VvW:w";
|
static char const *optstring = "Ccf:hi:jk:L:l:m:n:Oo:p:r:st:VvW:w";
|
||||||
|
|
||||||
|
// Variables for the long-only options
|
||||||
|
static int longOpt; // `--color`
|
||||||
|
|
||||||
// Equivalent long options
|
// Equivalent long options
|
||||||
// Please keep in the same order as short opts.
|
// Please keep in the same order as short opts.
|
||||||
// Also, make sure long opts don't create ambiguity:
|
// Also, make sure long opts don't create ambiguity:
|
||||||
@@ -35,47 +39,54 @@ static char const *optstring = "Ccf:hi:jk:L:l:m:n:Oo:p:r:st:VvW:w";
|
|||||||
// This is because long opt matching, even to a single char, is prioritized
|
// This is because long opt matching, even to a single char, is prioritized
|
||||||
// over short opt matching.
|
// over short opt matching.
|
||||||
static option const longopts[] = {
|
static option const longopts[] = {
|
||||||
{"color-only", no_argument, nullptr, 'C'},
|
{"color-only", no_argument, nullptr, 'C'},
|
||||||
{"color-compatible", no_argument, nullptr, 'c'},
|
{"color-compatible", no_argument, nullptr, 'c'},
|
||||||
{"fix-spec", required_argument, nullptr, 'f'},
|
{"fix-spec", required_argument, nullptr, 'f'},
|
||||||
{"help", no_argument, nullptr, 'h'},
|
{"help", no_argument, nullptr, 'h'},
|
||||||
{"game-id", required_argument, nullptr, 'i'},
|
{"game-id", required_argument, nullptr, 'i'},
|
||||||
{"non-japanese", no_argument, nullptr, 'j'},
|
{"non-japanese", no_argument, nullptr, 'j'},
|
||||||
{"new-licensee", required_argument, nullptr, 'k'},
|
{"new-licensee", required_argument, nullptr, 'k'},
|
||||||
{"logo", required_argument, nullptr, 'L'},
|
{"logo", required_argument, nullptr, 'L'},
|
||||||
{"old-licensee", required_argument, nullptr, 'l'},
|
{"old-licensee", required_argument, nullptr, 'l'},
|
||||||
{"mbc-type", required_argument, nullptr, 'm'},
|
{"mbc-type", required_argument, nullptr, 'm'},
|
||||||
{"rom-version", required_argument, nullptr, 'n'},
|
{"rom-version", required_argument, nullptr, 'n'},
|
||||||
{"overwrite", no_argument, nullptr, 'O'},
|
{"overwrite", no_argument, nullptr, 'O'},
|
||||||
{"output", required_argument, nullptr, 'o'},
|
{"output", required_argument, nullptr, 'o'},
|
||||||
{"pad-value", required_argument, nullptr, 'p'},
|
{"pad-value", required_argument, nullptr, 'p'},
|
||||||
{"ram-size", required_argument, nullptr, 'r'},
|
{"ram-size", required_argument, nullptr, 'r'},
|
||||||
{"sgb-compatible", no_argument, nullptr, 's'},
|
{"sgb-compatible", no_argument, nullptr, 's'},
|
||||||
{"title", required_argument, nullptr, 't'},
|
{"title", required_argument, nullptr, 't'},
|
||||||
{"version", no_argument, nullptr, 'V'},
|
{"version", no_argument, nullptr, 'V'},
|
||||||
{"validate", no_argument, nullptr, 'v'},
|
{"validate", no_argument, nullptr, 'v'},
|
||||||
{"warning", required_argument, nullptr, 'W'},
|
{"warning", required_argument, nullptr, 'W'},
|
||||||
{nullptr, no_argument, nullptr, 0 }
|
{"color", required_argument, &longOpt, 'c'},
|
||||||
|
{nullptr, no_argument, nullptr, 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
// clang-format off: long string literal
|
// clang-format off: nested initializers
|
||||||
static Usage usage(
|
static Usage usage = {
|
||||||
"Usage: rgbfix [-hjOsVvw] [-C | -c] [-f <fix_spec>] [-i <game_id>] [-k <licensee>]\n"
|
.name = "rgbfix",
|
||||||
" [-L <logo_file>] [-l <licensee_byte>] [-m <mbc_type>]\n"
|
.flags = {
|
||||||
" [-n <rom_version>] [-p <pad_value>] [-r <ram_size>] [-t <title_str>]\n"
|
"[-hjOsVvw]", "[-C | -c]", "[-f <fix_spec>]", "[-i <game_id>]", "[-k <licensee>]",
|
||||||
" [-W warning] <file> ...\n"
|
"[-L <logo_file>]", "[-l <licensee_byte>]", "[-m <mbc_type>]", "[-n <rom_version>]",
|
||||||
"Useful options:\n"
|
"[-p <pad_value>]", "[-r <ram_size>]", "[-t <title_str>]", "[-W warning]", "<file> ...",
|
||||||
" -m, --mbc-type <value> set the MBC type byte to this value; `-m help'\n"
|
},
|
||||||
" or `-m list' prints the accepted values\n"
|
.options = {
|
||||||
" -p, --pad-value <value> pad to the next valid size using this value\n"
|
{
|
||||||
" -r, --ram-size <code> set the cart RAM size byte to this value\n"
|
{"-m", "--mbc-type <value>"},
|
||||||
" -o, --output <path> set the output file\n"
|
{
|
||||||
" -V, --version print RGBFIX version and exit\n"
|
"set the MBC type byte to this value; `-m help'",
|
||||||
" -v, --validate fix the header logo and both checksums (`-f lhg')\n"
|
"or `-m list' prints the accepted values",
|
||||||
" -W, --warning <warning> enable or disable warnings\n"
|
},
|
||||||
"\n"
|
},
|
||||||
"For help, use `man rgbfix' or go to https://rgbds.gbdev.io/docs/\n"
|
{{"-p", "--pad-value <value>"}, {"pad to the next valid size using this value"}},
|
||||||
);
|
{{"-r", "--ram-size <code>"}, {"set the cart RAM size byte to this value"}},
|
||||||
|
{{"-o", "--output <path>"}, {"set the output file"}},
|
||||||
|
{{"-V", "--version"}, {"print RGBFIX version and exit"}},
|
||||||
|
{{"-v", "--validate"}, {"fix the header logo and both checksums (`-f lhg')"}},
|
||||||
|
{{"-W", "--warning <warning>"}, {"enable or disable warnings"}},
|
||||||
|
},
|
||||||
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
static uint8_t tpp1Rev[2];
|
static uint8_t tpp1Rev[2];
|
||||||
@@ -817,6 +828,19 @@ int main(int argc, char *argv[]) {
|
|||||||
warnings.state.warningsEnabled = false;
|
warnings.state.warningsEnabled = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
// Long-only options
|
||||||
|
case 0:
|
||||||
|
if (longOpt == 'c') {
|
||||||
|
if (!strcasecmp(musl_optarg, "always")) {
|
||||||
|
style_Enable(true);
|
||||||
|
} else if (!strcasecmp(musl_optarg, "never")) {
|
||||||
|
style_Enable(false);
|
||||||
|
} else if (strcasecmp(musl_optarg, "auto")) {
|
||||||
|
fatal("Invalid argument for option '--color'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
usage.printAndExit(1); // LCOV_EXCL_LINE
|
usage.printAndExit(1); // LCOV_EXCL_LINE
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
#include "fix/mbc.hpp"
|
#include "fix/mbc.hpp"
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
#include "fix/warning.hpp"
|
#include "fix/warning.hpp"
|
||||||
|
|
||||||
|
#include "style.hpp"
|
||||||
|
|
||||||
// clang-format off: nested initializers
|
// clang-format off: nested initializers
|
||||||
Diagnostics<WarningLevel, WarningID> warnings = {
|
Diagnostics<WarningLevel, WarningID> warnings = {
|
||||||
.metaWarnings = {
|
.metaWarnings = {
|
||||||
@@ -20,6 +24,7 @@ Diagnostics<WarningLevel, WarningID> warnings = {
|
|||||||
|
|
||||||
uint32_t checkErrors(char const *filename) {
|
uint32_t checkErrors(char const *filename) {
|
||||||
if (warnings.nbErrors > 0) {
|
if (warnings.nbErrors > 0) {
|
||||||
|
style_Set(stderr, STYLE_RED, true);
|
||||||
fprintf(
|
fprintf(
|
||||||
stderr,
|
stderr,
|
||||||
"Fixing \"%s\" failed with %" PRIu64 " error%s\n",
|
"Fixing \"%s\" failed with %" PRIu64 " error%s\n",
|
||||||
@@ -27,13 +32,16 @@ uint32_t checkErrors(char const *filename) {
|
|||||||
warnings.nbErrors,
|
warnings.nbErrors,
|
||||||
warnings.nbErrors == 1 ? "" : "s"
|
warnings.nbErrors == 1 ? "" : "s"
|
||||||
);
|
);
|
||||||
|
style_Reset(stderr);
|
||||||
}
|
}
|
||||||
return warnings.nbErrors;
|
return warnings.nbErrors;
|
||||||
}
|
}
|
||||||
|
|
||||||
void error(char const *fmt, ...) {
|
void error(char const *fmt, ...) {
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
style_Set(stderr, STYLE_RED, true);
|
||||||
fputs("error: ", stderr);
|
fputs("error: ", stderr);
|
||||||
|
style_Reset(stderr);
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
vfprintf(stderr, fmt, ap);
|
vfprintf(stderr, fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
@@ -44,7 +52,9 @@ void error(char const *fmt, ...) {
|
|||||||
|
|
||||||
void fatal(char const *fmt, ...) {
|
void fatal(char const *fmt, ...) {
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
style_Set(stderr, STYLE_RED, true);
|
||||||
fputs("FATAL: ", stderr);
|
fputs("FATAL: ", stderr);
|
||||||
|
style_Reset(stderr);
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
vfprintf(stderr, fmt, ap);
|
vfprintf(stderr, fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
@@ -62,7 +72,9 @@ void warning(WarningID id, char const *fmt, ...) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case WarningBehavior::ENABLED:
|
case WarningBehavior::ENABLED:
|
||||||
|
style_Set(stderr, STYLE_YELLOW, true);
|
||||||
fprintf(stderr, "warning: [-W%s]\n ", flag);
|
fprintf(stderr, "warning: [-W%s]\n ", flag);
|
||||||
|
style_Reset(stderr);
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
vfprintf(stderr, fmt, ap);
|
vfprintf(stderr, fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
@@ -70,7 +82,9 @@ void warning(WarningID id, char const *fmt, ...) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case WarningBehavior::ERROR:
|
case WarningBehavior::ERROR:
|
||||||
|
style_Set(stderr, STYLE_RED, true);
|
||||||
fprintf(stderr, "error: [-Werror=%s]\n ", flag);
|
fprintf(stderr, "error: [-Werror=%s]\n ", flag);
|
||||||
|
style_Reset(stderr);
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
vfprintf(stderr, fmt, ap);
|
vfprintf(stderr, fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|||||||
120
src/gfx/main.cpp
120
src/gfx/main.cpp
@@ -18,6 +18,7 @@
|
|||||||
#include "extern/getopt.hpp"
|
#include "extern/getopt.hpp"
|
||||||
#include "file.hpp"
|
#include "file.hpp"
|
||||||
#include "platform.hpp"
|
#include "platform.hpp"
|
||||||
|
#include "style.hpp"
|
||||||
#include "usage.hpp"
|
#include "usage.hpp"
|
||||||
#include "verbosity.hpp"
|
#include "verbosity.hpp"
|
||||||
#include "version.hpp"
|
#include "version.hpp"
|
||||||
@@ -44,6 +45,9 @@ static struct LocalOptions {
|
|||||||
// Short options
|
// Short options
|
||||||
static char const *optstring = "-Aa:B:b:Cc:d:hi:L:l:mN:n:Oo:Pp:Qq:r:s:Tt:U:uVvW:wXx:YZ";
|
static char const *optstring = "-Aa:B:b:Cc:d:hi:L:l:mN:n:Oo:Pp:Qq:r:s:Tt:U:uVvW:wXx:YZ";
|
||||||
|
|
||||||
|
// Variables for the long-only options
|
||||||
|
static int longOpt; // `--color`
|
||||||
|
|
||||||
// Equivalent long options
|
// Equivalent long options
|
||||||
// Please keep in the same order as short opts.
|
// Please keep in the same order as short opts.
|
||||||
// Also, make sure long opts don't create ambiguity:
|
// Also, make sure long opts don't create ambiguity:
|
||||||
@@ -52,59 +56,62 @@ static char const *optstring = "-Aa:B:b:Cc:d:hi:L:l:mN:n:Oo:Pp:Qq:r:s:Tt:U:uVvW:
|
|||||||
// This is because long opt matching, even to a single char, is prioritized
|
// This is because long opt matching, even to a single char, is prioritized
|
||||||
// over short opt matching.
|
// over short opt matching.
|
||||||
static option const longopts[] = {
|
static option const longopts[] = {
|
||||||
{"auto-attr-map", no_argument, nullptr, 'A'},
|
{"auto-attr-map", no_argument, nullptr, 'A'},
|
||||||
{"attr-map", required_argument, nullptr, 'a'},
|
{"attr-map", required_argument, nullptr, 'a'},
|
||||||
{"background-color", required_argument, nullptr, 'B'},
|
{"background-color", required_argument, nullptr, 'B'},
|
||||||
{"base-tiles", required_argument, nullptr, 'b'},
|
{"base-tiles", required_argument, nullptr, 'b'},
|
||||||
{"color-curve", no_argument, nullptr, 'C'},
|
{"color-curve", no_argument, nullptr, 'C'},
|
||||||
{"colors", required_argument, nullptr, 'c'},
|
{"colors", required_argument, nullptr, 'c'},
|
||||||
{"depth", required_argument, nullptr, 'd'},
|
{"depth", required_argument, nullptr, 'd'},
|
||||||
{"help", no_argument, nullptr, 'h'},
|
{"help", no_argument, nullptr, 'h'},
|
||||||
{"input-tileset", required_argument, nullptr, 'i'},
|
{"input-tileset", required_argument, nullptr, 'i'},
|
||||||
{"slice", required_argument, nullptr, 'L'},
|
{"slice", required_argument, nullptr, 'L'},
|
||||||
{"base-palette", required_argument, nullptr, 'l'},
|
{"base-palette", required_argument, nullptr, 'l'},
|
||||||
{"mirror-tiles", no_argument, nullptr, 'm'},
|
{"mirror-tiles", no_argument, nullptr, 'm'},
|
||||||
{"nb-tiles", required_argument, nullptr, 'N'},
|
{"nb-tiles", required_argument, nullptr, 'N'},
|
||||||
{"nb-palettes", required_argument, nullptr, 'n'},
|
{"nb-palettes", required_argument, nullptr, 'n'},
|
||||||
{"group-outputs", no_argument, nullptr, 'O'},
|
{"group-outputs", no_argument, nullptr, 'O'},
|
||||||
{"output", required_argument, nullptr, 'o'},
|
{"output", required_argument, nullptr, 'o'},
|
||||||
{"auto-palette", no_argument, nullptr, 'P'},
|
{"auto-palette", no_argument, nullptr, 'P'},
|
||||||
{"palette", required_argument, nullptr, 'p'},
|
{"palette", required_argument, nullptr, 'p'},
|
||||||
{"auto-palette-map", no_argument, nullptr, 'Q'},
|
{"auto-palette-map", no_argument, nullptr, 'Q'},
|
||||||
{"palette-map", required_argument, nullptr, 'q'},
|
{"palette-map", required_argument, nullptr, 'q'},
|
||||||
{"reverse", required_argument, nullptr, 'r'},
|
{"reverse", required_argument, nullptr, 'r'},
|
||||||
{"palette-size", required_argument, nullptr, 's'},
|
{"palette-size", required_argument, nullptr, 's'},
|
||||||
{"auto-tilemap", no_argument, nullptr, 'T'},
|
{"auto-tilemap", no_argument, nullptr, 'T'},
|
||||||
{"tilemap", required_argument, nullptr, 't'},
|
{"tilemap", required_argument, nullptr, 't'},
|
||||||
{"unit-size", required_argument, nullptr, 'U'},
|
{"unit-size", required_argument, nullptr, 'U'},
|
||||||
{"unique-tiles", no_argument, nullptr, 'u'},
|
{"unique-tiles", no_argument, nullptr, 'u'},
|
||||||
{"version", no_argument, nullptr, 'V'},
|
{"version", no_argument, nullptr, 'V'},
|
||||||
{"verbose", no_argument, nullptr, 'v'},
|
{"verbose", no_argument, nullptr, 'v'},
|
||||||
{"warning", required_argument, nullptr, 'W'},
|
{"warning", required_argument, nullptr, 'W'},
|
||||||
{"mirror-x", no_argument, nullptr, 'X'},
|
{"mirror-x", no_argument, nullptr, 'X'},
|
||||||
{"trim-end", required_argument, nullptr, 'x'},
|
{"trim-end", required_argument, nullptr, 'x'},
|
||||||
{"mirror-y", no_argument, nullptr, 'Y'},
|
{"mirror-y", no_argument, nullptr, 'Y'},
|
||||||
{"columns", no_argument, nullptr, 'Z'},
|
{"columns", no_argument, nullptr, 'Z'},
|
||||||
{nullptr, no_argument, nullptr, 0 }
|
{"color", required_argument, &longOpt, 'c'},
|
||||||
|
{nullptr, no_argument, nullptr, 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
// clang-format off: long string literal
|
// clang-format off: nested initializers
|
||||||
static Usage usage(
|
static Usage usage = {
|
||||||
"Usage: rgbgfx [-r stride] [-ChmOuVXYZ] [-v [-v ...]] [-a <attr_map> | -A]\n"
|
.name = "rgbgfx",
|
||||||
" [-b <base_ids>] [-c <colors>] [-d <depth>] [-i <tileset_file>]\n"
|
.flags = {
|
||||||
" [-L <slice>] [-l <base_pal>] [-N <nb_tiles>] [-n <nb_pals>]\n"
|
"[-r stride]", "[-ChmOuVXYZ]", "[-v [-v ...]]", "[-a <attr_map> | -A]", "[-b <base_ids>]",
|
||||||
" [-o <out_file>] [-p <pal_file> | -P] [-q <pal_map> | -Q]\n"
|
"[-c <colors>]", "[-d <depth>]", "[-i <tileset_file>]", "[-L <slice>]", "[-l <base_pal>]",
|
||||||
" [-s <nb_colors>] [-t <tile_map> | -T] [-x <nb_tiles>] <file>\n"
|
"[-N <nb_tiles>]", "[-n <nb_pals>]", "[-o <out_file>]", "[-p <pal_file> | -P]",
|
||||||
"Useful options:\n"
|
"[-q <pal_map> | -Q]", "[-s <nb_colors>]", "[-t <tile_map> | -T]", "[-x <nb_tiles>]",
|
||||||
" -m, --mirror-tiles optimize out mirrored tiles\n"
|
"<file>",
|
||||||
" -o, --output <path> output the tile data to this path\n"
|
},
|
||||||
" -t, --tilemap <path> output the tile map to this path\n"
|
.options = {
|
||||||
" -u, --unique-tiles optimize out identical tiles\n"
|
{{"-m", "--mirror-tiles"}, {"optimize out mirrored tiles"}},
|
||||||
" -V, --version print RGBGFX version and exit\n"
|
{{"-o", "--output <path>"}, {"output the tile data to this path"}},
|
||||||
" -W, --warning <warning> enable or disable warnings\n"
|
{{"-t", "--tilemap <path>"}, {"output the tile map to this path"}},
|
||||||
"\n"
|
{{"-u", "--unique-tiles"}, {"optimize out identical tiles"}},
|
||||||
"For help, use `man rgbgfx' or go to https://rgbds.gbdev.io/docs/\n"
|
{{"-V", "--version"}, {"print RGBGFX version and exit"}},
|
||||||
);
|
{{"-W", "--warning <warning>"}, {"enable or disable warnings"}},
|
||||||
|
},
|
||||||
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
// Parses a number at the beginning of a string, moving the pointer to skip the parsed characters.
|
// Parses a number at the beginning of a string, moving the pointer to skip the parsed characters.
|
||||||
@@ -552,6 +559,17 @@ static char *parseArgv(int argc, char *argv[]) {
|
|||||||
case 'Z':
|
case 'Z':
|
||||||
options.columnMajor = true;
|
options.columnMajor = true;
|
||||||
break;
|
break;
|
||||||
|
case 0: // Long-only options
|
||||||
|
if (longOpt == 'c') {
|
||||||
|
if (!strcasecmp(musl_optarg, "always")) {
|
||||||
|
style_Enable(true);
|
||||||
|
} else if (!strcasecmp(musl_optarg, "never")) {
|
||||||
|
style_Enable(false);
|
||||||
|
} else if (strcasecmp(musl_optarg, "auto")) {
|
||||||
|
fatal("Invalid argument for option '--color'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 1: // Positional argument, requested by leading `-` in opt string
|
case 1: // Positional argument, requested by leading `-` in opt string
|
||||||
if (musl_optarg[0] == '@') {
|
if (musl_optarg[0] == '@') {
|
||||||
// Instruct the caller to process that at-file
|
// Instruct the caller to process that at-file
|
||||||
|
|||||||
@@ -630,7 +630,7 @@ static void outputUnoptimizedTileData(
|
|||||||
uint64_t nbKeptTiles = nbTiles > options.trim ? nbTiles - options.trim : 0;
|
uint64_t nbKeptTiles = nbTiles > options.trim ? nbTiles - options.trim : 0;
|
||||||
uint64_t tileIdx = 0;
|
uint64_t tileIdx = 0;
|
||||||
|
|
||||||
for (auto [tile, attr] : zip(image.visitAsTiles(), attrmap)) {
|
for (auto const &[tile, attr] : zip(image.visitAsTiles(), attrmap)) {
|
||||||
// Do not emit fully-background tiles.
|
// Do not emit fully-background tiles.
|
||||||
if (attr.isBackgroundTile()) {
|
if (attr.isBackgroundTile()) {
|
||||||
++tileIdx;
|
++tileIdx;
|
||||||
@@ -799,7 +799,7 @@ static UniqueTiles dedupTiles(
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool inputWithoutOutput = !options.inputTileset.empty() && options.output.empty();
|
bool inputWithoutOutput = !options.inputTileset.empty() && options.output.empty();
|
||||||
for (auto [tile, attr] : zip(image.visitAsTiles(), attrmap)) {
|
for (auto const &[tile, attr] : zip(image.visitAsTiles(), attrmap)) {
|
||||||
if (attr.isBackgroundTile()) {
|
if (attr.isBackgroundTile()) {
|
||||||
attr.xFlip = false;
|
attr.xFlip = false;
|
||||||
attr.yFlip = false;
|
attr.yFlip = false;
|
||||||
|
|||||||
@@ -7,6 +7,8 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "style.hpp"
|
||||||
|
|
||||||
// clang-format off: nested initializers
|
// clang-format off: nested initializers
|
||||||
Diagnostics<WarningLevel, WarningID> warnings = {
|
Diagnostics<WarningLevel, WarningID> warnings = {
|
||||||
.metaWarnings = {
|
.metaWarnings = {
|
||||||
@@ -25,12 +27,14 @@ Diagnostics<WarningLevel, WarningID> warnings = {
|
|||||||
|
|
||||||
[[noreturn]]
|
[[noreturn]]
|
||||||
void giveUp() {
|
void giveUp() {
|
||||||
|
style_Set(stderr, STYLE_RED, true);
|
||||||
fprintf(
|
fprintf(
|
||||||
stderr,
|
stderr,
|
||||||
"Conversion aborted after %" PRIu64 " error%s\n",
|
"Conversion aborted after %" PRIu64 " error%s\n",
|
||||||
warnings.nbErrors,
|
warnings.nbErrors,
|
||||||
warnings.nbErrors == 1 ? "" : "s"
|
warnings.nbErrors == 1 ? "" : "s"
|
||||||
);
|
);
|
||||||
|
style_Reset(stderr);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,7 +46,9 @@ void requireZeroErrors() {
|
|||||||
|
|
||||||
void error(char const *fmt, ...) {
|
void error(char const *fmt, ...) {
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
style_Set(stderr, STYLE_RED, true);
|
||||||
fputs("error: ", stderr);
|
fputs("error: ", stderr);
|
||||||
|
style_Reset(stderr);
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
vfprintf(stderr, fmt, ap);
|
vfprintf(stderr, fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
@@ -54,7 +60,9 @@ void error(char const *fmt, ...) {
|
|||||||
[[noreturn]]
|
[[noreturn]]
|
||||||
void fatal(char const *fmt, ...) {
|
void fatal(char const *fmt, ...) {
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
style_Set(stderr, STYLE_RED, true);
|
||||||
fputs("FATAL: ", stderr);
|
fputs("FATAL: ", stderr);
|
||||||
|
style_Reset(stderr);
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
vfprintf(stderr, fmt, ap);
|
vfprintf(stderr, fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
@@ -73,7 +81,9 @@ void warning(WarningID id, char const *fmt, ...) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case WarningBehavior::ENABLED:
|
case WarningBehavior::ENABLED:
|
||||||
|
style_Set(stderr, STYLE_YELLOW, true);
|
||||||
fprintf(stderr, "warning: [-W%s]\n ", flag);
|
fprintf(stderr, "warning: [-W%s]\n ", flag);
|
||||||
|
style_Reset(stderr);
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
vfprintf(stderr, fmt, ap);
|
vfprintf(stderr, fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
@@ -81,7 +91,9 @@ void warning(WarningID id, char const *fmt, ...) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case WarningBehavior::ERROR:
|
case WarningBehavior::ERROR:
|
||||||
|
style_Set(stderr, STYLE_RED, true);
|
||||||
fprintf(stderr, "error: [-Werror=%s]\n ", flag);
|
fprintf(stderr, "error: [-Werror=%s]\n ", flag);
|
||||||
|
style_Reset(stderr);
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
vfprintf(stderr, fmt, ap);
|
vfprintf(stderr, fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
#include "itertools.hpp"
|
#include "itertools.hpp"
|
||||||
#include "platform.hpp"
|
#include "platform.hpp"
|
||||||
#include "script.hpp" // Generated from script.y
|
#include "script.hpp" // Generated from script.y
|
||||||
|
#include "style.hpp"
|
||||||
#include "usage.hpp"
|
#include "usage.hpp"
|
||||||
#include "util.hpp" // UpperMap, printChar
|
#include "util.hpp" // UpperMap, printChar
|
||||||
#include "verbosity.hpp"
|
#include "verbosity.hpp"
|
||||||
@@ -37,6 +38,9 @@ static char const *linkerScriptName = nullptr; // -l
|
|||||||
// Short options
|
// Short options
|
||||||
static char const *optstring = "dhl:m:Mn:O:o:p:S:tVvW:wx";
|
static char const *optstring = "dhl:m:Mn:O:o:p:S:tVvW:wx";
|
||||||
|
|
||||||
|
// Variables for the long-only options
|
||||||
|
static int longOpt; // `--color`
|
||||||
|
|
||||||
// Equivalent long options
|
// Equivalent long options
|
||||||
// Please keep in the same order as short opts.
|
// Please keep in the same order as short opts.
|
||||||
// Also, make sure long opts don't create ambiguity:
|
// Also, make sure long opts don't create ambiguity:
|
||||||
@@ -45,42 +49,44 @@ static char const *optstring = "dhl:m:Mn:O:o:p:S:tVvW:wx";
|
|||||||
// This is because long opt matching, even to a single char, is prioritized
|
// This is because long opt matching, even to a single char, is prioritized
|
||||||
// over short opt matching.
|
// over short opt matching.
|
||||||
static option const longopts[] = {
|
static option const longopts[] = {
|
||||||
{"dmg", no_argument, nullptr, 'd'},
|
{"dmg", no_argument, nullptr, 'd'},
|
||||||
{"help", no_argument, nullptr, 'h'},
|
{"help", no_argument, nullptr, 'h'},
|
||||||
{"linkerscript", required_argument, nullptr, 'l'},
|
{"linkerscript", required_argument, nullptr, 'l'},
|
||||||
{"map", required_argument, nullptr, 'm'},
|
{"map", required_argument, nullptr, 'm'},
|
||||||
{"no-sym-in-map", no_argument, nullptr, 'M'},
|
{"no-sym-in-map", no_argument, nullptr, 'M'},
|
||||||
{"sym", required_argument, nullptr, 'n'},
|
{"sym", required_argument, nullptr, 'n'},
|
||||||
{"overlay", required_argument, nullptr, 'O'},
|
{"overlay", required_argument, nullptr, 'O'},
|
||||||
{"output", required_argument, nullptr, 'o'},
|
{"output", required_argument, nullptr, 'o'},
|
||||||
{"pad", required_argument, nullptr, 'p'},
|
{"pad", required_argument, nullptr, 'p'},
|
||||||
{"scramble", required_argument, nullptr, 'S'},
|
{"scramble", required_argument, nullptr, 'S'},
|
||||||
{"tiny", no_argument, nullptr, 't'},
|
{"tiny", no_argument, nullptr, 't'},
|
||||||
{"version", no_argument, nullptr, 'V'},
|
{"version", no_argument, nullptr, 'V'},
|
||||||
{"verbose", no_argument, nullptr, 'v'},
|
{"verbose", no_argument, nullptr, 'v'},
|
||||||
{"warning", required_argument, nullptr, 'W'},
|
{"warning", required_argument, nullptr, 'W'},
|
||||||
{"wramx", no_argument, nullptr, 'w'},
|
{"wramx", no_argument, nullptr, 'w'},
|
||||||
{"nopad", no_argument, nullptr, 'x'},
|
{"nopad", no_argument, nullptr, 'x'},
|
||||||
{nullptr, no_argument, nullptr, 0 }
|
{"color", required_argument, &longOpt, 'c'},
|
||||||
|
{nullptr, no_argument, nullptr, 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
// clang-format off: long string literal
|
// clang-format off: nested initializers
|
||||||
static Usage usage(
|
static Usage usage = {
|
||||||
"Usage: rgblink [-dhMtVvwx] [-l script] [-m map_file] [-n sym_file]\n"
|
.name = "rgblink",
|
||||||
" [-O overlay_file] [-o out_file] [-p pad_value]\n"
|
.flags = {
|
||||||
" [-S spec] <file> ...\n"
|
"[-dhMtVvwx]", "[-l script]", "[-m map_file]", "[-n sym_file]", "[-O overlay_file]",
|
||||||
"Useful options:\n"
|
"[-o out_file]", "[-p pad_value]", "[-S spec]", "<file> ...",
|
||||||
" -l, --linkerscript <path> set the input linker script\n"
|
},
|
||||||
" -m, --map <path> set the output map file\n"
|
.options = {
|
||||||
" -n, --sym <path> set the output symbol list file\n"
|
{{"-l", "--linkerscript <path>"}, {"set the input linker script"}},
|
||||||
" -o, --output <path> set the output file\n"
|
{{"-m", "--map <path>"}, {"set the output map file"}},
|
||||||
" -p, --pad <value> set the value to pad between sections with\n"
|
{{"-n", "--sym <path>"}, {"set the output symbol list file"}},
|
||||||
" -x, --nopad disable padding of output binary\n"
|
{{"-o", "--output <path>"}, {"set the output file"}},
|
||||||
" -V, --version print RGBLINK version and exit\n"
|
{{"-p", "--pad <value>"}, {"set the value to pad between sections with"}},
|
||||||
" -W, --warning <warning> enable or disable warnings\n"
|
{{"-x", "--nopad"}, {"disable padding of output binary"}},
|
||||||
"\n"
|
{{"-V", "--version"}, {"print RGBLINK version and exit"}},
|
||||||
"For help, use `man rgblink' or go to https://rgbds.gbdev.io/docs/\n"
|
{{"-W", "--warning <warning>"}, {"enable or disable warnings"}},
|
||||||
);
|
},
|
||||||
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
// LCOV_EXCL_START
|
// LCOV_EXCL_START
|
||||||
@@ -174,21 +180,29 @@ std::string const &FileStackNode::dump(uint32_t curLineNo) const {
|
|||||||
if (std::holds_alternative<std::vector<uint32_t>>(data)) {
|
if (std::holds_alternative<std::vector<uint32_t>>(data)) {
|
||||||
assume(parent); // REPT nodes use their parent's name
|
assume(parent); // REPT nodes use their parent's name
|
||||||
std::string const &lastName = parent->dump(lineNo);
|
std::string const &lastName = parent->dump(lineNo);
|
||||||
|
style_Set(stderr, STYLE_CYAN, false);
|
||||||
fputs(" -> ", stderr);
|
fputs(" -> ", stderr);
|
||||||
|
style_Set(stderr, STYLE_CYAN, true);
|
||||||
fputs(lastName.c_str(), stderr);
|
fputs(lastName.c_str(), stderr);
|
||||||
for (uint32_t iter : iters()) {
|
for (uint32_t iter : iters()) {
|
||||||
fprintf(stderr, "::REPT~%" PRIu32, iter);
|
fprintf(stderr, "::REPT~%" PRIu32, iter);
|
||||||
}
|
}
|
||||||
|
style_Set(stderr, STYLE_CYAN, false);
|
||||||
fprintf(stderr, "(%" PRIu32 ")", curLineNo);
|
fprintf(stderr, "(%" PRIu32 ")", curLineNo);
|
||||||
|
style_Reset(stderr);
|
||||||
return lastName;
|
return lastName;
|
||||||
} else {
|
} else {
|
||||||
if (parent) {
|
if (parent) {
|
||||||
parent->dump(lineNo);
|
parent->dump(lineNo);
|
||||||
|
style_Set(stderr, STYLE_CYAN, false);
|
||||||
fputs(" -> ", stderr);
|
fputs(" -> ", stderr);
|
||||||
}
|
}
|
||||||
std::string const &nodeName = name();
|
std::string const &nodeName = name();
|
||||||
|
style_Set(stderr, STYLE_CYAN, true);
|
||||||
fputs(nodeName.c_str(), stderr);
|
fputs(nodeName.c_str(), stderr);
|
||||||
|
style_Set(stderr, STYLE_CYAN, false);
|
||||||
fprintf(stderr, "(%" PRIu32 ")", curLineNo);
|
fprintf(stderr, "(%" PRIu32 ")", curLineNo);
|
||||||
|
style_Reset(stderr);
|
||||||
return nodeName;
|
return nodeName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -388,6 +402,17 @@ int main(int argc, char *argv[]) {
|
|||||||
// implies tiny mode
|
// implies tiny mode
|
||||||
options.is32kMode = true;
|
options.is32kMode = true;
|
||||||
break;
|
break;
|
||||||
|
case 0: // Long-only options
|
||||||
|
if (longOpt == 'c') {
|
||||||
|
if (!strcasecmp(musl_optarg, "always")) {
|
||||||
|
style_Enable(true);
|
||||||
|
} else if (!strcasecmp(musl_optarg, "never")) {
|
||||||
|
style_Enable(false);
|
||||||
|
} else if (strcasecmp(musl_optarg, "auto")) {
|
||||||
|
fatal("Invalid argument for option '--color'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
usage.printAndExit(1); // LCOV_EXCL_LINE
|
usage.printAndExit(1); // LCOV_EXCL_LINE
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
#include "style.hpp"
|
||||||
|
|
||||||
#include "link/main.hpp"
|
#include "link/main.hpp"
|
||||||
|
|
||||||
// clang-format off: nested initializers
|
// clang-format off: nested initializers
|
||||||
@@ -33,24 +35,29 @@ static void printDiag(
|
|||||||
char const *fmt,
|
char const *fmt,
|
||||||
va_list args,
|
va_list args,
|
||||||
char const *type,
|
char const *type,
|
||||||
|
StyleColor color,
|
||||||
char const *flagfmt,
|
char const *flagfmt,
|
||||||
char const *flag
|
char const *flag
|
||||||
) {
|
) {
|
||||||
|
style_Set(stderr, color, true);
|
||||||
fprintf(stderr, "%s: ", type);
|
fprintf(stderr, "%s: ", type);
|
||||||
if (src) {
|
if (src) {
|
||||||
src->dump(lineNo);
|
src->dump(lineNo);
|
||||||
fputs(": ", stderr);
|
fputs(": ", stderr);
|
||||||
}
|
}
|
||||||
if (flagfmt) {
|
if (flagfmt) {
|
||||||
|
style_Set(stderr, color, true);
|
||||||
fprintf(stderr, flagfmt, flag);
|
fprintf(stderr, flagfmt, flag);
|
||||||
fputs("\n ", stderr);
|
fputs("\n ", stderr);
|
||||||
}
|
}
|
||||||
|
style_Reset(stderr);
|
||||||
vfprintf(stderr, fmt, args);
|
vfprintf(stderr, fmt, args);
|
||||||
putc('\n', stderr);
|
putc('\n', stderr);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[noreturn]]
|
[[noreturn]]
|
||||||
static void abortLinking(char const *verb) {
|
static void abortLinking(char const *verb) {
|
||||||
|
style_Set(stderr, STYLE_RED, true);
|
||||||
fprintf(
|
fprintf(
|
||||||
stderr,
|
stderr,
|
||||||
"Linking %s with %" PRIu64 " error%s\n",
|
"Linking %s with %" PRIu64 " error%s\n",
|
||||||
@@ -58,27 +65,28 @@ static void abortLinking(char const *verb) {
|
|||||||
warnings.nbErrors,
|
warnings.nbErrors,
|
||||||
warnings.nbErrors == 1 ? "" : "s"
|
warnings.nbErrors == 1 ? "" : "s"
|
||||||
);
|
);
|
||||||
|
style_Reset(stderr);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void warning(FileStackNode const *src, uint32_t lineNo, char const *fmt, ...) {
|
void warning(FileStackNode const *src, uint32_t lineNo, char const *fmt, ...) {
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
printDiag(src, lineNo, fmt, args, "warning", nullptr, 0);
|
printDiag(src, lineNo, fmt, args, "warning", STYLE_YELLOW, nullptr, nullptr);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
void warning(char const *fmt, ...) {
|
void warning(char const *fmt, ...) {
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
printDiag(nullptr, 0, fmt, args, "warning", nullptr, 0);
|
printDiag(nullptr, 0, fmt, args, "warning", STYLE_YELLOW, nullptr, nullptr);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
void error(FileStackNode const *src, uint32_t lineNo, char const *fmt, ...) {
|
void error(FileStackNode const *src, uint32_t lineNo, char const *fmt, ...) {
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
printDiag(src, lineNo, fmt, args, "error", nullptr, 0);
|
printDiag(src, lineNo, fmt, args, "error", STYLE_RED, nullptr, nullptr);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
warnings.incrementErrors();
|
warnings.incrementErrors();
|
||||||
@@ -87,7 +95,7 @@ void error(FileStackNode const *src, uint32_t lineNo, char const *fmt, ...) {
|
|||||||
void error(char const *fmt, ...) {
|
void error(char const *fmt, ...) {
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
printDiag(nullptr, 0, fmt, args, "error", nullptr, 0);
|
printDiag(nullptr, 0, fmt, args, "error", STYLE_RED, nullptr, nullptr);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
warnings.incrementErrors();
|
warnings.incrementErrors();
|
||||||
@@ -95,7 +103,9 @@ void error(char const *fmt, ...) {
|
|||||||
|
|
||||||
void errorNoDump(char const *fmt, ...) {
|
void errorNoDump(char const *fmt, ...) {
|
||||||
va_list args;
|
va_list args;
|
||||||
|
style_Set(stderr, STYLE_RED, true);
|
||||||
fputs("error: ", stderr);
|
fputs("error: ", stderr);
|
||||||
|
style_Reset(stderr);
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
vfprintf(stderr, fmt, args);
|
vfprintf(stderr, fmt, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
@@ -104,7 +114,13 @@ void errorNoDump(char const *fmt, ...) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void scriptError(char const *name, uint32_t lineNo, char const *fmt, va_list args) {
|
void scriptError(char const *name, uint32_t lineNo, char const *fmt, va_list args) {
|
||||||
fprintf(stderr, "error: %s(%" PRIu32 "): ", name, lineNo);
|
style_Set(stderr, STYLE_RED, true);
|
||||||
|
fputs("error: ", stderr);
|
||||||
|
style_Set(stderr, STYLE_CYAN, true);
|
||||||
|
fputs(name, stderr);
|
||||||
|
style_Set(stderr, STYLE_CYAN, false);
|
||||||
|
fprintf(stderr, "(%" PRIu32 "): ", lineNo);
|
||||||
|
style_Reset(stderr);
|
||||||
vfprintf(stderr, fmt, args);
|
vfprintf(stderr, fmt, args);
|
||||||
putc('\n', stderr);
|
putc('\n', stderr);
|
||||||
|
|
||||||
@@ -115,7 +131,7 @@ void scriptError(char const *name, uint32_t lineNo, char const *fmt, va_list arg
|
|||||||
void fatal(FileStackNode const *src, uint32_t lineNo, char const *fmt, ...) {
|
void fatal(FileStackNode const *src, uint32_t lineNo, char const *fmt, ...) {
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
printDiag(src, lineNo, fmt, args, "FATAL", nullptr, 0);
|
printDiag(src, lineNo, fmt, args, "FATAL", STYLE_RED, nullptr, nullptr);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
warnings.incrementErrors();
|
warnings.incrementErrors();
|
||||||
@@ -126,7 +142,7 @@ void fatal(FileStackNode const *src, uint32_t lineNo, char const *fmt, ...) {
|
|||||||
void fatal(char const *fmt, ...) {
|
void fatal(char const *fmt, ...) {
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
printDiag(nullptr, 0, fmt, args, "FATAL", nullptr, 0);
|
printDiag(nullptr, 0, fmt, args, "FATAL", STYLE_RED, nullptr, nullptr);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
warnings.incrementErrors();
|
warnings.incrementErrors();
|
||||||
@@ -150,11 +166,11 @@ void warning(FileStackNode const *src, uint32_t lineNo, WarningID id, char const
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case WarningBehavior::ENABLED:
|
case WarningBehavior::ENABLED:
|
||||||
printDiag(src, lineNo, fmt, args, "warning", "[-W%s]", flag);
|
printDiag(src, lineNo, fmt, args, "warning", STYLE_RED, "[-W%s]", flag);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WarningBehavior::ERROR:
|
case WarningBehavior::ERROR:
|
||||||
printDiag(src, lineNo, fmt, args, "error", "[-Werror=%s]", flag);
|
printDiag(src, lineNo, fmt, args, "error", STYLE_YELLOW, "[-Werror=%s]", flag);
|
||||||
|
|
||||||
warnings.incrementErrors();
|
warnings.incrementErrors();
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ SectionTypeInfo sectionTypeInfo[SECTTYPE_INVALID] = {
|
|||||||
.size = 0x2000, // Patched to 0x1000 if !isWRAM0Mode
|
.size = 0x2000, // Patched to 0x1000 if !isWRAM0Mode
|
||||||
.firstBank = 0,
|
.firstBank = 0,
|
||||||
.lastBank = 0,
|
.lastBank = 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.name = "VRAM"s,
|
.name = "VRAM"s,
|
||||||
.startAddr = 0x8000,
|
.startAddr = 0x8000,
|
||||||
@@ -28,42 +28,42 @@ SectionTypeInfo sectionTypeInfo[SECTTYPE_INVALID] = {
|
|||||||
.size = 0x4000,
|
.size = 0x4000,
|
||||||
.firstBank = 1,
|
.firstBank = 1,
|
||||||
.lastBank = 65535,
|
.lastBank = 65535,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.name = "ROM0"s,
|
.name = "ROM0"s,
|
||||||
.startAddr = 0x0000,
|
.startAddr = 0x0000,
|
||||||
.size = 0x8000, // Patched to 0x4000 if !is32kMode
|
.size = 0x8000, // Patched to 0x4000 if !is32kMode
|
||||||
.firstBank = 0,
|
.firstBank = 0,
|
||||||
.lastBank = 0,
|
.lastBank = 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.name = "HRAM"s,
|
.name = "HRAM"s,
|
||||||
.startAddr = 0xFF80,
|
.startAddr = 0xFF80,
|
||||||
.size = 0x007F,
|
.size = 0x007F,
|
||||||
.firstBank = 0,
|
.firstBank = 0,
|
||||||
.lastBank = 0,
|
.lastBank = 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.name = "WRAMX"s,
|
.name = "WRAMX"s,
|
||||||
.startAddr = 0xD000,
|
.startAddr = 0xD000,
|
||||||
.size = 0x1000,
|
.size = 0x1000,
|
||||||
.firstBank = 1,
|
.firstBank = 1,
|
||||||
.lastBank = 7,
|
.lastBank = 7,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.name = "SRAM"s,
|
.name = "SRAM"s,
|
||||||
.startAddr = 0xA000,
|
.startAddr = 0xA000,
|
||||||
.size = 0x2000,
|
.size = 0x2000,
|
||||||
.firstBank = 0,
|
.firstBank = 0,
|
||||||
.lastBank = 255,
|
.lastBank = 255,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.name = "OAM"s,
|
.name = "OAM"s,
|
||||||
.startAddr = 0xFE00,
|
.startAddr = 0xFE00,
|
||||||
.size = 0x00A0,
|
.size = 0x00A0,
|
||||||
.firstBank = 0,
|
.firstBank = 0,
|
||||||
.lastBank = 0,
|
.lastBank = 0,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
|
|||||||
98
src/style.cpp
Normal file
98
src/style.cpp
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
// This implementation was based on https://github.com/agauniyal/rang/
|
||||||
|
// and adapted for RGBDS.
|
||||||
|
|
||||||
|
#include "style.hpp"
|
||||||
|
|
||||||
|
#include <stdlib.h> // getenv
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "platform.hpp" // isatty
|
||||||
|
|
||||||
|
#if !STYLE_ANSI
|
||||||
|
// clang-format off: maintain `include` order
|
||||||
|
#define WIN32_LEAN_AND_MEAN // Include less from `windows.h`
|
||||||
|
#include <windows.h>
|
||||||
|
// clang-format on
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum Tribool { TRI_NO, TRI_YES, TRI_MAYBE };
|
||||||
|
|
||||||
|
#if !STYLE_ANSI
|
||||||
|
static const HANDLE outHandle = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
|
static const HANDLE errHandle = GetStdHandle(STD_ERROR_HANDLE);
|
||||||
|
|
||||||
|
static const WORD defaultAttrib = []() {
|
||||||
|
if (CONSOLE_SCREEN_BUFFER_INFO info; GetConsoleScreenBufferInfo(outHandle, &info)
|
||||||
|
|| GetConsoleScreenBufferInfo(errHandle, &info)) {
|
||||||
|
return info.wAttributes;
|
||||||
|
}
|
||||||
|
return static_cast<WORD>((STYLE_BLACK << 4) | (STYLE_GRAY | 8));
|
||||||
|
}();
|
||||||
|
|
||||||
|
static HANDLE getHandle(FILE *file) {
|
||||||
|
return file == stdout ? outHandle : file == stderr ? errHandle : INVALID_HANDLE_VALUE;
|
||||||
|
}
|
||||||
|
#endif // !STYLE_ANSI
|
||||||
|
|
||||||
|
static Tribool forceStyle = []() {
|
||||||
|
if (char const *forceColor = getenv("FORCE_COLOR");
|
||||||
|
forceColor && strcmp(forceColor, "") && strcmp(forceColor, "0")) {
|
||||||
|
return TRI_YES;
|
||||||
|
}
|
||||||
|
if (char const *noColor = getenv("NO_COLOR");
|
||||||
|
noColor && strcmp(noColor, "") && strcmp(noColor, "0")) {
|
||||||
|
return TRI_NO;
|
||||||
|
}
|
||||||
|
return TRI_MAYBE;
|
||||||
|
}();
|
||||||
|
|
||||||
|
static bool isTerminal(FILE *file) {
|
||||||
|
static bool isOutTerminal = isatty(STDOUT_FILENO);
|
||||||
|
static bool isErrTerminal = isatty(STDERR_FILENO);
|
||||||
|
|
||||||
|
return (file == stdout && isOutTerminal) || (file == stderr && isErrTerminal);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool allowStyle(FILE *file) {
|
||||||
|
return forceStyle == TRI_YES || (forceStyle == TRI_MAYBE && isTerminal(file));
|
||||||
|
}
|
||||||
|
|
||||||
|
void style_Enable(bool enable) {
|
||||||
|
forceStyle = enable ? TRI_YES : TRI_NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
void style_Set(FILE *file, StyleColor color, bool bold) {
|
||||||
|
if (!allowStyle(file)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// LCOV_EXCL_START
|
||||||
|
#if STYLE_ANSI
|
||||||
|
fprintf(file, "\033[%dm", static_cast<int>(color) + (bold ? 90 : 30));
|
||||||
|
#else
|
||||||
|
if (HANDLE handle = getHandle(file); handle != INVALID_HANDLE_VALUE) {
|
||||||
|
fflush(file);
|
||||||
|
SetConsoleTextAttribute(handle, (defaultAttrib & ~0xF) | (color | (bold ? 8 : 0)));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
// LCOV_EXCL_STOP
|
||||||
|
}
|
||||||
|
|
||||||
|
void style_Reset(FILE *file) {
|
||||||
|
if (!allowStyle(file)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// LCOV_EXCL_START
|
||||||
|
#if STYLE_ANSI
|
||||||
|
fputs("\033[m", file);
|
||||||
|
#else
|
||||||
|
if (HANDLE handle = getHandle(file); handle != INVALID_HANDLE_VALUE) {
|
||||||
|
fflush(file);
|
||||||
|
SetConsoleTextAttribute(handle, defaultAttrib);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
// LCOV_EXCL_STOP
|
||||||
|
}
|
||||||
@@ -2,17 +2,111 @@
|
|||||||
|
|
||||||
#include "usage.hpp"
|
#include "usage.hpp"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "helpers.hpp"
|
||||||
|
#include "style.hpp"
|
||||||
|
|
||||||
|
static constexpr size_t maxLineLen = 79;
|
||||||
|
|
||||||
|
// LCOV_EXCL_START
|
||||||
|
|
||||||
void Usage::printAndExit(int code) const {
|
void Usage::printAndExit(int code) const {
|
||||||
fputs(usage, stderr);
|
FILE *file = code ? stderr : stdout;
|
||||||
|
|
||||||
|
// Print "Usage: <program name>"
|
||||||
|
style_Set(file, STYLE_GREEN, true);
|
||||||
|
fputs("Usage: ", file);
|
||||||
|
style_Set(file, STYLE_CYAN, true);
|
||||||
|
fputs(name.c_str(), file);
|
||||||
|
size_t padFlags = literal_strlen("Usage: ") + name.length();
|
||||||
|
|
||||||
|
// Print the flags after the program name, indented to the same level
|
||||||
|
style_Set(file, STYLE_CYAN, false);
|
||||||
|
size_t flagsWidth = padFlags;
|
||||||
|
for (std::string const &flag : flags) {
|
||||||
|
if (flagsWidth + 1 + flag.length() > maxLineLen) {
|
||||||
|
fprintf(file, "\n%*c", static_cast<int>(padFlags), ' ');
|
||||||
|
flagsWidth = padFlags;
|
||||||
|
}
|
||||||
|
fprintf(file, " %s", flag.c_str());
|
||||||
|
flagsWidth += 1 + flag.length();
|
||||||
|
}
|
||||||
|
fputs("\n\n", file);
|
||||||
|
|
||||||
|
// Measure the options' flags
|
||||||
|
size_t padOpts = 0;
|
||||||
|
for (auto const &item : options) {
|
||||||
|
size_t pad = 0;
|
||||||
|
for (size_t i = 0; i < item.first.size(); ++i) {
|
||||||
|
if (i > 0) {
|
||||||
|
pad += literal_strlen(", ");
|
||||||
|
}
|
||||||
|
pad += item.first[i].length();
|
||||||
|
}
|
||||||
|
if (pad > padOpts) {
|
||||||
|
padOpts = pad;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int optIndent = static_cast<int>(literal_strlen(" ") + padOpts);
|
||||||
|
|
||||||
|
// Print the options
|
||||||
|
if (!options.empty()) {
|
||||||
|
style_Set(file, STYLE_GREEN, true);
|
||||||
|
fputs("Useful options:\n", file);
|
||||||
|
}
|
||||||
|
for (auto const &[opts, description] : options) {
|
||||||
|
fputs(" ", file);
|
||||||
|
|
||||||
|
// Print the comma-separated options
|
||||||
|
size_t optWidth = 0;
|
||||||
|
for (size_t i = 0; i < opts.size(); ++i) {
|
||||||
|
if (i > 0) {
|
||||||
|
style_Reset(file);
|
||||||
|
fputs(", ", file);
|
||||||
|
optWidth += literal_strlen(", ");
|
||||||
|
}
|
||||||
|
style_Set(file, STYLE_CYAN, false);
|
||||||
|
fputs(opts[i].c_str(), file);
|
||||||
|
optWidth += opts[i].length();
|
||||||
|
}
|
||||||
|
if (optWidth < padOpts) {
|
||||||
|
fprintf(file, "%*c", static_cast<int>(padOpts - optWidth), ' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print the description lines, indented to the same level
|
||||||
|
for (size_t i = 0; i < description.size(); ++i) {
|
||||||
|
style_Reset(file);
|
||||||
|
if (i > 0) {
|
||||||
|
fprintf(file, "\n%*c", optIndent, ' ');
|
||||||
|
}
|
||||||
|
fprintf(file, " %s", description[i].c_str());
|
||||||
|
}
|
||||||
|
putc('\n', file);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print the link for further help information
|
||||||
|
style_Reset(file);
|
||||||
|
fputs("\nFor more help, use `", file);
|
||||||
|
style_Set(file, STYLE_CYAN, true);
|
||||||
|
fprintf(file, "man %s", name.c_str());
|
||||||
|
style_Reset(file);
|
||||||
|
fputs("' or go to ", file);
|
||||||
|
style_Set(file, STYLE_BLUE, true);
|
||||||
|
fputs("https://rgbds.gbdev.io/docs/", file);
|
||||||
|
style_Reset(file);
|
||||||
|
putc('\n', file);
|
||||||
|
|
||||||
exit(code);
|
exit(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Usage::printAndExit(char const *fmt, ...) const {
|
void Usage::printAndExit(char const *fmt, ...) const {
|
||||||
va_list args;
|
va_list args;
|
||||||
|
style_Set(stderr, STYLE_RED, true);
|
||||||
fputs("FATAL: ", stderr);
|
fputs("FATAL: ", stderr);
|
||||||
|
style_Reset(stderr);
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
vfprintf(stderr, fmt, args);
|
vfprintf(stderr, fmt, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
@@ -20,3 +114,5 @@ void Usage::printAndExit(char const *fmt, ...) const {
|
|||||||
|
|
||||||
printAndExit(1);
|
printAndExit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LCOV_EXCL_STOP
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
#include "verbosity.hpp"
|
#include "verbosity.hpp"
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
@@ -8,16 +10,18 @@
|
|||||||
|
|
||||||
static Verbosity verbosity = VERB_NONE;
|
static Verbosity verbosity = VERB_NONE;
|
||||||
|
|
||||||
|
bool checkVerbosity(Verbosity level) {
|
||||||
|
return verbosity >= level;
|
||||||
|
}
|
||||||
|
|
||||||
|
// LCOV_EXCL_START
|
||||||
|
|
||||||
void incrementVerbosity() {
|
void incrementVerbosity() {
|
||||||
if (verbosity < VERB_VVVVVV) {
|
if (verbosity < VERB_VVVVVV) {
|
||||||
verbosity = static_cast<Verbosity>(verbosity + 1);
|
verbosity = static_cast<Verbosity>(verbosity + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool checkVerbosity(Verbosity level) {
|
|
||||||
return verbosity >= level;
|
|
||||||
}
|
|
||||||
|
|
||||||
void printVVVVVVerbosity() {
|
void printVVVVVVerbosity() {
|
||||||
if (!checkVerbosity(VERB_VVVVVV)) {
|
if (!checkVerbosity(VERB_VVVVVV)) {
|
||||||
return;
|
return;
|
||||||
@@ -67,3 +71,5 @@ void printVVVVVVerbosity() {
|
|||||||
}
|
}
|
||||||
putc('\n', stderr);
|
putc('\n', stderr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LCOV_EXCL_STOP
|
||||||
|
|||||||
Reference in New Issue
Block a user