File Coverage

XS.xs
Criterion Covered Total %
statement 77 98 78.5
branch 37 62 59.6
condition n/a
subroutine n/a
pod n/a
total 114 160 71.2


line stmt bran cond sub pod time code
1             #define PERL_NO_GET_CONTEXT
2             #include "EXTERN.h"
3             #include "perl.h"
4             #include "XSUB.h"
5              
6             #ifdef AMBIGUOUS_WIDTH_IS_WIDE
7             #include "charwidth_ambiguous_is_wide.h"
8             #else
9             #include "charwidth_default.h"
10             #endif
11              
12              
13 209           static int _char_width(UV codepoint) {
14 209 100         if (codepoint < width_table[0].start) {
15 93           return 1;
16             }
17              
18 116           int min = 0;
19 116           int max = width_table_len - 1;
20             int mid;
21              
22 116 50         if (codepoint > width_table[max].end) {
23 0           return 1;
24             }
25              
26 1071 50         while (max >= min) {
27 1071           mid = (min + max) / 2;
28 1071 100         if (codepoint > width_table[mid].end) {
29 589           min = mid + 1;
30 482 100         } else if (codepoint < width_table[mid].start) {
31 366           max = mid - 1;
32             } else {
33 116           return width_table[mid].width;
34             }
35             }
36 0           return 1;
37             }
38              
39              
40             MODULE = Term::Choose::LineFold::XS PACKAGE = Term::Choose::LineFold::XS
41              
42             PROTOTYPES: DISABLE
43              
44              
45             int
46             char_width(UV codepoint)
47             CODE:
48 12           RETVAL = _char_width(codepoint);
49             OUTPUT:
50             RETVAL
51              
52              
53              
54             SV *
55             print_columns(SV *input)
56             PREINIT:
57             STRLEN len;
58             const U8 *p, *end;
59             UV codepoint;
60 12 50         int width = 0;
61             STRLEN clen;
62             CODE:
63 12 50         if (!SvOK(input)) {
64 0           XSRETURN_UNDEF;
65             }
66 12 50         if (!SvPOK(input)) {
67 0           input = sv_mortalcopy(input); // Ensure string
68 0           SvPV_force(input, len);
69             }
70 12           p = (const U8 *) SvPVutf8(input, len);
71 12           end = p + len;
72              
73 80 100         while (p < end) {
74 68           codepoint = utf8_to_uvchr_buf(p, end, &clen);
75 68 50         if (clen == -1 ) {
76 0           codepoint = *p; // Interpret the invalid byte as a single character
77 0           clen = 1; // Advance by 1 byte
78             }
79 68           p += clen;
80 68           width += _char_width(codepoint);
81             }
82              
83 12           RETVAL = newSViv(width);
84             OUTPUT:
85             RETVAL
86              
87              
88              
89             SV*
90             cut_to_printwidth(SV *input, int max_width)
91             PREINIT:
92             STRLEN len;
93             const U8 *p, *end;
94 20           const U8 *split_point = NULL;
95             const U8 *char_start;
96             UV codepoint;
97 20           int str_w = 0, this_w;
98             STRLEN clen;
99             // bool skip_padding;
100             PPCODE:
101 20 50         if (!SvOK(input)) {
102 0           XSRETURN_UNDEF;
103             }
104              
105 20 50         if (!SvPOK(input)) {
106 0           input = sv_mortalcopy(input);
107 0           SvPV_force(input, len);
108             }
109              
110 20           const U8 *start = (const U8 *) SvPVutf8(input, len);
111 20           p = start;
112 20           end = p + len;
113              
114 66 50         while (p < end) {
115 66           char_start = p;
116 66           codepoint = utf8_to_uvchr_buf(p, end, &clen);
117              
118 66 50         if (clen == -1) {
119 0           codepoint = *p;
120 0           clen = 1;
121             }
122              
123 66           this_w = _char_width(codepoint);
124              
125 66 100         if (str_w + this_w > max_width) {
126 20           split_point = char_start;
127 20           break;
128             }
129              
130 46           str_w += this_w;
131 46           p += clen;
132             }
133              
134 20 50         if (!split_point) {
135             // Whole string fits
136 0 0         if (GIMME_V == G_ARRAY) {
137 0 0         XPUSHs(sv_2mortal(newSVsv(input)));
138 0 0         XPUSHs(sv_2mortal(newSVpvn("", 0)));
139             } else {
140 0 0         XPUSHs(sv_2mortal(newSVsv(input)));
141             }
142             } else {
143 20           STRLEN first_len = split_point - start;
144 20           SV *first_part = newSVpvn((const char *)start, first_len);
145 20           SvUTF8_on(first_part);
146              
147 20 100         if (str_w == max_width - 1) {
148 6           sv_catpv(first_part, " ");
149 6           str_w += 1;
150             }
151              
152 20 100         if (GIMME_V == G_ARRAY) {
153 10           STRLEN rest_len = end - split_point;
154 10           SV *rest_part = newSVpvn((const char *)split_point, rest_len);
155 10           SvUTF8_on(rest_part);
156              
157 10 50         XPUSHs(sv_2mortal(first_part));
158 10 50         XPUSHs(sv_2mortal(rest_part));
159             } else {
160 10 50         XPUSHs(sv_2mortal(first_part));
161             }
162             }
163              
164              
165              
166             SV *
167             adjust_to_printwidth(SV *input, int width)
168             PREINIT:
169             STRLEN len;
170             const U8 *p, *end;
171             UV codepoint;
172 17           int str_w = 0, this_w;
173             STRLEN clen;
174             SV *result;
175             const U8 *start;
176             CODE:
177 17 50         if (!SvOK(input)) {
178 0           XSRETURN_UNDEF;
179             }
180              
181 17 50         if (!SvPOK(input)) {
182 0           input = sv_mortalcopy(input);
183 0           SvPV_force(input, len);
184             }
185              
186 17           p = (const U8 *) SvPVutf8(input, len); // len is char length
187 17           end = p + len;
188 17           start = p;
189              
190 70 100         while (p < end) {
191 63           codepoint = utf8_to_uvchr_buf(p, end, &clen);
192 63 50         if (clen == (STRLEN)-1) {
193 0           codepoint = *p;
194 0           clen = 1;
195             }
196              
197 63           this_w = _char_width(codepoint);
198 63 100         if (str_w + this_w > width) {
199 10           break;
200             }
201              
202 53           str_w += this_w;
203 53           p += clen;
204             }
205              
206 17           len = (STRLEN)(p - start); // now len is byte length
207              
208 17 100         if (str_w == width) {
209 7           RETVAL = newSVpvn((const char *)start, len);
210             } else {
211 10           result = newSVpvn((const char *)start, len);
212 10           sv_catpvf(result, "%*s", width - str_w, "");
213 10           RETVAL = result;
214             }
215              
216 17           SvUTF8_on(RETVAL);
217             OUTPUT:
218             RETVAL
219