Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/mmdata.c
Original file line number Diff line number Diff line change
Expand Up @@ -731,7 +731,7 @@ void outOfMemory(const char *msg) {
"To solve this problem, remove some unnecessary statements or file\n"
"inclusions to reduce the size of your input source.\n"
"Monitor memory periodically with SHOW MEMORY.\n";
fatalErrorExitAt(__FILE__, __LINE__, format, msg);
fatalErrorExit(format, msg);
}


Expand Down Expand Up @@ -3068,11 +3068,11 @@ long **alloc2DMatrix(size_t xsize, size_t ysize)
long i;
matrix = malloc(xsize * sizeof(long *));
if (matrix == NULL)
fatalErrorExitAt(__FILE__, __LINE__, "?FATAL ERROR 1376 Out of memory\n");
fatalErrorExit("?FATAL ERROR 1376 Out of memory\n");
for (i = 0; i < (long)xsize; i++) {
matrix[i] = malloc(ysize * sizeof(long));
if (matrix[i] == NULL)
fatalErrorExitAt(__FILE__, __LINE__, "?FATAL ERROR 1377 Out of memory\n");
fatalErrorExit("?FATAL ERROR 1377 Out of memory\n");
}
return matrix;
} /* alloc2DMatrix */
Expand Down
105 changes: 85 additions & 20 deletions src/mmfatl.c
Original file line number Diff line number Diff line change
Expand Up @@ -450,23 +450,87 @@ void fatalErrorPrintAndExit(void) {
#endif // TEST_ENABLE
}

void fatalErrorExitAt(char const* file, unsigned line,
char const* msgWithPlaceholders, ...) {
void fatalErrorExit(char const* msgWithPlaceholders, ...) {
fatalErrorInit();

if (msgWithPlaceholders) {
struct ParserState* state = getParserStateInstance();

state->format = msgWithPlaceholders;
va_start(state->args, msgWithPlaceholders);
parse(state);
va_end(state->args);
}

fatalErrorPrintAndExit();
}

#if 0 /* fatalErrorExitAt */

/*
* This extension to the fatal error interface allows you to pinpoint a source
* code line as the origin of a fatal error, based on the __FILE__ and
* __LINE__ macros, and add it as a location info to the error message.
* While tempting because fairly easy to invoke in your program code, it does
* not come without problems:
* (1) the error position is not stable across program versions;
* (2) it is not a descriptive identifier that you can search your program for,
* or cross reference in documentation;
* (3) Metamath has already an error location system based on numbers #nn in
* place, that was sufficient so far.
*
* Because of these limitations, and because Metamath code as of January 2023
* does not need this extension, it is disabled. The knowledge is available,
* though. On request it can be activated and put to use fairly easily.
*
* The call for a fatal error report with error location is
*
* fatalErrorExitAt(
* createErrorLocation(__FILE__, __LINE_),
* "We are %s here, in need %u help, unable %u continue",
* "screwed", 4, 2);
*/

struct ErrorLocation {
char const* file;
unsigned line;
};

/*
* result is stable only the next call to this function
*/
struct ErrorLocation const* createErrorLocation(char const* file,
unsigned line) {
static struct ErrorLocation loc;
loc.file = file;
loc.line = line;
return &loc;
}

bool fatalErrorPos(struct ErrorLocation const* loc) {
// a format for the error location, only showing relevant data
char const* format = NULL;
if (file && *file)
bool result = true;
if (loc)
{
if (line > 0)
format = "At %s:%u\n";
else
format = "In file %s:\n";
if (loc->file && *(loc->file)) {
if (loc->line > 0)
format = "At %s:%u\n";
else
format = "In file %s:\n";
}
else if (loc->line > 0)
format = "%sIn line %u:\n";
result = fatalErrorPush(format, loc->file, loc->line);
}
else if (line > 0)
format = "%sIn line %u:\n";
return result;
}

if (fatalErrorPush(format, file, line) && msgWithPlaceholders) {
void fatalErrorExitAt(struct ErrorLocation const* loc,
char const* msgWithPlaceholders, ...) {
fatalErrorInit();

if (fatalErrorPos(loc) && msgWithPlaceholders) {
struct ParserState* state = getParserStateInstance();

state->format = msgWithPlaceholders;
Expand All @@ -478,6 +542,7 @@ void fatalErrorExitAt(char const* file, unsigned line,
fatalErrorPrintAndExit();
}

#endif /* fatalErrorExitAt */

//================= Regression tests =====================

Expand Down Expand Up @@ -859,21 +924,21 @@ static bool test_fatalErrorPrintAndExit(void) {
return true;
}

static bool test_fatalErrorExitAt() {
// note that in test mode the fatalErrorExitAt neither prints to stderr
static bool test_fatalErrorExit() {
// note that in test mode the fatalErrorExit neither prints to stderr
// nor exits. The message is still in the buffer.

fatalErrorExitAt("test.c", 1000, "%s failed!", "program");
ASSERT(strcmp(buffer.text, "At test.c:1000\nprogram failed!\n") == 0);
fatalErrorExit("%s failed!", "program");
ASSERT(strcmp(buffer.text, "program failed!\n") == 0);
// ignoring line
fatalErrorExitAt("x.c", 0, "test %u failed!", 5);
ASSERT(strcmp(buffer.text, "In file x.c:\ntest 5 failed!\n") == 0);
fatalErrorExit("test %u failed!", 5);
ASSERT(strcmp(buffer.text, "test 5 failed!\n") == 0);
// ignoring file
fatalErrorExitAt(NULL, 123, "%s", "need help!\n");
ASSERT(strcmp(buffer.text, "In line 123:\nneed help!\n") == 0);
fatalErrorExit("%s", "need help!\n");
ASSERT(strcmp(buffer.text, "need help!\n") == 0);

// ignoring error location
fatalErrorExitAt(NULL, 0, "take lessons, you fool!");
fatalErrorExit("take lessons, you fool!");
ASSERT(strcmp(buffer.text, "take lessons, you fool!\n") == 0);

return true;
Expand All @@ -892,7 +957,7 @@ void test_mmfatl(void) {
RUN_TEST(test_handleSubstitution);
RUN_TEST(test_fatalErrorPush);
RUN_TEST(test_fatalErrorPrintAndExit);
RUN_TEST(test_fatalErrorExitAt);
RUN_TEST(test_fatalErrorExit);
}

#endif // TEST_ENABLE
11 changes: 2 additions & 9 deletions src/mmfatl.h
Original file line number Diff line number Diff line change
Expand Up @@ -279,12 +279,6 @@ extern void fatalErrorPrintAndExit(void);
* a sequence of \ref fatalErrorInit, multiple \ref fatalErrorPush and finally
* \ref fatalErrorPrintAndExit instead of this function.
*
* \param[in] file [null] filename of code responsible for calling this
* function, suitable for macro __FILE__. Part of an error location.
* Ignored in case of NULL.
* \param[in] line [unsigned] if greater 0, interpreted as a line number, where
* a call to this function is initiated, suitable for macro __LINE__. Part
* of an error location.
* \param[in] msgWithPlaceholders [null] the error message to display. This
* message may include placeholders in printf style, in which case it must be
* followed by more parameters, corresponding to the values replacing
Expand All @@ -293,12 +287,11 @@ extern void fatalErrorPrintAndExit(void);
* The details of this process is explained in \ref fatalErrorPush. Ignored
* if NULL.
* \post the program exits with EXIT_FAILURE return code, after writing the
* error location and message to stderr.
* error message to stderr.
* \invariant the memory state of the rest of the program is not changed (in
* case there is still a function in the atexit queue).
*/
extern void fatalErrorExitAt(char const* file, unsigned line,
char const* msgWithPlaceholders, ...);
extern void fatalErrorExit(char const* msgWithPlaceholders, ...);

#ifdef TEST_ENABLE

Expand Down