Line | Branch | Exec | Source |
---|---|---|---|
1 | #include <stdlib.h> | ||
2 | #include <string.h> | ||
3 | #include <sys/stat.h> | ||
4 | #include "buffer.h" | ||
5 | #include "editor.h" | ||
6 | #include "encoding.h" | ||
7 | #include "file-option.h" | ||
8 | #include "filetype.h" | ||
9 | #include "syntax/state.h" | ||
10 | #include "util/intern.h" | ||
11 | #include "util/path.h" | ||
12 | #include "util/xmalloc.h" | ||
13 | #include "util/xstring.h" | ||
14 | |||
15 | 126 | void buffer_set_display_filename(Buffer *buffer, char *name) | |
16 | { | ||
17 | 126 | free(buffer->display_filename); | |
18 | 126 | buffer->display_filename = name; | |
19 | 126 | } | |
20 | |||
21 | /* | ||
22 | * Mark line range min...max (inclusive) "changed". These lines will be | ||
23 | * redrawn when screen is updated. This is called even when content has not | ||
24 | * been changed, but selection has or line has been deleted and all lines | ||
25 | * after the deleted line move up. | ||
26 | * | ||
27 | * Syntax highlighter has different logic. It cares about contents of the | ||
28 | * lines, not about selection or if the lines have been moved up or down. | ||
29 | */ | ||
30 | 476 | void buffer_mark_lines_changed(Buffer *buffer, long min, long max) | |
31 | { | ||
32 | 476 | buffer->changed_line_min = MIN3(min, max, buffer->changed_line_min); | |
33 | 476 | buffer->changed_line_max = MAX3(min, max, buffer->changed_line_max); | |
34 | 476 | } | |
35 | |||
36 | 4 | const char *buffer_filename(const Buffer *buffer) | |
37 | { | ||
38 | 4 | const char *name = buffer->display_filename; | |
39 |
2/2✓ Branch 0 (2→3) taken 3 times.
✓ Branch 1 (2→4) taken 1 times.
|
4 | return name ? name : "(No name)"; |
40 | } | ||
41 | |||
42 | 57 | void buffer_set_encoding(Buffer *buffer, const char *encoding, bool utf8_bom) | |
43 | { | ||
44 | 57 | if (DEBUG >= 1) { | |
45 | 57 | const char *nenc = encoding_normalize(encoding); | |
46 | 57 | BUG_ON(encoding != nenc); | |
47 | } | ||
48 | |||
49 |
2/2✓ Branch 0 (5→6) taken 54 times.
✓ Branch 1 (5→10) taken 3 times.
|
57 | if (interned_strings_equal(buffer->encoding, encoding)) { |
50 | return; | ||
51 | } | ||
52 | |||
53 | 54 | EncodingType type = lookup_encoding(encoding); | |
54 |
1/2✗ Branch 0 (7→8) not taken.
✓ Branch 1 (7→9) taken 54 times.
|
54 | buffer->bom = (type == UTF8) ? utf8_bom : encoding_type_has_bom(type); |
55 | 54 | buffer->encoding = encoding; | |
56 | } | ||
57 | |||
58 | 81 | Buffer *buffer_new(PointerArray *buffers, const GlobalOptions *gopts, const char *encoding) | |
59 | { | ||
60 | 81 | static unsigned long id; | |
61 | 81 | Buffer *buffer = xnew0(Buffer, 1); | |
62 | 81 | list_init(&buffer->blocks); | |
63 | 81 | buffer->cur_change = &buffer->change_head; | |
64 | 81 | buffer->saved_change = &buffer->change_head; | |
65 | 81 | buffer->id = ++id; | |
66 | 81 | buffer->crlf_newlines = gopts->crlf_newlines; | |
67 | |||
68 |
2/2✓ Branch 0 (4→5) taken 54 times.
✓ Branch 1 (4→6) taken 27 times.
|
81 | if (encoding) { |
69 | 54 | buffer_set_encoding(buffer, encoding, gopts->utf8_bom); | |
70 | } | ||
71 | |||
72 | 81 | static_assert(sizeof(*gopts) >= sizeof(CommonOptions)); | |
73 | 81 | memcpy(&buffer->options, gopts, sizeof(CommonOptions)); | |
74 | 81 | buffer->options.brace_indent = 0; | |
75 | 81 | buffer->options.filetype = str_intern("none"); | |
76 | 81 | buffer->options.indent_regex = NULL; | |
77 | |||
78 | 81 | ptr_array_append(buffers, buffer); | |
79 | 81 | return buffer; | |
80 | } | ||
81 | |||
82 | 49 | Buffer *open_empty_buffer(PointerArray *buffers, const GlobalOptions *gopts) | |
83 | { | ||
84 | 49 | Buffer *buffer = buffer_new(buffers, gopts, encoding_from_type(UTF8)); | |
85 | |||
86 | // At least one block required | ||
87 | 49 | Block *blk = block_new(1); | |
88 | 49 | list_insert_before(&blk->node, &buffer->blocks); | |
89 | |||
90 | 49 | return buffer; | |
91 | } | ||
92 | |||
93 | 81 | void free_blocks(Buffer *buffer) | |
94 | { | ||
95 | 81 | ListHead *item = buffer->blocks.next; | |
96 |
2/2✓ Branch 0 (4→3) taken 111 times.
✓ Branch 1 (4→5) taken 81 times.
|
192 | while (item != &buffer->blocks) { |
97 | 111 | ListHead *next = item->next; | |
98 | 111 | Block *blk = BLOCK(item); | |
99 | 111 | free(blk->data); | |
100 | 111 | free(blk); | |
101 | 111 | item = next; | |
102 | } | ||
103 | 81 | } | |
104 | |||
105 | 81 | static void buffer_unlock_and_free ( | |
106 | Buffer *buffer, | ||
107 | ErrorBuffer *ebuf, | ||
108 | const FileLocksContext *locks_ctx | ||
109 | ) { | ||
110 |
1/2✗ Branch 0 (2→3) not taken.
✓ Branch 1 (2→4) taken 81 times.
|
81 | if (buffer->locked) { |
111 | ✗ | unlock_file(locks_ctx, ebuf, buffer->abs_filename); | |
112 | } | ||
113 | |||
114 | 81 | free_changes(&buffer->change_head); | |
115 | 81 | ptr_array_free_array(&buffer->line_start_states); | |
116 | 81 | ptr_array_free_array(&buffer->views); | |
117 | 81 | free(buffer->display_filename); | |
118 | 81 | free(buffer->abs_filename); | |
119 | |||
120 |
2/2✓ Branch 0 (7→8) taken 76 times.
✓ Branch 1 (7→10) taken 5 times.
|
81 | if (buffer->stdout_buffer) { |
121 | /* | ||
122 | * If this buffer is to be piped to stdout on exit, retain just | ||
123 | * the blocks and the buffer itself. After this point, the pointer | ||
124 | * in main() takes ownership and is responsible for freeing the | ||
125 | * remaining allocations. | ||
126 | * | ||
127 | * See also: | ||
128 | * • init_std_buffer() | ||
129 | * • buffer_write_blocks_and_free() | ||
130 | * • main() | ||
131 | * • cmd_save() | ||
132 | */ | ||
133 | return; | ||
134 | } | ||
135 | |||
136 | 76 | free_blocks(buffer); | |
137 | 76 | free(buffer); | |
138 | } | ||
139 | |||
140 | 8 | void free_buffers ( | |
141 | PointerArray *buffers, | ||
142 | ErrorBuffer *ebuf, | ||
143 | const FileLocksContext *locks_ctx | ||
144 | ) { | ||
145 |
1/2✗ Branch 0 (5→3) not taken.
✓ Branch 1 (5→6) taken 8 times.
|
8 | for (size_t i = 0, n = buffers->count; i < n; i++) { |
146 | ✗ | Buffer *buffer = buffers->ptrs[i]; | |
147 | ✗ | buffer_unlock_and_free(buffer, ebuf, locks_ctx); | |
148 | ✗ | buffers->ptrs[i] = NULL; | |
149 | } | ||
150 | 8 | ptr_array_free_array(buffers); | |
151 | 8 | } | |
152 | |||
153 | 81 | void buffer_remove_unlock_and_free ( | |
154 | PointerArray *buffers, | ||
155 | Buffer *buffer, | ||
156 | ErrorBuffer *ebuf, | ||
157 | const FileLocksContext *locks_ctx | ||
158 | ) { | ||
159 | 81 | ptr_array_remove(buffers, buffer); | |
160 | 81 | buffer_unlock_and_free(buffer, ebuf, locks_ctx); | |
161 | 81 | } | |
162 | |||
163 | 873 | static bool same_file(const Buffer *buffer, const struct stat *st) | |
164 | { | ||
165 |
3/4✓ Branch 0 (2→3) taken 349 times.
✓ Branch 1 (2→4) taken 524 times.
✓ Branch 2 (3→4) taken 349 times.
✗ Branch 3 (3→5) not taken.
|
873 | return (st->st_dev == buffer->file.dev) && (st->st_ino == buffer->file.ino); |
166 | } | ||
167 | |||
168 | 27 | Buffer *find_buffer(const PointerArray *buffers, const char *abs_filename) | |
169 | { | ||
170 | 27 | struct stat st; | |
171 | 27 | bool st_ok = stat(abs_filename, &st) == 0; | |
172 |
2/2✓ Branch 0 (9→4) taken 873 times.
✓ Branch 1 (9→10) taken 27 times.
|
900 | for (size_t i = 0, n = buffers->count; i < n; i++) { |
173 | 873 | Buffer *buffer = buffers->ptrs[i]; | |
174 | 873 | const char *f = buffer->abs_filename; | |
175 |
5/8✓ Branch 0 (4→5) taken 349 times.
✓ Branch 1 (4→6) taken 524 times.
✓ Branch 2 (5→6) taken 349 times.
✗ Branch 3 (5→10) not taken.
✓ Branch 4 (6→7) taken 873 times.
✗ Branch 5 (6→8) not taken.
✓ Branch 6 (7→8) taken 873 times.
✗ Branch 7 (7→10) not taken.
|
873 | if ((f && streq(f, abs_filename)) || (st_ok && same_file(buffer, &st))) { |
176 | return buffer; | ||
177 | } | ||
178 | } | ||
179 | return NULL; | ||
180 | } | ||
181 | |||
182 | 11 | Buffer *find_buffer_by_id(const PointerArray *buffers, unsigned long id) | |
183 | { | ||
184 |
2/2✓ Branch 0 (5→3) taken 72 times.
✓ Branch 1 (5→6) taken 7 times.
|
79 | for (size_t i = 0, n = buffers->count; i < n; i++) { |
185 | 72 | Buffer *buffer = buffers->ptrs[i]; | |
186 |
2/2✓ Branch 0 (3→4) taken 68 times.
✓ Branch 1 (3→6) taken 4 times.
|
72 | if (buffer->id == id) { |
187 | return buffer; | ||
188 | } | ||
189 | } | ||
190 | return NULL; | ||
191 | } | ||
192 | |||
193 | 75 | bool buffer_detect_filetype(Buffer *buffer, const PointerArray *filetypes) | |
194 | { | ||
195 | 75 | StringView line = STRING_VIEW_INIT; | |
196 |
2/2✓ Branch 0 (2→3) taken 25 times.
✓ Branch 1 (2→5) taken 50 times.
|
75 | if (BLOCK(buffer->blocks.next)->size) { |
197 | 25 | BlockIter bi = block_iter(buffer); | |
198 | 25 | line = block_iter_get_line(&bi); | |
199 |
1/2✗ Branch 0 (5→6) not taken.
✓ Branch 1 (5→11) taken 50 times.
|
50 | } else if (!buffer->abs_filename) { |
200 | return false; | ||
201 | } | ||
202 | |||
203 | 25 | const char *ft = find_ft(filetypes, buffer->abs_filename, line); | |
204 |
3/4✓ Branch 0 (7→8) taken 4 times.
✓ Branch 1 (7→11) taken 21 times.
✓ Branch 2 (8→9) taken 4 times.
✗ Branch 3 (8→11) not taken.
|
25 | if (ft && !streq(ft, buffer->options.filetype)) { |
205 | 4 | buffer->options.filetype = str_intern(ft); | |
206 | 4 | return true; | |
207 | } | ||
208 | |||
209 | return false; | ||
210 | } | ||
211 | |||
212 | 136 | void buffer_update_short_filename_cwd(Buffer *buffer, const StringView *home, const char *cwd) | |
213 | { | ||
214 | 136 | const char *abs = buffer->abs_filename; | |
215 |
2/2✓ Branch 0 (2→3) taken 73 times.
✓ Branch 1 (2→7) taken 63 times.
|
136 | if (!abs) { |
216 | return; | ||
217 | } | ||
218 |
1/2✓ Branch 0 (3→4) taken 73 times.
✗ Branch 1 (3→5) not taken.
|
73 | char *name = cwd ? short_filename_cwd(abs, cwd, home) : xstrdup(abs); |
219 | 73 | buffer_set_display_filename(buffer, name); | |
220 | } | ||
221 | |||
222 | 47 | void buffer_update_short_filename(Buffer *buffer, const StringView *home) | |
223 | { | ||
224 | 47 | const char *abs = buffer->abs_filename; | |
225 | 47 | BUG_ON(!abs); | |
226 | 47 | buffer_set_display_filename(buffer, short_filename(abs, home)); | |
227 | 47 | } | |
228 | |||
229 | 58 | void buffer_update_syntax(EditorState *e, Buffer *buffer) | |
230 | { | ||
231 | 58 | Syntax *syn = NULL; | |
232 |
2/2✓ Branch 0 (2→3) taken 57 times.
✓ Branch 1 (2→6) taken 1 times.
|
58 | if (buffer->options.syntax) { |
233 | // Even "none" can have syntax | ||
234 | 57 | syn = find_syntax(&e->syntaxes, buffer->options.filetype); | |
235 |
2/2✓ Branch 0 (4→5) taken 52 times.
✓ Branch 1 (4→6) taken 5 times.
|
57 | if (!syn) { |
236 | 52 | syn = load_syntax_by_filetype(e, buffer->options.filetype); | |
237 | } | ||
238 | } | ||
239 |
2/2✓ Branch 0 (6→7) taken 6 times.
✓ Branch 1 (6→12) taken 52 times.
|
58 | if (syn == buffer->syntax) { |
240 | return; | ||
241 | } | ||
242 | |||
243 | 6 | buffer->syntax = syn; | |
244 |
2/2✓ Branch 0 (7→8) taken 5 times.
✓ Branch 1 (7→11) taken 1 times.
|
6 | if (syn) { |
245 | // Start state of first line is constant | ||
246 | 5 | PointerArray *s = &buffer->line_start_states; | |
247 |
1/2✓ Branch 0 (8→9) taken 5 times.
✗ Branch 1 (8→10) not taken.
|
5 | if (!s->alloc) { |
248 | 5 | ptr_array_init(s, 64); | |
249 | } | ||
250 | 5 | s->ptrs[0] = syn->start_state; | |
251 | 5 | s->count = 1; | |
252 | } | ||
253 | |||
254 | 6 | mark_all_lines_changed(buffer); | |
255 | } | ||
256 | |||
257 | 36 | static bool allow_odd_indent(uint8_t indents_bitmask) | |
258 | { | ||
259 | 36 | static_assert(INDENT_WIDTH_MAX == 8); | |
260 | 36 | return !!(indents_bitmask & 0x55); // 0x55 == 0b01010101 | |
261 | } | ||
262 | |||
263 | 163 | static int indent_len(StringView line, uint8_t indents_bitmask, bool *tab_indent) | |
264 | { | ||
265 | 163 | bool space_before_tab = false; | |
266 | 163 | size_t spaces = 0; | |
267 | 163 | size_t tabs = 0; | |
268 | 163 | size_t pos = 0; | |
269 | |||
270 |
2/2✓ Branch 0 (9→3) taken 651 times.
✓ Branch 1 (9→10) taken 20 times.
|
671 | for (size_t n = line.length; pos < n; pos++) { |
271 |
3/3✓ Branch 0 (3→4) taken 90 times.
✓ Branch 1 (3→7) taken 418 times.
✓ Branch 2 (3→10) taken 143 times.
|
651 | switch (line.data[pos]) { |
272 | 90 | case '\t': | |
273 | 90 | tabs++; | |
274 |
2/2✓ Branch 0 (4→5) taken 36 times.
✓ Branch 1 (4→6) taken 54 times.
|
90 | if (spaces) { |
275 | 36 | space_before_tab = true; | |
276 | } | ||
277 | 90 | continue; | |
278 | 418 | case ' ': | |
279 | 418 | spaces++; | |
280 | 418 | continue; | |
281 | } | ||
282 | break; | ||
283 | } | ||
284 | |||
285 | 163 | *tab_indent = false; | |
286 |
2/2✓ Branch 0 (10→11) taken 143 times.
✓ Branch 1 (10→21) taken 20 times.
|
163 | if (pos == line.length) { |
287 | return -1; // Whitespace only | ||
288 | } | ||
289 |
2/2✓ Branch 0 (11→12) taken 115 times.
✓ Branch 1 (11→21) taken 28 times.
|
143 | if (pos == 0) { |
290 | return 0; // Not indented | ||
291 | } | ||
292 |
2/2✓ Branch 0 (12→13) taken 97 times.
✓ Branch 1 (12→21) taken 18 times.
|
115 | if (space_before_tab) { |
293 | return -2; // Mixed indent | ||
294 | } | ||
295 |
2/2✓ Branch 0 (13→14) taken 18 times.
✓ Branch 1 (13→15) taken 79 times.
|
97 | if (tabs) { |
296 | // Tabs and possible spaces after tab for alignment | ||
297 | 18 | *tab_indent = true; | |
298 | 18 | return tabs * 8; | |
299 | } | ||
300 |
3/4✓ Branch 0 (15→16) taken 79 times.
✗ Branch 1 (15→20) not taken.
✓ Branch 2 (16→17) taken 54 times.
✓ Branch 3 (16→20) taken 25 times.
|
79 | if (line.length > spaces && line.data[spaces] == '*') { |
301 | // '*' after indent, could be long C style comment | ||
302 |
4/4✓ Branch 0 (17→18) taken 36 times.
✓ Branch 1 (17→19) taken 18 times.
✓ Branch 2 (18→19) taken 18 times.
✓ Branch 3 (18→20) taken 18 times.
|
54 | if (spaces & 1 || allow_odd_indent(indents_bitmask)) { |
303 | 36 | return spaces - 1; | |
304 | } | ||
305 | } | ||
306 | 43 | return spaces; | |
307 | } | ||
308 | |||
309 | 18 | UNITTEST { | |
310 | 18 | bool tab; | |
311 | 18 | int len = indent_len(strview_from_cstring(" 4 space"), 0, &tab); | |
312 | 18 | BUG_ON(len != 4); | |
313 | 18 | BUG_ON(tab); | |
314 | |||
315 | 18 | len = indent_len(strview_from_cstring("\t\t2 tab"), 0, &tab); | |
316 | 18 | BUG_ON(len != 16); | |
317 | 18 | BUG_ON(!tab); | |
318 | |||
319 | 18 | len = indent_len(strview_from_cstring("no indent"), 0, &tab); | |
320 | 18 | BUG_ON(len != 0); | |
321 | |||
322 | 18 | len = indent_len(strview_from_cstring(" \t mixed"), 0, &tab); | |
323 | 18 | BUG_ON(len != -2); | |
324 | |||
325 | 18 | len = indent_len(strview_from_cstring("\t \t "), 0, &tab); | |
326 | 18 | BUG_ON(len != -1); // whitespace only | |
327 | |||
328 | 18 | len = indent_len(strview_from_cstring(" * 5 space"), 0, &tab); | |
329 | 18 | BUG_ON(len != 4); | |
330 | |||
331 | 18 | StringView line = strview_from_cstring(" * 4 space"); | |
332 | 18 | len = indent_len(line, 0, &tab); | |
333 | 18 | BUG_ON(len != 4); | |
334 | 18 | len = indent_len(line, 1 << 2, &tab); | |
335 | 18 | BUG_ON(len != 3); | |
336 | 18 | } | |
337 | |||
338 | 3 | static bool detect_indent(Buffer *buffer) | |
339 | { | ||
340 | 3 | LocalOptions *options = &buffer->options; | |
341 | 3 | unsigned int bitset = options->detect_indent; | |
342 | 3 | BlockIter bi = block_iter(buffer); | |
343 | 3 | unsigned int tab_count = 0; | |
344 | 3 | unsigned int space_count = 0; | |
345 | 3 | int current_indent = 0; | |
346 | 3 | int counts[INDENT_WIDTH_MAX + 1] = {0}; | |
347 | 3 | BUG_ON((bitset & ((1u << INDENT_WIDTH_MAX) - 1)) != bitset); | |
348 | |||
349 |
2/2✓ Branch 0 (19→4) taken 19 times.
✓ Branch 1 (19→20) taken 3 times.
|
22 | for (size_t i = 0, j = 1; i < 200 && j > 0; i++, j = block_iter_next_line(&bi)) { |
350 | 19 | StringView line = block_iter_get_line(&bi); | |
351 | 19 | bool tab; | |
352 | 19 | int indent = indent_len(line, bitset, &tab); | |
353 |
3/3✓ Branch 0 (6→7) taken 2 times.
✓ Branch 1 (6→8) taken 10 times.
✓ Branch 2 (6→9) taken 7 times.
|
19 | switch (indent) { |
354 | 2 | case -2: // Ignore mixed indent because tab width might not be 8 | |
355 | case -1: // Empty line; no change in indent | ||
356 | 12 | continue; | |
357 | 10 | case 0: | |
358 | 10 | current_indent = 0; | |
359 | 10 | continue; | |
360 | } | ||
361 | |||
362 | 7 | BUG_ON(indent <= 0); | |
363 | 7 | int change = indent - current_indent; | |
364 |
2/2✓ Branch 0 (11→12) taken 3 times.
✓ Branch 1 (11→13) taken 4 times.
|
7 | if (change >= 1 && change <= INDENT_WIDTH_MAX) { |
365 | 3 | counts[change]++; | |
366 | } | ||
367 | |||
368 |
1/2✗ Branch 0 (13→14) not taken.
✓ Branch 1 (13→15) taken 7 times.
|
7 | if (tab) { |
369 | ✗ | tab_count++; | |
370 | } else { | ||
371 | 7 | space_count++; | |
372 | } | ||
373 | 7 | current_indent = indent; | |
374 | } | ||
375 | |||
376 |
1/2✓ Branch 0 (20→21) taken 3 times.
✗ Branch 1 (20→30) not taken.
|
3 | if (tab_count == 0 && space_count == 0) { |
377 | return false; | ||
378 | } | ||
379 | |||
380 |
1/2✗ Branch 0 (21→22) not taken.
✓ Branch 1 (21→27) taken 3 times.
|
3 | if (tab_count > space_count) { |
381 | ✗ | options->emulate_tab = false; | |
382 | ✗ | options->expand_tab = false; | |
383 | ✗ | options->indent_width = options->tab_width; | |
384 | ✗ | return true; | |
385 | } | ||
386 | |||
387 | size_t m = 0; | ||
388 |
2/2✓ Branch 0 (27→23) taken 24 times.
✓ Branch 1 (27→28) taken 3 times.
|
27 | for (size_t i = 1; i < ARRAYLEN(counts); i++) { |
389 | 24 | unsigned int bit = 1u << (i - 1); | |
390 |
4/4✓ Branch 0 (23→24) taken 9 times.
✓ Branch 1 (23→26) taken 15 times.
✓ Branch 2 (24→25) taken 3 times.
✓ Branch 3 (24→26) taken 6 times.
|
24 | if ((bitset & bit) && counts[i] > counts[m]) { |
391 | 3 | m = i; | |
392 | } | ||
393 | } | ||
394 | |||
395 |
1/2✓ Branch 0 (28→29) taken 3 times.
✗ Branch 1 (28→30) not taken.
|
3 | if (m == 0) { |
396 | return false; | ||
397 | } | ||
398 | |||
399 | 3 | options->emulate_tab = true; | |
400 | 3 | options->expand_tab = true; | |
401 | 3 | options->indent_width = m; | |
402 | 3 | return true; | |
403 | } | ||
404 | |||
405 | 56 | void buffer_setup(EditorState *e, Buffer *buffer) | |
406 | { | ||
407 | 56 | const char *filename = buffer->abs_filename; | |
408 | 56 | buffer->setup = true; | |
409 | 56 | buffer_detect_filetype(buffer, &e->filetypes); | |
410 | 56 | set_file_options(e, buffer); | |
411 | 56 | set_editorconfig_options(buffer); | |
412 | 56 | buffer_update_syntax(e, buffer); | |
413 |
3/4✓ Branch 0 (6→7) taken 3 times.
✓ Branch 1 (6→9) taken 53 times.
✓ Branch 2 (7→8) taken 3 times.
✗ Branch 3 (7→9) not taken.
|
56 | if (buffer->options.detect_indent && filename) { |
414 | 3 | detect_indent(buffer); | |
415 | } | ||
416 | 56 | sanity_check_local_options(&e->err, &buffer->options); | |
417 | 56 | } | |
418 | |||
419 | 4 | void buffer_count_blocks_and_bytes(const Buffer *buffer, uintmax_t counts[2]) | |
420 | { | ||
421 | 4 | uintmax_t blocks = 0; | |
422 | 4 | uintmax_t bytes = 0; | |
423 | 4 | const Block *blk; | |
424 |
2/2✓ Branch 0 (4→3) taken 8 times.
✓ Branch 1 (4→5) taken 4 times.
|
12 | block_for_each(blk, &buffer->blocks) { |
425 | 8 | blocks += 1; | |
426 | 8 | bytes += blk->size; | |
427 | } | ||
428 | 4 | counts[0] = blocks; | |
429 | 4 | counts[1] = bytes; | |
430 | 4 | } | |
431 |