Coverage Report

Created: 2026-06-08 06:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/mupdf/thirdparty/cmark-gfm/extensions/strikethrough.c
Line
Count
Source
1
#include "strikethrough.h"
2
#include <parser.h>
3
#include <render.h>
4
5
cmark_node_type CMARK_NODE_STRIKETHROUGH;
6
7
static cmark_node *match(cmark_syntax_extension *self, cmark_parser *parser,
8
                         cmark_node *parent, unsigned char character,
9
0
                         cmark_inline_parser *inline_parser) {
10
0
  cmark_node *res = NULL;
11
0
  int left_flanking, right_flanking, punct_before, punct_after, delims;
12
0
  char buffer[101];
13
14
0
  if (character != '~')
15
0
    return NULL;
16
17
0
  delims = cmark_inline_parser_scan_delimiters(
18
0
      inline_parser, sizeof(buffer) - 1, '~',
19
0
      &left_flanking,
20
0
      &right_flanking, &punct_before, &punct_after);
21
22
0
  memset(buffer, '~', delims);
23
0
  buffer[delims] = 0;
24
25
0
  res = cmark_node_new_with_mem(CMARK_NODE_TEXT, parser->mem);
26
0
  cmark_node_set_literal(res, buffer);
27
0
  res->start_line = res->end_line = cmark_inline_parser_get_line(inline_parser);
28
0
  res->start_column = cmark_inline_parser_get_column(inline_parser) - delims;
29
30
0
  if ((left_flanking || right_flanking) &&
31
0
      (delims == 2 || (!(parser->options & CMARK_OPT_STRIKETHROUGH_DOUBLE_TILDE) && delims == 1))) {
32
0
    cmark_inline_parser_push_delimiter(inline_parser, character, left_flanking,
33
0
                                       right_flanking, res);
34
0
  }
35
36
0
  return res;
37
0
}
38
39
static delimiter *insert(cmark_syntax_extension *self, cmark_parser *parser,
40
                         cmark_inline_parser *inline_parser, delimiter *opener,
41
0
                         delimiter *closer) {
42
0
  cmark_node *strikethrough;
43
0
  cmark_node *tmp, *next;
44
0
  delimiter *delim, *tmp_delim;
45
0
  delimiter *res = closer->next;
46
47
0
  strikethrough = opener->inl_text;
48
49
0
  if (opener->inl_text->as.literal.len != closer->inl_text->as.literal.len)
50
0
    goto done;
51
52
0
  if (!cmark_node_set_type(strikethrough, CMARK_NODE_STRIKETHROUGH))
53
0
    goto done;
54
55
0
  cmark_node_set_syntax_extension(strikethrough, self);
56
57
0
  tmp = cmark_node_next(opener->inl_text);
58
59
0
  while (tmp) {
60
0
    if (tmp == closer->inl_text)
61
0
      break;
62
0
    next = cmark_node_next(tmp);
63
0
    cmark_node_append_child(strikethrough, tmp);
64
0
    tmp = next;
65
0
  }
66
67
0
  strikethrough->end_column = closer->inl_text->start_column + closer->inl_text->as.literal.len - 1;
68
0
  cmark_node_free(closer->inl_text);
69
70
0
done:
71
0
  delim = closer;
72
0
  while (delim != NULL && delim != opener) {
73
0
    tmp_delim = delim->previous;
74
0
    cmark_inline_parser_remove_delimiter(inline_parser, delim);
75
0
    delim = tmp_delim;
76
0
  }
77
78
0
  cmark_inline_parser_remove_delimiter(inline_parser, opener);
79
80
0
  return res;
81
0
}
82
83
static const char *get_type_string(cmark_syntax_extension *extension,
84
0
                                   cmark_node *node) {
85
0
  return node->type == CMARK_NODE_STRIKETHROUGH ? "strikethrough" : "<unknown>";
86
0
}
87
88
static int can_contain(cmark_syntax_extension *extension, cmark_node *node,
89
0
                       cmark_node_type child_type) {
90
0
  if (node->type != CMARK_NODE_STRIKETHROUGH)
91
0
    return false;
92
93
0
  return CMARK_NODE_TYPE_INLINE_P(child_type);
94
0
}
95
96
static void commonmark_render(cmark_syntax_extension *extension,
97
                              cmark_renderer *renderer, cmark_node *node,
98
0
                              cmark_event_type ev_type, int options) {
99
0
  renderer->out(renderer, node, "~~", false, LITERAL);
100
0
}
101
102
static void latex_render(cmark_syntax_extension *extension,
103
                         cmark_renderer *renderer, cmark_node *node,
104
0
                         cmark_event_type ev_type, int options) {
105
  // requires \usepackage{ulem}
106
0
  bool entering = (ev_type == CMARK_EVENT_ENTER);
107
0
  if (entering) {
108
0
    renderer->out(renderer, node, "\\sout{", false, LITERAL);
109
0
  } else {
110
0
    renderer->out(renderer, node, "}", false, LITERAL);
111
0
  }
112
0
}
113
114
static void man_render(cmark_syntax_extension *extension,
115
                       cmark_renderer *renderer, cmark_node *node,
116
0
                       cmark_event_type ev_type, int options) {
117
0
  bool entering = (ev_type == CMARK_EVENT_ENTER);
118
0
  if (entering) {
119
0
    renderer->cr(renderer);
120
0
    renderer->out(renderer, node, ".ST \"", false, LITERAL);
121
0
  } else {
122
0
    renderer->out(renderer, node, "\"", false, LITERAL);
123
0
    renderer->cr(renderer);
124
0
  }
125
0
}
126
127
static void html_render(cmark_syntax_extension *extension,
128
                        cmark_html_renderer *renderer, cmark_node *node,
129
0
                        cmark_event_type ev_type, int options) {
130
0
  bool entering = (ev_type == CMARK_EVENT_ENTER);
131
0
  if (entering) {
132
0
    cmark_strbuf_puts(renderer->html, "<del>");
133
0
  } else {
134
0
    cmark_strbuf_puts(renderer->html, "</del>");
135
0
  }
136
0
}
137
138
static void plaintext_render(cmark_syntax_extension *extension,
139
                             cmark_renderer *renderer, cmark_node *node,
140
0
                             cmark_event_type ev_type, int options) {
141
0
  renderer->out(renderer, node, "~", false, LITERAL);
142
0
}
143
144
0
cmark_syntax_extension *create_strikethrough_extension(void) {
145
0
  cmark_syntax_extension *ext = cmark_syntax_extension_new("strikethrough");
146
0
  cmark_llist *special_chars = NULL;
147
148
0
  cmark_syntax_extension_set_get_type_string_func(ext, get_type_string);
149
0
  cmark_syntax_extension_set_can_contain_func(ext, can_contain);
150
0
  cmark_syntax_extension_set_commonmark_render_func(ext, commonmark_render);
151
0
  cmark_syntax_extension_set_latex_render_func(ext, latex_render);
152
0
  cmark_syntax_extension_set_man_render_func(ext, man_render);
153
0
  cmark_syntax_extension_set_html_render_func(ext, html_render);
154
0
  cmark_syntax_extension_set_plaintext_render_func(ext, plaintext_render);
155
0
  CMARK_NODE_STRIKETHROUGH = cmark_syntax_extension_add_node(1);
156
157
0
  cmark_syntax_extension_set_match_inline_func(ext, match);
158
0
  cmark_syntax_extension_set_inline_from_delim_func(ext, insert);
159
160
0
  cmark_mem *mem = cmark_get_default_mem_allocator();
161
0
  special_chars = cmark_llist_append(mem, special_chars, (void *)'~');
162
0
  cmark_syntax_extension_set_special_inline_chars(ext, special_chars);
163
164
0
  cmark_syntax_extension_set_emphasis(ext, 1);
165
166
0
  return ext;
167
0
}