File Coverage

Replace.xs
Criterion Covered Total %
statement 59 60 98.3
branch 46 60 76.6
condition n/a
subroutine n/a
pod n/a
total 105 120 87.5


line stmt bran cond sub pod time code
1             /*
2             *
3             * Copyright (c) 2018, cPanel, LLC.
4             * All rights reserved.
5             * http://cpanel.net
6             *
7             * This is free software; you can redistribute it and/or modify it under the
8             * same terms as Perl itself.
9             *
10             */
11              
12             #include
13             #include
14             #include
15             #include
16              
17             #define _REPLACE_BUFFER_SIZE 64
18              
19             #define IS_SPACE(c) c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == '\f'
20              
21             SV *_replace_str( SV *sv, SV *map );
22             SV *_trim_sv( SV *sv );
23              
24 13           SV *_trim_sv( SV *sv ) {
25              
26 13           int len = SvCUR(sv);
27 13           char *str = SvPVX(sv);;
28 13           char *end = str + len - 1;
29              
30             // Skip whitespace at front...
31 32 100         while ( IS_SPACE( (unsigned char) *str) ) {
    100          
    100          
    100          
    100          
32 19           ++str;
33 19           --len;
34             }
35              
36             // Trim at end...
37 32 50         while (end > str && isspace( (unsigned char) *end) ) {
    100          
38 19           *end--;// = 0;
39 19           --len;
40             }
41              
42 13           return newSVpvn_flags( str, len, SvUTF8(sv) );
43             }
44              
45              
46 10           SV *_replace_str( SV *sv, SV *map ) {
47 10           char buffer[_REPLACE_BUFFER_SIZE] = { 0 };
48 10           char *src = SvPVX(sv);
49 10           int len = SvCUR(sv);
50 10           int i = 0;
51 10           char *ptr = src;
52 10           char *str = buffer; /* the new string we are going to use */
53             char *tmp; /* used to grow */
54 10           int str_size = _REPLACE_BUFFER_SIZE; /* we start with the buffer */
55 10           int ix_newstr = 0;
56             AV *mapav;
57             SV *reply;
58              
59 10 50         if ( !map || SvTYPE(map) != SVt_RV || SvTYPE(SvRV(map)) != SVt_PVAV
    100          
    50          
    50          
60 9 0         || AvFILL( SvRV(map) ) <= 0
    100          
61             ) {
62 2           return newSVpv( src, len ); /* no alteration */
63             }
64              
65 8           mapav = (AV *)SvRV(map);
66 8           SV **ary = AvARRAY(mapav);
67              
68              
69 380 100         for ( i = 0; i < len; ++i, ++ptr, ++ix_newstr ) {
70 372           char c = *ptr;
71 372           int ix = (int) ( c );
72 372 100         if ( ix < 0 ) ix = 256 + ix;
73             // need to croak in DEBUG mode if char is invalid
74              
75 372           str[ix_newstr] = c; /* default always performed... */
76 372 50         if ( ix >= AvFILL(mapav) || !AvARRAY(mapav)[ix] ) {
    100          
    50          
77 1           continue;
78             } else {
79 371           SV *entry = AvARRAY(mapav)[ix];
80 371 50         if ( SvPOK( entry ) ) {
81 371           int slen = SvCUR( entry ); /* length of the string used for replacement */
82 371 50         if ( slen <= 0 ) {
83 0           continue;
84             } else {
85 371           char *replace = SvPVX( entry );
86 371           int j = 0;
87              
88             /* Check if we need to expand. */
89 371 100         if (str_size <= (ix_newstr + slen + 1) ) { /* +1 for \0 */
90             //printf( "neew to grow %d -> %d\n", str_size, ix_newstr + slen );
91 4           str_size *= 2;
92              
93 4 100         if ( str == buffer ) {
94             /* our first malloc */
95 2 50         Newx(str, str_size, char*);
96 2           strncpy( str, buffer, ix_newstr );
97             } else {
98             /* grow the string */
99 2           tmp = Perl_realloc( str, str_size );
100 2 50         if ( !tmp ) Perl_croak(aTHX_ "failed to realloc string" );
101 2           str = tmp;
102             }
103             }
104              
105             /* replace all characters except the last one, which avoids us to do a --ix_newstr after */
106 496 100         for ( ; j < slen - 1; ++j ) {
107 125           str[ix_newstr++] = replace[j];
108             }
109             /* handle the last character */
110 371           str[ix_newstr] = replace[j];
111             }
112             } /* end - SvPOK */
113             } /* end - AvFILL || AvARRAY */
114             }
115              
116 8           str[ix_newstr] = '\0'; /* add the final trailing \0 character */
117 8           reply = newSVpvn_flags( str, ix_newstr, SvUTF8(sv) );
118            
119             /* free our tmp buffer if needed */
120 8 100         if ( str != buffer ) free(str);
121              
122 10           return reply;
123             }
124              
125             MODULE = Char__Replace PACKAGE = Char::Replace
126              
127             SV*
128             replace(sv, map)
129             SV *sv;
130             SV *map;
131             CODE:
132 13 50         if ( sv && SvPOK(sv) ) {
    100          
133 10           RETVAL = _replace_str( sv, map );
134             } else {
135 3           RETVAL = &PL_sv_undef;
136             }
137             OUTPUT:
138             RETVAL
139              
140             SV*
141             trim(sv)
142             SV *sv;
143             CODE:
144 16 50         if ( sv && SvPOK(sv) ) {
    100          
145 13           RETVAL = _trim_sv( sv );
146             } else {
147 3           RETVAL = &PL_sv_undef;
148             }
149             OUTPUT:
150             RETVAL