~mcf/cproc

Show source line contents in error messages v1 PROPOSED

Lassi Pulkkinen: 1
 Show source line contents in error messages

 1 files changed, 32 insertions(+), 0 deletions(-)
Export patchset (mbox)
How do I use this?

Copy & paste the following snippet into your terminal to import this patchset into git:

curl -s https://lists.sr.ht/~mcf/cproc/patches/52357/mbox | git am -3
Learn more about email & git

[RFC PATCH] Show source line contents in error messages Export this patch

---
Obtaining line contents in a very stupid way, but also probably the best
we can do given preprocessor shenanigans. Apart from the lack of special
handling for stdin / fake file names. _That said_,

$ gcc -xc -
x
<stdin>:1:1: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ at end of input
$ echo x > '<stdin>'
$ gcc -xc -
x
<stdin>:1:1: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ at end of input
    1 | x
      | ^

Oh, and NUL bytes throw off the line counter, because fgets.

It would make sense to have an option for disabling this. The equivalent
flags for GCC and Clang respectively are -fdiagnostics-plain-output and
-fno-caret-diagnostics. Neither is understood by the other, and both are
rather long.

 token.c | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/token.c b/token.c
index b67baa6..223f6a9 100644
--- a/token.c
+++ b/token.c
@@ -4,6 +4,7 @@
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "util.h"
#include "cc.h"

@@ -193,11 +194,42 @@ tokencheck(const struct token *t, enum tokenkind kind, const char *msg)
void error(const struct location *loc, const char *fmt, ...)
{
	va_list ap;
	FILE *file;
	static char line[1024];
	size_t len, i;
	int w;

	fprintf(stderr, "%s:%zu:%zu: error: ", loc->file, loc->line, loc->col);
	va_start(ap, fmt);
	vfprintf(stderr, fmt, ap);
	va_end(ap);
	putc('\n', stderr);

	file = fopen(loc->file, "r");
	if (!file)
		goto exit;
	for (i = 1;;) {
		if (!fgets(line, sizeof(line), file))
			goto exit;
		len = strlen(line);
		if (i == loc->line)
			break;
		if (line[len - 1] == '\n')
			++i;
	}
	if (line[len - 1] == '\n')
		line[len - 1] = '\0', --len;

	w = snprintf(NULL, 0, "%zu", loc->line);
	if (w < 4)
		w = 4;
	fprintf(stderr, " %*s |\n", w, "");
	fprintf(stderr, " %*zu |\t%s\n", w, loc->line, line);
	fprintf(stderr, " %*s |\t", w, "");
	for (i = 0; i <= len && i + 1 < loc->col; ++i)
		putc(isspace(line[i]) ? line[i] : ' ', stderr);
	fputs("^\n", stderr);

exit:
	exit(1);
}
-- 
2.45.0