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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
|
#include <stdlib.h>
#include <string.h>
#include "lines.h"
#include "util/debug.h"
#include "util/error.h"
bool file_lines_open(const char *progname, const char *fname, FILE *f, struct file_lines *dst) {
dst->f = f;
dst->cap = 4096;
dst->buffer = malloc(dst->cap);
if (!dst->buffer) {
print_error_nomem(progname);
return false;
}
dst->cursor = 0;
dst->readfrom = (size_t)-1;
dst->progname = progname;
dst->fname = fname;
return true;
}
bool file_lines_read(struct file_lines *fl, struct string_view *dst) {
// Return already-read line if we have any
if (fl->readfrom != (size_t)-1) {
char *p = memchr(fl->buffer + fl->readfrom, '\n', fl->cursor - fl->readfrom);
if (p != NULL) {
dst->s = fl->buffer + fl->readfrom;
dst->len = p - (fl->buffer + fl->readfrom);
fl->readfrom = p - fl->buffer + 1;
DEBUG("next line from %zu len %zu\n", fl->readfrom, dst->len);
return true;
}
DEBUG("no more newlines, moving back from %zu len %zu\n", fl->readfrom, fl->cursor - fl->readfrom);
// move back whatever we have left
memmove(fl->buffer, fl->buffer + fl->readfrom, fl->cursor - fl->readfrom);
fl->cursor -= fl->readfrom;
}
DEBUG("cursor=%zu\n", fl->cursor);
// read a line
size_t linelen = 0;
bool havenewline = true;
while (true) {
// grow buffer when small
if (fl->cap - fl->cursor < 1024) {
fl->cap *= 2;
if (fl->cap == 0) {
fprintf(stderr, "%s: Regel te lang\n", fl->progname);
exit(1);
}
DEBUG("realloc to cap %zu\n", fl->cap);
fl->buffer = realloc(fl->buffer, fl->cap);
if (!fl->buffer) print_error_nomem(fl->progname);
}
size_t nr = fread(fl->buffer + fl->cursor, 1, fl->cap - fl->cursor, fl->f);
DEBUG("nr=%zu\n", nr);
if (nr == 0) {
if (feof(fl->f)) {
if (fl->cursor == 0) return false;
linelen = fl->cursor;
havenewline = false;
break;
}
if (fl->fname) fprintf(stderr, "%s: Fout bij lezen van bestand '%s'\n", fl->progname, fl->fname);
else fprintf(stderr, "%s: Fout bij lezen van standaardinvoer\n", fl->progname);
exit(1);
}
char *p = memchr(fl->buffer + fl->cursor, '\n', nr);
fl->cursor += nr;
if (p != NULL) {
linelen = p - fl->buffer;
break;
}
}
DEBUG("line with len %zu (cursor=%zu)\n", linelen, fl->cursor);
// we have a newline at buffer + linelen; return lines in buffer
dst->s = fl->buffer;
dst->len = linelen;
fl->readfrom = linelen + havenewline;
return true;
}
void file_lines_close(struct file_lines *fl) {
free(fl->buffer);
}
|