From 34b2543c8b4f044f9c5857f6ffb1f3c40f012a1e Mon Sep 17 00:00:00 2001 From: Rangi <35663410+Rangi42@users.noreply.github.com> Date: Thu, 7 Dec 2023 05:42:47 -0500 Subject: [PATCH] Implement `-X/--max-errors` for RGBASM (#1262) Co-authored-by: Eldred Habert --- contrib/bash_compl/_rgbasm.bash | 1 + contrib/zsh_compl/_rgbasm | 1 + include/asm/warning.hpp | 2 +- man/rgbasm.1 | 8 ++++++++ src/asm/main.cpp | 27 +++++++++++++++++++++++---- src/asm/warning.cpp | 6 ++++++ test/asm/max-errors.asm | 3 +++ test/asm/max-errors.err | 3 +++ test/asm/max-errors.flags | 1 + 9 files changed, 47 insertions(+), 5 deletions(-) create mode 100644 test/asm/max-errors.asm create mode 100644 test/asm/max-errors.err create mode 100644 test/asm/max-errors.flags diff --git a/contrib/bash_compl/_rgbasm.bash b/contrib/bash_compl/_rgbasm.bash index 9da15c95..95bde528 100755 --- a/contrib/bash_compl/_rgbasm.bash +++ b/contrib/bash_compl/_rgbasm.bash @@ -43,6 +43,7 @@ _rgbasm_completions() { [Q]="q-precision:unk" [r]="recursion-depth:unk" [W]="warning:warning" + [X]="max-errors:unk" ) # Parse command-line up to current word local opt_ena=true diff --git a/contrib/zsh_compl/_rgbasm b/contrib/zsh_compl/_rgbasm index 8882f288..8fa4759f 100644 --- a/contrib/zsh_compl/_rgbasm +++ b/contrib/zsh_compl/_rgbasm @@ -60,6 +60,7 @@ local args=( '(-Q --q-precision)'{-Q,--q-precision}'+[Set fixed-point precision]:precision:' '(-r --recursion-depth)'{-r,--recursion-depth}'+[Set maximum recursion depth]:depth:' '(-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'" ) diff --git a/include/asm/warning.hpp b/include/asm/warning.hpp index 3f3525bb..d091ef87 100644 --- a/include/asm/warning.hpp +++ b/include/asm/warning.hpp @@ -5,7 +5,7 @@ #include "helpers.hpp" -extern unsigned int nbErrors; +extern unsigned int nbErrors, maxErrors; enum WarningState { WARNING_DEFAULT, diff --git a/man/rgbasm.1 b/man/rgbasm.1 index 4cac6e81..236134f4 100644 --- a/man/rgbasm.1 +++ b/man/rgbasm.1 @@ -24,6 +24,7 @@ .Op Fl Q Ar fix_precision .Op Fl r Ar recursion_depth .Op Fl W Ar warning +.Op Fl X Ar max_errors .Ar asmfile .Sh DESCRIPTION The @@ -176,6 +177,13 @@ See the section for a list of warnings. .It Fl w Disable all warning output, even when turned into errors. +.It Fl X Ar max_errors , Fl \-max-errors Ar max_errors +If more than this number of errors (not warnings) occur, then abort the assembly process; +.Fl X 0 +disables this behavior. +The default is 100 if +.Nm +is printing errors to a terminal, and 0 otherwise. .El .Sh DIAGNOSTICS Warnings are diagnostic messages that indicate possibly erroneous behavior that does not necessarily compromise the assembling process. diff --git a/src/asm/main.cpp b/src/asm/main.cpp index 643a882f..3901a7b8 100644 --- a/src/asm/main.cpp +++ b/src/asm/main.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -83,7 +84,7 @@ static char *make_escape(char const *str) } // Short options -static const char *optstring = "b:D:Eg:Hhi:I:LlM:o:P:p:Q:r:VvW:w"; +static const char *optstring = "b:D:Eg:Hhi:I:LlM:o:P:p:Q:r:VvW:wX:"; // Variables for the long-only options static int depType; // Variants of `-M` @@ -110,6 +111,7 @@ static struct option const longopts[] = { { "MG", no_argument, &depType, 'G' }, { "MP", no_argument, &depType, 'P' }, { "MT", required_argument, &depType, 'T' }, + { "warning", required_argument, NULL, 'W' }, { "MQ", required_argument, &depType, 'Q' }, { "output", required_argument, NULL, 'o' }, { "preinclude", required_argument, NULL, 'P' }, @@ -119,6 +121,7 @@ static struct option const longopts[] = { { "version", no_argument, NULL, 'V' }, { "verbose", no_argument, NULL, 'v' }, { "warning", required_argument, NULL, 'W' }, + { "max-errors", required_argument, NULL, 'X' }, { NULL, no_argument, NULL, 0 } }; @@ -128,7 +131,7 @@ static void printUsage(void) "Usage: rgbasm [-EHhLlVvw] [-b chars] [-D name[=value]] [-g chars] [-I path]\n" " [-M depend_file] [-MG] [-MP] [-MT target_file] [-MQ target_file]\n" " [-o out_file] [-P include_file] [-p pad_value] [-Q precision]\n" -" [-r depth] [-W warning] \n" +" [-r depth] [-W warning] [-X max_errors] \n" "Useful options:\n" " -E, --export-all export all labels\n" " -M, --dependfile set the output dependency file\n" @@ -171,6 +174,10 @@ int main(int argc, char *argv[]) char const *dependFileName = NULL; size_t targetFileNameLen = 0; + // Maximum of 100 errors only applies if rgbasm is printing errors to a terminal. + if (isatty(STDERR_FILENO)) + maxErrors = 100; + for (int ch; (ch = musl_getopt_long_only(argc, argv, optstring, longopts, NULL)) != -1;) { switch (ch) { char *endptr; @@ -316,6 +323,19 @@ int main(int argc, char *argv[]) warnings = false; break; + unsigned int maxValue; + case 'X': + maxValue = strtoul(musl_optarg, &endptr, 0); + + if (musl_optarg[0] == '\0' || *endptr != '\0') + errx("Invalid argument for option 'X'"); + + if (maxValue > UINT_MAX) + errx("Argument for option 'X' must be between 0 and %u", UINT_MAX); + + maxErrors = maxValue; + break; + // Long-only options case 0: switch (depType) { @@ -399,8 +419,7 @@ int main(int argc, char *argv[]) sect_CheckUnionClosed(); if (nbErrors != 0) - errx("Assembly aborted (%u error%s)!", nbErrors, - nbErrors == 1 ? "" : "s"); + errx("Assembly aborted (%u error%s)!", nbErrors, nbErrors == 1 ? "" : "s"); // If parse aborted due to missing an include, and `-MG` was given, exit normally if (failedOnMissingInclude) diff --git a/src/asm/warning.cpp b/src/asm/warning.cpp index 05aa1718..69b19181 100644 --- a/src/asm/warning.cpp +++ b/src/asm/warning.cpp @@ -16,6 +16,7 @@ #include "itertools.hpp" unsigned int nbErrors = 0; +unsigned int maxErrors = 0; static const enum WarningState defaultWarnings[ARRAY_SIZE(warningStates)] = { AT(WARNING_ASSERT) WARNING_ENABLED, @@ -343,7 +344,12 @@ void error(char const *fmt, ...) va_start(args, fmt); printDiag(fmt, args, "error: ", ":\n ", NULL); va_end(args); + + // This intentionally makes 0 act as "unlimited" (or at least "limited to sizeof(unsigned)") nbErrors++; + if (nbErrors == maxErrors) + errx("The maximum of %u error%s was reached (configure with \"-X/--max-errors\"); assembly aborted!", + maxErrors, maxErrors == 1 ? "" : "s"); } [[noreturn]] void fatalerror(char const *fmt, ...) diff --git a/test/asm/max-errors.asm b/test/asm/max-errors.asm new file mode 100644 index 00000000..032259ab --- /dev/null +++ b/test/asm/max-errors.asm @@ -0,0 +1,3 @@ +section "s", rom0 +db 42 +println @ ; causes an error before println occurs diff --git a/test/asm/max-errors.err b/test/asm/max-errors.err new file mode 100644 index 00000000..de22fb6e --- /dev/null +++ b/test/asm/max-errors.err @@ -0,0 +1,3 @@ +error: max-errors.asm(3): + Expected constant expression: PC is not constant at assembly time +error: The maximum of 1 error was reached (configure with "-X/--max-errors"); assembly aborted! diff --git a/test/asm/max-errors.flags b/test/asm/max-errors.flags new file mode 100644 index 00000000..c8401c0e --- /dev/null +++ b/test/asm/max-errors.flags @@ -0,0 +1 @@ +-Weverything -X 1