summaryrefslogtreecommitdiffstats
path: root/locfile.h
blob: 710cfbd1d733e4a8c0a897fed729acf2a8ad836c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#ifndef _LOCFILE_H
#define _LOCFILE_H
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <stdarg.h>
#include "jv_alloc.h"
typedef struct {
  int start, end;
} location;

static const location UNKNOWN_LOCATION = {-1, -1};

struct locfile {
  const char* data;
  int length;
  int* linemap;
  int nlines;
};

static void locfile_init(struct locfile* l, const char* data, int length) {
  l->data = data;
  l->length = length;
  l->nlines = 1;
  for (int i=0; i<length; i++) {
    if (data[i] == '\n') l->nlines++;
  }
  l->linemap = jv_mem_alloc(sizeof(int) * (l->nlines + 1));
  l->linemap[0] = 0;
  int line = 1;
  for (int i=0; i<length; i++) {
    if (data[i] == '\n') {
      l->linemap[line] = i;
      line++;
    }
  }
  l->linemap[l->nlines] = length;
}

static void locfile_free(struct locfile* l) {
  jv_mem_free(l->linemap);
}

static int locfile_get_line(struct locfile* l, int pos) {
  assert(pos < l->length);
  int line = 0;
  while (l->linemap[line+1] < pos) line++;
  assert(line < l->nlines);
  return line;
}

static int locfile_line_length(struct locfile* l, int line) {
  assert(line < l->nlines);
  return l->linemap[line+1] - l->linemap[line];
}

static void locfile_locate(struct locfile* l, location loc, const char* fmt, ...) {
  va_list fmtargs;
  va_start(fmtargs, fmt);
  vfprintf(stderr, fmt, fmtargs);
  va_end(fmtargs);
  fprintf(stderr, "\n");
  if (loc.start == -1) {
    fprintf(stderr, "<unknown location>\n");
    return;
  }
  int startline = locfile_get_line(l, loc.start);
  int offset = l->linemap[startline];
  fprintf(stderr, "%.*s\n", locfile_line_length(l, startline), l->data + offset);
  fprintf(stderr, "%*s", loc.start - offset, "");
  for (int i = loc.start; 
       i < loc.end && i < offset + locfile_line_length(l, startline);
       i++){
    fprintf(stderr, "^");
  }
  fprintf(stderr, "\n");
}

#endif