7 bool text_range_valid(const Filerange
*r
) {
8 return r
->start
!= EPOS
&& r
->end
!= EPOS
&& r
->start
<= r
->end
;
11 size_t text_range_size(const Filerange
*r
) {
12 return text_range_valid(r
) ? r
->end
- r
->start
: 0;
15 Filerange
text_range_empty(void) {
16 return (Filerange
){ .start
= EPOS
, .end
= EPOS
};
19 Filerange
text_range_union(const Filerange
*r1
, const Filerange
*r2
) {
20 if (!text_range_valid(r1
))
22 if (!text_range_valid(r2
))
25 .start
= MIN(r1
->start
, r2
->start
),
26 .end
= MAX(r1
->end
, r2
->end
),
30 Filerange
text_range_new(size_t a
, size_t b
) {
37 bool text_range_equal(const Filerange
*r1
, const Filerange
*r2
) {
38 if (!text_range_valid(r1
) && !text_range_valid(r2
))
40 return r1
->start
== r2
->start
&& r1
->end
== r2
->end
;
43 bool text_range_overlap(const Filerange
*r1
, const Filerange
*r2
) {
44 if (!text_range_valid(r1
) || !text_range_valid(r2
))
46 return r1
->start
<= r2
->end
&& r2
->start
<= r1
->end
;
49 bool text_range_contains(const Filerange
*r
, size_t pos
) {
50 return text_range_valid(r
) && r
->start
<= pos
&& pos
<= r
->end
;
53 int text_char_count(const char *data
, size_t len
) {
58 size_t wclen
= mbrtowc(&wc
, data
, len
, &ps
);
59 if (wclen
== (size_t)-1 && errno
== EILSEQ
) {
61 while (!ISUTF8(*data
))
63 } else if (wclen
== (size_t)-2) {
65 } else if (wclen
== 0) {
70 int width
= wcwidth(wc
);
80 int text_string_width(const char *data
, size_t len
) {
88 size_t wclen
= mbrtowc(&wc
, s
, len
, &ps
);
89 if (wclen
== (size_t)-1 && errno
== EILSEQ
) {
90 /* assume a replacement symbol will be displayed */
93 } else if (wclen
== (size_t)-2) {
94 /* do nothing, advance to next character */
96 } else if (wclen
== 0) {
97 /* assume NUL byte will be displayed as ^@ */
100 } else if (wc
== L
'\t') {
106 w
= 2; /* assume non-printable will be displayed as ^{char} */