From bf72cc408db5244881143619236aee20156f4ffd Mon Sep 17 00:00:00 2001
From: David Robillard <d@drobilla.net>
Date: Fri, 9 Jul 2021 20:23:41 -0400
Subject: Add SerdCaret

---
 src/byte_source.c | 27 +++++++++++++-------
 src/byte_source.h | 23 ++++++++---------
 src/caret.c       | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/caret.h       | 28 +++++++++++++++++++++
 src/reader.c      | 30 ++++++++++++----------
 src/serdi.c       | 12 ++++++---
 src/world.c       | 14 +++++++----
 7 files changed, 166 insertions(+), 43 deletions(-)
 create mode 100644 src/caret.c
 create mode 100644 src/caret.h

(limited to 'src')

diff --git a/src/byte_source.c b/src/byte_source.c
index 727c655f..0e6ae2be 100644
--- a/src/byte_source.c
+++ b/src/byte_source.c
@@ -16,6 +16,7 @@
 
 #include "byte_source.h"
 
+#include "caret.h"
 #include "system.h"
 
 #include "serd/serd.h"
@@ -52,11 +53,9 @@ serd_byte_source_open_source(SerdByteSource* const     source,
                              const SerdStreamErrorFunc error_func,
                              const SerdStreamCloseFunc close_func,
                              void* const               stream,
-                             const char* const         name,
+                             const SerdNode* const     name,
                              const size_t              page_size)
 {
-  const Cursor cur = {name, 1, 1};
-
   memset(source, '\0', sizeof(*source));
   source->read_func   = read_func;
   source->error_func  = error_func;
@@ -64,7 +63,10 @@ serd_byte_source_open_source(SerdByteSource* const     source,
   source->stream      = stream;
   source->page_size   = page_size;
   source->buf_size    = page_size;
-  source->cur         = cur;
+  source->name        = serd_node_copy(name);
+  source->caret.file  = source->name;
+  source->caret.line  = 1u;
+  source->caret.col   = 1u;
   source->from_stream = true;
 
   if (page_size > 1) {
@@ -93,13 +95,19 @@ serd_byte_source_prepare(SerdByteSource* const source)
 
 SerdStatus
 serd_byte_source_open_string(SerdByteSource* const source,
-                             const char* const     utf8)
+                             const char* const     utf8,
+                             const SerdNode* const name)
 {
-  const Cursor cur = {"(string)", 1, 1};
-
   memset(source, '\0', sizeof(*source));
-  source->cur      = cur;
-  source->read_buf = (const uint8_t*)utf8;
+
+  source->name =
+    name ? serd_node_copy(name) : serd_new_string(SERD_STRING("string"));
+
+  source->read_buf   = (const uint8_t*)utf8;
+  source->caret.file = source->name;
+  source->caret.line = 1u;
+  source->caret.col  = 1u;
+
   return SERD_SUCCESS;
 }
 
@@ -115,6 +123,7 @@ serd_byte_source_close(SerdByteSource* const source)
     serd_free_aligned(source->file_buf);
   }
 
+  serd_node_free(source->name);
   memset(source, '\0', sizeof(*source));
   return st;
 }
diff --git a/src/byte_source.h b/src/byte_source.h
index 69f92295..6469ba95 100644
--- a/src/byte_source.h
+++ b/src/byte_source.h
@@ -17,6 +17,8 @@
 #ifndef SERD_BYTE_SOURCE_H
 #define SERD_BYTE_SOURCE_H
 
+#include "caret.h"
+
 #include "serd/serd.h"
 
 #include <assert.h>
@@ -26,12 +28,6 @@
 
 typedef int (*SerdStreamCloseFunc)(void*);
 
-typedef struct {
-  const char* filename;
-  unsigned    line;
-  unsigned    col;
-} Cursor;
-
 typedef struct {
   SerdReadFunc        read_func;   ///< Read function (e.g. fread)
   SerdStreamErrorFunc error_func;  ///< Error function (e.g. ferror)
@@ -39,7 +35,8 @@ typedef struct {
   void*               stream;      ///< Stream (e.g. FILE)
   size_t              page_size;   ///< Number of bytes to read at a time
   size_t              buf_size;    ///< Number of bytes in file_buf
-  Cursor              cur;         ///< Cursor for error reporting
+  SerdNode*           name;        ///< Name of stream (referenced by cur)
+  SerdCaret           caret;       ///< Caret for error reporting
   uint8_t*            file_buf;    ///< Buffer iff reading pages from a file
   const uint8_t*      read_buf;    ///< Pointer to file_buf or read_byte
   size_t              read_head;   ///< Offset into read_buf
@@ -50,7 +47,9 @@ typedef struct {
 } SerdByteSource;
 
 SerdStatus
-serd_byte_source_open_string(SerdByteSource* source, const char* utf8);
+serd_byte_source_open_string(SerdByteSource* source,
+                             const char*     utf8,
+                             const SerdNode* name);
 
 SerdStatus
 serd_byte_source_open_source(SerdByteSource*     source,
@@ -58,7 +57,7 @@ serd_byte_source_open_source(SerdByteSource*     source,
                              SerdStreamErrorFunc error_func,
                              SerdStreamCloseFunc close_func,
                              void*               stream,
-                             const char*         name,
+                             const SerdNode*     name,
                              size_t              page_size);
 
 SerdStatus
@@ -85,11 +84,11 @@ serd_byte_source_advance(SerdByteSource* source)
 
   switch (serd_byte_source_peek(source)) {
   case '\n':
-    ++source->cur.line;
-    source->cur.col = 0;
+    ++source->caret.line;
+    source->caret.col = 0;
     break;
   default:
-    ++source->cur.col;
+    ++source->caret.col;
   }
 
   const bool was_eof = source->eof;
diff --git a/src/caret.c b/src/caret.c
new file mode 100644
index 00000000..2fe92f94
--- /dev/null
+++ b/src/caret.c
@@ -0,0 +1,75 @@
+/*
+  Copyright 2018-2020 David Robillard <d@drobilla.net>
+
+  Permission to use, copy, modify, and/or distribute this software for any
+  purpose with or without fee is hereby granted, provided that the above
+  copyright notice and this permission notice appear in all copies.
+
+  THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#include "caret.h"
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+SerdCaret*
+serd_caret_new(const SerdNode* name, unsigned line, unsigned col)
+{
+  SerdCaret* caret = (SerdCaret*)malloc(sizeof(SerdCaret));
+
+  caret->file = name;
+  caret->line = line;
+  caret->col  = col;
+  return caret;
+}
+
+SerdCaret*
+serd_caret_copy(const SerdCaret* caret)
+{
+  if (!caret) {
+    return NULL;
+  }
+
+  SerdCaret* copy = (SerdCaret*)malloc(sizeof(SerdCaret));
+  memcpy(copy, caret, sizeof(SerdCaret));
+  return copy;
+}
+
+void
+serd_caret_free(SerdCaret* caret)
+{
+  free(caret);
+}
+
+bool
+serd_caret_equals(const SerdCaret* l, const SerdCaret* r)
+{
+  return (l == r || (l && r && serd_node_equals(l->file, r->file) &&
+                     l->line == r->line && l->col == r->col));
+}
+
+const SerdNode*
+serd_caret_name(const SerdCaret* caret)
+{
+  return caret->file;
+}
+
+unsigned
+serd_caret_line(const SerdCaret* caret)
+{
+  return caret->line;
+}
+
+unsigned
+serd_caret_column(const SerdCaret* caret)
+{
+  return caret->col;
+}
diff --git a/src/caret.h b/src/caret.h
new file mode 100644
index 00000000..3add78a7
--- /dev/null
+++ b/src/caret.h
@@ -0,0 +1,28 @@
+/*
+  Copyright 2018-2020 David Robillard <d@drobilla.net>
+
+  Permission to use, copy, modify, and/or distribute this software for any
+  purpose with or without fee is hereby granted, provided that the above
+  copyright notice and this permission notice appear in all copies.
+
+  THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#ifndef SERD_CARET_H
+#define SERD_CARET_H
+
+#include "serd/serd.h"
+
+struct SerdCaretImpl {
+  const SerdNode* file;
+  unsigned        line;
+  unsigned        col;
+};
+
+#endif // SERD_CARET_H
diff --git a/src/reader.c b/src/reader.c
index 2cdf18c6..9957e55c 100644
--- a/src/reader.c
+++ b/src/reader.c
@@ -37,8 +37,7 @@ r_err(SerdReader* const reader, const SerdStatus st, const char* const fmt, ...)
 {
   va_list args;
   va_start(args, fmt);
-  const Cursor* const cur = &reader->source.cur;
-  const SerdError     e = {st, cur->filename, cur->line, cur->col, fmt, &args};
+  const SerdError e = {st, &reader->source.caret, fmt, &args};
   serd_world_error(reader->world, &e);
   va_end(args);
   return st;
@@ -246,7 +245,7 @@ serd_reader_start_stream(SerdReader* const         reader,
                          const SerdReadFunc        read_func,
                          const SerdStreamErrorFunc error_func,
                          void* const               stream,
-                         const char* const         name,
+                         const SerdNode* const     name,
                          const size_t              page_size)
 {
   return serd_byte_source_open_source(
@@ -267,20 +266,25 @@ serd_reader_start_file(SerdReader* reader, const char* uri, bool bulk)
     return SERD_ERR_UNKNOWN;
   }
 
-  return serd_byte_source_open_source(&reader->source,
-                                      bulk ? (SerdReadFunc)fread
-                                           : serd_file_read_byte,
-                                      (SerdStreamErrorFunc)ferror,
-                                      (SerdStreamCloseFunc)fclose,
-                                      fd,
-                                      uri,
-                                      bulk ? SERD_PAGE_SIZE : 1);
+  SerdNode* const  name = serd_new_uri(SERD_STRING(uri));
+  const SerdStatus st   = serd_byte_source_open_source(
+    &reader->source,
+    bulk ? (SerdReadFunc)fread : serd_file_read_byte,
+    (SerdStreamErrorFunc)ferror,
+    (SerdStreamCloseFunc)fclose,
+    fd,
+    name,
+    bulk ? SERD_PAGE_SIZE : 1u);
+  serd_node_free(name);
+  return st;
 }
 
 SerdStatus
-serd_reader_start_string(SerdReader* const reader, const char* const utf8)
+serd_reader_start_string(SerdReader* const     reader,
+                         const char* const     utf8,
+                         const SerdNode* const name)
 {
-  return serd_byte_source_open_string(&reader->source, utf8);
+  return serd_byte_source_open_string(&reader->source, utf8, name);
 }
 
 static SerdStatus
diff --git a/src/serdi.c b/src/serdi.c
index fcddac6c..a94051bc 100644
--- a/src/serdi.c
+++ b/src/serdi.c
@@ -283,15 +283,18 @@ main(int argc, char** argv)
   serd_writer_chop_blank_prefix(writer, chop_prefix);
   serd_reader_add_blank_prefix(reader, add_prefix);
 
-  SerdStatus st = SERD_SUCCESS;
+  SerdStatus st         = SERD_SUCCESS;
+  SerdNode*  input_name = NULL;
   if (from_string) {
-    st = serd_reader_start_string(reader, input);
+    input_name = serd_new_string(SERD_STRING("string"));
+    st         = serd_reader_start_string(reader, input, input_name);
   } else if (from_stdin) {
-    st = serd_reader_start_stream(reader,
+    input_name = serd_new_string(SERD_STRING("stdin"));
+    st         = serd_reader_start_stream(reader,
                                   serd_file_read_byte,
                                   (SerdStreamErrorFunc)ferror,
                                   stdin,
-                                  "(stdin)",
+                                  input_name,
                                   1);
   } else {
     st = serd_reader_start_file(reader, input, bulk_read);
@@ -305,6 +308,7 @@ main(int argc, char** argv)
   serd_reader_free(reader);
   serd_writer_finish(writer);
   serd_writer_free(writer);
+  serd_node_free(input_name);
   serd_env_free(env);
   serd_node_free(base);
   serd_world_free(world);
diff --git a/src/world.c b/src/world.c
index 4413f433..4230448a 100644
--- a/src/world.c
+++ b/src/world.c
@@ -16,6 +16,7 @@
 
 #include "world.h"
 
+#include "caret.h"
 #include "node.h"
 #include "serd_config.h"
 #include "system.h"
@@ -58,10 +59,13 @@ serd_world_error(const SerdWorld* const world, const SerdError* const e)
   if (world->error_func) {
     world->error_func(world->error_handle, e);
   } else {
-    if (e->filename) {
-      fprintf(stderr, "error: %s:%u:%u: ", e->filename, e->line, e->col);
-    } else {
-      fprintf(stderr, "error: ");
+    fprintf(stderr, "error: ");
+    if (e->caret) {
+      fprintf(stderr,
+              "%s:%u:%u: ",
+              serd_node_string(e->caret->file),
+              e->caret->line,
+              e->caret->col);
     }
     vfprintf(stderr, e->fmt, *e->args);
   }
@@ -76,7 +80,7 @@ serd_world_errorf(const SerdWorld* const world,
 {
   va_list args;
   va_start(args, fmt);
-  const SerdError e = {st, NULL, 0, 0, fmt, &args};
+  const SerdError e = {st, NULL, fmt, &args};
   serd_world_error(world, &e);
   va_end(args);
   return st;
-- 
cgit v1.2.1