| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
/* mds_footnote.c — GFM footnote definitions table. |
|
2
|
|
|
|
|
|
|
* |
|
3
|
|
|
|
|
|
|
* Lookup is by case-folded label (matching link-reference rules so that |
|
4
|
|
|
|
|
|
|
* `[^Foo]: x` is found by `[^foo]`). The implementation reuses the |
|
5
|
|
|
|
|
|
|
* same fold/normalise approach as mds_linkref by simply lowercasing |
|
6
|
|
|
|
|
|
|
* ASCII and collapsing inner whitespace; GFM spec examples only need |
|
7
|
|
|
|
|
|
|
* that subset for footnote labels (no Unicode case-folding in tests). |
|
8
|
|
|
|
|
|
|
*/ |
|
9
|
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
#include "mds_footnote.h" |
|
11
|
|
|
|
|
|
|
#include |
|
12
|
|
|
|
|
|
|
#include |
|
13
|
|
|
|
|
|
|
#include |
|
14
|
|
|
|
|
|
|
|
|
15
|
66
|
|
|
|
|
|
static size_t fn_normalise(const char* s, size_t n, char* out) { |
|
16
|
66
|
|
|
|
|
|
size_t a = 0, b = n; |
|
17
|
66
|
|
|
|
|
|
size_t j = 0; |
|
18
|
|
|
|
|
|
|
size_t i; |
|
19
|
66
|
|
|
|
|
|
int in_ws = 0; |
|
20
|
66
|
50
|
|
|
|
|
while (a < b && (s[a] == ' ' || s[a] == '\t' || s[a] == '\n')) a++; |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
21
|
66
|
50
|
|
|
|
|
while (b > a && (s[b-1] == ' ' || s[b-1] == '\t' || s[b-1] == '\n')) b--; |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
22
|
786
|
100
|
|
|
|
|
for (i = a; i < b; i++) { |
|
23
|
720
|
|
|
|
|
|
unsigned char c = (unsigned char)s[i]; |
|
24
|
720
|
50
|
|
|
|
|
if (c == ' ' || c == '\t' || c == '\n') { |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
25
|
0
|
0
|
|
|
|
|
if (!in_ws) { out[j++] = ' '; in_ws = 1; } |
|
26
|
|
|
|
|
|
|
} else { |
|
27
|
720
|
100
|
|
|
|
|
if (c >= 'A' && c <= 'Z') c = (unsigned char)(c + 0x20); |
|
|
|
50
|
|
|
|
|
|
|
28
|
720
|
|
|
|
|
|
out[j++] = (char)c; |
|
29
|
720
|
|
|
|
|
|
in_ws = 0; |
|
30
|
|
|
|
|
|
|
} |
|
31
|
|
|
|
|
|
|
} |
|
32
|
66
|
|
|
|
|
|
return j; |
|
33
|
|
|
|
|
|
|
} |
|
34
|
|
|
|
|
|
|
|
|
35
|
63
|
|
|
|
|
|
static char* fn_arena_dup(mds_arena* a, const char* s, size_t n) { |
|
36
|
|
|
|
|
|
|
char* d; |
|
37
|
63
|
|
|
|
|
|
d = (char*)mds_arena_alloc(a, n + 1); |
|
38
|
63
|
50
|
|
|
|
|
if (n) memcpy(d, s, n); |
|
39
|
63
|
|
|
|
|
|
d[n] = '\0'; |
|
40
|
63
|
|
|
|
|
|
return d; |
|
41
|
|
|
|
|
|
|
} |
|
42
|
|
|
|
|
|
|
|
|
43
|
9
|
|
|
|
|
|
void mds_footnote_init(struct mds_footnote_tab* t, mds_arena* a) { |
|
44
|
9
|
|
|
|
|
|
t->entries = NULL; |
|
45
|
9
|
|
|
|
|
|
t->len = 0; |
|
46
|
9
|
|
|
|
|
|
t->cap = 0; |
|
47
|
9
|
|
|
|
|
|
t->arena = a; |
|
48
|
9
|
|
|
|
|
|
} |
|
49
|
|
|
|
|
|
|
|
|
50
|
45
|
|
|
|
|
|
const mds_footnote* mds_footnote_get(const struct mds_footnote_tab* t, |
|
51
|
|
|
|
|
|
|
const char* label, size_t llen) { |
|
52
|
|
|
|
|
|
|
char buf[4096]; |
|
53
|
|
|
|
|
|
|
size_t nlen; |
|
54
|
|
|
|
|
|
|
size_t i; |
|
55
|
45
|
50
|
|
|
|
|
if (!t || !t->len) return NULL; |
|
|
|
50
|
|
|
|
|
|
|
56
|
45
|
50
|
|
|
|
|
if (llen > sizeof buf) return NULL; |
|
57
|
45
|
|
|
|
|
|
nlen = fn_normalise(label, llen, buf); |
|
58
|
96
|
100
|
|
|
|
|
for (i = 0; i < t->len; i++) { |
|
59
|
93
|
100
|
|
|
|
|
if (t->entries[i].klen == nlen && |
|
|
|
50
|
|
|
|
|
|
|
60
|
42
|
50
|
|
|
|
|
(nlen == 0 || memcmp(t->entries[i].key, buf, nlen) == 0)) |
|
61
|
42
|
|
|
|
|
|
return &t->entries[i]; |
|
62
|
|
|
|
|
|
|
} |
|
63
|
3
|
|
|
|
|
|
return NULL; |
|
64
|
|
|
|
|
|
|
} |
|
65
|
|
|
|
|
|
|
|
|
66
|
21
|
|
|
|
|
|
int mds_footnote_add(struct mds_footnote_tab* t, |
|
67
|
|
|
|
|
|
|
const char* label, size_t llen, |
|
68
|
|
|
|
|
|
|
const char* body, size_t blen) { |
|
69
|
|
|
|
|
|
|
char nbuf[4096]; |
|
70
|
|
|
|
|
|
|
size_t nlen; |
|
71
|
|
|
|
|
|
|
size_t i; |
|
72
|
|
|
|
|
|
|
mds_footnote* e; |
|
73
|
21
|
50
|
|
|
|
|
if (llen > sizeof nbuf) return 0; |
|
74
|
21
|
|
|
|
|
|
nlen = fn_normalise(label, llen, nbuf); |
|
75
|
|
|
|
|
|
|
/* duplicate label: first-wins (spec §6.13). */ |
|
76
|
51
|
100
|
|
|
|
|
for (i = 0; i < t->len; i++) { |
|
77
|
30
|
50
|
|
|
|
|
if (t->entries[i].klen == nlen && |
|
|
|
0
|
|
|
|
|
|
|
78
|
0
|
0
|
|
|
|
|
(nlen == 0 || memcmp(t->entries[i].key, nbuf, nlen) == 0)) |
|
79
|
0
|
|
|
|
|
|
return 0; |
|
80
|
|
|
|
|
|
|
} |
|
81
|
21
|
100
|
|
|
|
|
if (t->len == t->cap) { |
|
82
|
9
|
50
|
|
|
|
|
size_t nc = t->cap ? t->cap * 2 : 8; |
|
83
|
9
|
|
|
|
|
|
t->entries = (mds_footnote*)realloc(t->entries, nc * sizeof(mds_footnote)); |
|
84
|
9
|
|
|
|
|
|
t->cap = nc; |
|
85
|
|
|
|
|
|
|
} |
|
86
|
21
|
|
|
|
|
|
e = &t->entries[t->len++]; |
|
87
|
21
|
|
|
|
|
|
e->label = fn_arena_dup(t->arena, label, llen); e->llen = llen; |
|
88
|
21
|
|
|
|
|
|
e->key = fn_arena_dup(t->arena, nbuf, nlen); e->klen = nlen; |
|
89
|
21
|
|
|
|
|
|
e->body = fn_arena_dup(t->arena, body, blen); e->blen = blen; |
|
90
|
21
|
|
|
|
|
|
return 1; |
|
91
|
|
|
|
|
|
|
} |