Support for UTF-8

Not working perfectly yet however..

Also enable "Flipping" the message.
This commit is contained in:
Joakim Söderberg 2015-01-16 11:40:44 +01:00
parent b5af5c0716
commit 1fa63652bf
3 changed files with 92 additions and 36 deletions

View File

@ -158,8 +158,8 @@ json_t *load_json(const char *text) {
if (root) { if (root) {
return root; return root;
} else { } else {
char *detailed = json_error_get_detailed(&error, text, JSON_ERROR_COLOR | JSON_ERROR_ARROW_LEN(2)); char *detailed = json_error_get_detailed(&error, text,
//fprintf(stderr, "json error on line %d: %s\n", error.line, error.text); JSON_ERROR_COLOR | JSON_ERROR_ARROW_LEN(4));
fprintf(stderr, "Error:\n%s\n", detailed); fprintf(stderr, "Error:\n%s\n", detailed);
free(detailed); free(detailed);
return (json_t *)0; return (json_t *)0;

View File

@ -1,5 +1,6 @@
#include <string.h> #include <string.h>
#include "jansson_private.h" #include "jansson_private.h"
#include "utf.h"
void jsonp_error_init(json_error_t *error, const char *source) void jsonp_error_init(json_error_t *error, const char *source)
{ {
@ -62,6 +63,23 @@ void jsonp_error_vset(json_error_t *error, int line, int column,
error->text[JSON_ERROR_TEXT_LENGTH - 1] = '\0'; error->text[JSON_ERROR_TEXT_LENGTH - 1] = '\0';
} }
static size_t json_error_get_utf8_column(json_error_t *error, const char *src)
{
size_t utf8_len;
size_t srclen = strlen(src);
size_t i = 0;
const char *s = src;
const char *colend = src + error->column;
while (s < colend) {
if (!(s = utf8_iterate(s, colend - s, NULL)))
return error->column;
i++;
}
return i;
}
char *json_error_get_source_text(json_error_t *error, const char *src) char *json_error_get_source_text(json_error_t *error, const char *src)
{ {
const char *start; const char *start;
@ -69,6 +87,7 @@ char *json_error_get_source_text(json_error_t *error, const char *src)
size_t len; size_t len;
char *s; char *s;
// TODO: Pick start properly so we don't split a UTF-8 code point.
start = &src[(error->position - error->column)]; start = &src[(error->position - error->column)];
end = strchr(start, '\n'); end = strchr(start, '\n');
@ -76,13 +95,13 @@ char *json_error_get_source_text(json_error_t *error, const char *src)
end = src + strlen(src); end = src + strlen(src);
} }
len = (end - start); len = (end - start) + 2;
if (!(s = malloc(len))) { if (!(s = malloc(len))) {
return NULL; return NULL;
} }
if (snprintf(s, len - 1, "%*s", len, start) < 0) { if (snprintf(s, len - 1, "%.*s", (int)len - 2, start) < 0) {
free(s); free(s);
return NULL; return NULL;
} }
@ -90,28 +109,33 @@ char *json_error_get_source_text(json_error_t *error, const char *src)
return s; return s;
} }
char *json_error_get_arrow(json_error_t *error, const char *src, int length, size_t flags) char *json_error_get_arrow(json_error_t *error,
const char *src, size_t flags)
{ {
size_t msglen; size_t msglen;
int offset = 0; int offset = 0;
int ret = 0; int ret = 0;
char *msg; char *msg;
#define ARROWLEN 5 size_t utf8_len = 0;
const char padchars[] = "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"; size_t srclen = 0;
size_t utf8_column = 0;
int arrowlen = flags & JSON_ERROR_ARROW_MAXLEN;
#define DEFAULT_ARROWLEN 5
const char padchars[] = "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~";
if (strlen(src) < 2) { if (strlen(src) < 2) {
return strdup(""); return strdup("");
} }
if (length < 0) { if (arrowlen < 0) {
length = ARROWLEN; arrowlen = DEFAULT_ARROWLEN;
} }
if (length >= sizeof(padchars)) { if (arrowlen >= (int)sizeof(padchars)) {
length = sizeof(padchars); arrowlen = sizeof(padchars);
} }
msglen = (error->column + strlen(error->text) + ARROWLEN + 1) * 2; msglen = (error->column + strlen(error->text) + arrowlen + 1) * 2;
if (!(msg = malloc(msglen))) { if (!(msg = malloc(msglen))) {
return NULL; return NULL;
@ -128,19 +152,35 @@ char *json_error_get_arrow(json_error_t *error, const char *src, int length, siz
offset += ret; offset += ret;
#endif // _WIN32 #endif // _WIN32
// TODO: Make sure this works on Windows.
// TODO: How to check if console supports UTF-8? If not we want normal column value.
// Get the error column based on UTF-8 code points
// so that the arrow points in the correct position.
utf8_column = json_error_get_utf8_column(error, src);
if ((utf8_column + strlen(error->text) + (arrowlen + 1)) > JSON_ERROR_SOURCE_LENGTH) {
// Flip the arrow if the column is too far to the right.
if ((ret = snprintf(&msg[offset], msglen - offset,
"%*.*s^", arrowlen, arrowlen, padchars)) < 0) {
goto fail;
}
} else {
// Print the arrow. // Print the arrow.
if ((ret = snprintf(&msg[offset], msglen - offset, if ((ret = snprintf(&msg[offset], msglen - offset,
"%*s^%*.*s", "%*s^%*.*s",
error->column, "", (int)utf8_column, "",
length, length, padchars)) < 0) { arrowlen, arrowlen, padchars)) < 0) {
goto fail; goto fail;
} }
}
offset += ret; offset += ret;
#ifndef _WIN32 #ifndef _WIN32
if (flags & JSON_ERROR_COLOR) { if (flags & JSON_ERROR_COLOR) {
if (snprintf(&msg[offset], msglen - offset, "%s", "\x1b[0m\x1b[0m") < 0) { if (snprintf(&msg[offset], msglen - offset,
"%s", "\x1b[0m\x1b[0m") < 0) {
goto fail; goto fail;
} }
} }
@ -158,32 +198,47 @@ char *json_error_get_detailed(json_error_t *error, const char *src, size_t flags
char *arrow = NULL; char *arrow = NULL;
char *s = NULL; char *s = NULL;
size_t len; size_t len;
int arrow_length = flags & JSON_ERROR_ARROW_MAXLEN; size_t arrowlen = (flags & JSON_ERROR_ARROW_MAXLEN) + 1;
size_t textlen;
if (!arrow_length) size_t utf8_column;
arrow_length = -1; size_t srclen;
size_t total;
if (!(problem_src = json_error_get_source_text(error, src))) { if (!(problem_src = json_error_get_source_text(error, src))) {
return NULL; return NULL;
} }
if (!(arrow = json_error_get_arrow(error, src, arrow_length, flags))) { if (!(arrow = json_error_get_arrow(error, src, flags))) {
goto fail; goto fail;
} }
len = (strlen(problem_src) textlen = strlen(error->text);
+ strlen(arrow) srclen = strlen(problem_src);
+ strlen(error->text)) * 2; utf8_column = json_error_get_utf8_column(error, src);
total = (utf8_column + arrowlen + textlen + 3);
//problem_src[error->column]= '_';
len = (srclen + arrowlen + textlen) * 2;
if (!(s = malloc(len))) { if (!(s = malloc(len))) {
goto fail; goto fail;
} }
// TODO: If the error message goes outside of the console width, flip it! // If the error message goes outside of the console width, flip it!
if (total > JSON_ERROR_SOURCE_LENGTH) {
if (snprintf(s, len - 1, "%s\n%*s(%s) %s\n",
problem_src,
(int)(utf8_column - textlen - 3 - arrowlen), "",
error->text, arrow) < 0) {
goto fail;
}
} else {
if (snprintf(s, len - 1, "%s\n%s (%s)\n", if (snprintf(s, len - 1, "%s\n%s (%s)\n",
problem_src, arrow, error->text) < 0) { problem_src, arrow, error->text) < 0) {
goto fail; goto fail;
} }
}
free(problem_src); free(problem_src);
free(arrow); free(arrow);

View File

@ -127,8 +127,9 @@ typedef struct {
} json_error_t; } json_error_t;
#define JSON_ERROR_ARROW_MAXLEN 0x1f #define JSON_ERROR_ARROW_MAXLEN 0x1f
#define JSON_ERROR_ARROW_LEN(len) (len & JSON_ERROR_ARROW_MAXLEN) #define JSON_ERROR_ARROW_LEN(n) ((n) & JSON_ERROR_ARROW_MAXLEN)
#define JSON_ERROR_COLOR 0x20 #define JSON_ERROR_COLOR 0x20
#define JSON_ERROR_FLIP 0x40
char *json_error_get_detailed(json_error_t *error, const char *src, size_t flags); char *json_error_get_detailed(json_error_t *error, const char *src, size_t flags);