File Coverage

normalize.xs
Criterion Covered Total %
statement 88 104 84.6
branch 34 66 51.5
condition n/a
subroutine n/a
pod n/a
total 122 170 71.7


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             #include "ppport.h"
6             #include
7             #include
8              
9             typedef enum {
10             NFC,
11             NFD,
12             NFKC,
13             NFKD,
14             FCD,
15             FCC,
16             } normalization;
17              
18             typedef struct {
19             PerlIOBuf buf;
20             SV *data;
21             normalization norm;
22             } PerlIOnormalize;
23              
24             normalization
25 12           parse_parameters(pTHX_ SV* param)
26             {
27             STRLEN len;
28             const char* begin;
29 12 50         if (param && SvOK(param)) {
    50          
    0          
    0          
30 12 50         begin = SvPV(param, len);
31 12 50         if (len) {
32 12 100         if (strncmp(begin, "NFC", len) == 0) { return NFC; }
33 8 100         if (strncmp(begin, "NFD", len) == 0) { return NFD; }
34 4 100         if (strncmp(begin, "NFKC", len) == 0) { return NFKC; }
35 2 50         if (strncmp(begin, "NFKD", len) == 0) { return NFKD; }
36 0 0         if (strncmp(begin, "FCD", len) == 0) { return FCD; }
37 0 0         if (strncmp(begin, "FCC", len) == 0) { return FCC; }
38             }
39             }
40              
41 12           Perl_croak(aTHX_ ":normalize requires an argument of NFC, NFD, NFKC, NFKD, FCD, or FCC.");
42             }
43              
44             IV
45 12           PerlIOnormalize_pushed(pTHX_ PerlIO* f, const char* mode, SV* arg, PerlIO_funcs *tab)
46             {
47 12           normalization norm = parse_parameters(aTHX_ arg);
48 12 50         if (PerlIOBuf_pushed(aTHX_ f, mode, arg, tab) == 0) {
49 12           PerlIOBase(f)->flags |= PERLIO_F_UTF8;
50 12           PerlIOSelf(f, PerlIOnormalize)->norm = norm;
51 12           return 0;
52             }
53 0           return -1;
54             }
55              
56             STRLEN
57 12           do_normalize(pTHX_ normalization norm, SV *input, char **out) {
58 12           dSP;
59             SV *nf, *output;
60 12           char *temp = NULL;
61 12           STRLEN len = 0;
62              
63 12           switch(norm) {
64 4           case NFC: nf = newSVpvn("NFC", 3); break;
65 4           case NFD: nf = newSVpvn("NFD", 3); break;
66 2           case NFKC: nf = newSVpvn("NFKC", 4); break;
67 2           case NFKD: nf = newSVpvn("NFKD", 4); break;
68 0           case FCD: nf = newSVpvn("FCD", 3); break;
69 0           case FCC: nf = newSVpvn("FCC", 3); break;
70 0           default: Perl_croak(aTHX_ "Unknown normalization form %d", norm); break;
71             }
72              
73 12           ENTER;
74 12           SAVETMPS;
75              
76 12 50         PUSHMARK(sp);
77 12 50         XPUSHs(nf);
78 12 50         XPUSHs(input);
79 12           PUTBACK;
80              
81 12 50         if (call_pv("Unicode::Normalize::normalize", G_SCALAR) != 1) {
82 0           Perl_croak(aTHX_ "normalize returned nothing");
83             }
84 12           SPAGAIN;
85              
86 12           output = POPs;
87 12 50         if (SvPOK(output)) {
88 12 50         temp = SvPVutf8(output, len);
89             }
90              
91 12           *out = (char *)malloc(len);
92 12 50         if (*out == NULL) {
93 0           Perl_croak(aTHX_ "Could not allocate memory for return value of normalization");
94             }
95 12           memcpy(*out, temp, len);
96              
97 12 50         if (len <= 0) {
98 0           Perl_croak(aTHX_ "normalize returned an empty string");
99             }
100              
101 12           PUTBACK;
102 12 50         FREETMPS;
103 12           LEAVE;
104              
105 12           return len;
106             }
107              
108             IV
109 12           PerlIOnormalize_fill(pTHX_ PerlIO *f)
110             {
111 12           PerlIO *nx = PerlIONext(f);
112             SSize_t avail;
113              
114             /* make sure we have a buffer layer */
115 12 50         if (!PerlIO_fast_gets(nx)) {
116             char mode[8];
117 0           nx = PerlIO_push(aTHX_ nx, &PerlIO_perlio, PerlIO_modestr(f,mode), Nullsv);
118 0 0         if (!nx) {
119 0           Perl_croak(aTHX_ "cannot push :perlio for %p", f);
120             }
121             }
122              
123 12           avail = PerlIO_get_cnt(nx);
124 12 100         if (avail <= 0) {
125 6           avail = PerlIO_fill(nx);
126 6 50         if (avail == 0) {
127 0           avail = PerlIO_get_cnt(nx);
128             } else {
129 6 50         if (!PerlIO_error(nx) && PerlIO_eof(nx)) {
    50          
130 6           avail = 0;
131             }
132             }
133             }
134              
135 12 100         if (avail > 0) {
136 6           PerlIOnormalize *nz = PerlIOSelf(f, PerlIOnormalize);
137 6           STDCHAR *ptr = PerlIO_get_ptr(nx);
138             SV *input;
139             char *out;
140 6           STRLEN len = 0;
141              
142 6           nz->buf.ptr = nz->buf.end = (STDCHAR *) NULL;
143 6           input = newSVpvn(ptr, avail);
144 6           SvUTF8_on(input);
145              
146 6           len = do_normalize(aTHX_ nz->norm, input, &out);
147              
148 6           nz->data = newSVpvn(out,len);
149 6           free(out);
150              
151 6           nz->buf.ptr = nz->buf.buf = (STDCHAR*)SvPVX(nz->data);
152 6           nz->buf.end = nz->buf.ptr + SvCUR(nz->data);
153 6           PerlIOBase(f)->flags |= PERLIO_F_RDBUF;
154 6           SvUTF8_on(nz->data);
155              
156 6           PerlIO_set_ptrcnt(nx, ptr+avail, 0);
157              
158 6           return 0;
159             }
160            
161 6 50         if (avail == 0) {
162             /* EOF reached */
163 6           PerlIOBase(f)->flags |= PERLIO_F_EOF;
164             } else {
165 0           PerlIOBase(f)->flags |= PERLIO_F_ERROR;
166 0           Perl_PerlIO_save_errno(aTHX_ f);
167             }
168              
169 6           return -1;
170             }
171              
172             IV
173 12           PerlIOnormalize_flush(pTHX_ PerlIO *f)
174             {
175 12           PerlIOnormalize *nz = PerlIOSelf(f, PerlIOnormalize);
176              
177 12 100         if ((PerlIOBase(f)->flags & PERLIO_F_WRBUF) && (nz->buf.ptr > nz->buf.buf)) {
    50          
178 6           PerlIO *nx = PerlIONext(f);
179 6           STDCHAR *ptr = nz->buf.buf;
180 6           Size_t avail = nz->buf.ptr - nz->buf.buf;
181             SV *input;
182             char *out;
183 6           STRLEN len = 0;
184 6           SSize_t count = 0;
185              
186 6           input = newSVpvn(ptr, avail);
187 6           SvUTF8_on(input);
188              
189 6           len = do_normalize(aTHX_ nz->norm, input, &out);
190              
191 6           count = PerlIO_write(nx, out, len);
192 6           free(out);
193              
194 6 50         if ((STRLEN)count != len) {
195 0           return -1;
196             }
197              
198 6           return 0;
199             }
200            
201 6           return PerlIOBuf_flush(aTHX_ f);
202             }
203              
204             PerlIO_funcs PerlIO_normalize = {
205             sizeof(PerlIO_funcs),
206             "normalize",
207             sizeof(PerlIOnormalize),
208             PERLIO_K_BUFFERED | PERLIO_K_UTF8,
209             PerlIOnormalize_pushed,
210             PerlIOBuf_popped, /* IV PerlIOnormalize_popped */
211             PerlIOBuf_open,
212             PerlIOBase_binmode,
213             NULL,
214             PerlIOBase_fileno,
215             PerlIOBuf_dup,
216             PerlIOBuf_read, /* SSize_t PerlIOnormalize_read */
217             PerlIOBuf_unread, /* SSize_t PerlIOnormalize_unread */
218             PerlIOBuf_write, /* SSize_t PerlIOnormalize_write */
219             PerlIOBuf_seek,
220             PerlIOBuf_tell,
221             PerlIOBuf_close,
222             PerlIOnormalize_flush,
223             PerlIOnormalize_fill,
224             PerlIOBase_eof,
225             PerlIOBase_error,
226             PerlIOBase_clearerr,
227             PerlIOBase_setlinebuf,
228             PerlIOBuf_get_base,
229             PerlIOBuf_bufsiz,
230             PerlIOBuf_get_ptr,
231             PerlIOBuf_get_cnt,
232             PerlIOBuf_set_ptrcnt,
233             };
234              
235             MODULE = PerlIO::normalize PACKAGE = PerlIO::normalize
236              
237             PROTOTYPES: DISABLE
238              
239             BOOT:
240 1           PerlIO_define_layer(aTHX_ &PerlIO_normalize);