File Coverage

Replace.xs
Criterion Covered Total %
statement 43 44 97.7
branch 30 42 71.4
condition n/a
subroutine n/a
pod n/a
total 73 86 84.8


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             SV *_replace_str( char *src, int len, SV *map );
20              
21 8           SV *_replace_str( char *src, int len, SV *map ) {
22 8           char buffer[_REPLACE_BUFFER_SIZE] = { 0 };
23              
24 8           int i = 0;
25 8           char *ptr = src;
26 8           char *str = buffer; /* the new string we are going to use */
27             char *tmp; /* used to grow */
28 8           int str_size = _REPLACE_BUFFER_SIZE; /* we start with the buffer */
29 8           int ix_newstr = 0;
30             AV *mapav;
31             SV *reply;
32              
33            
34 8 50         if ( !map || SvTYPE(map) != SVt_RV || SvTYPE(SvRV(map)) != SVt_PVAV
    100          
    50          
    50          
35 7 0         || AvFILL( SvRV(map) ) <= 0
    100          
36             ) {
37 2           return newSVpv( src, len ); /* no alteration */
38             }
39              
40 6           mapav = (AV *)SvRV(map);
41 6           SV **ary = AvARRAY(mapav);
42              
43              
44 366 100         for ( i = 0; i < len; ++i, ++ptr, ++ix_newstr ) {
45 360           char c = *ptr;
46 360           int ix = (int) ( c );
47 360 100         if ( ix < 0 ) ix = 256 + ix;
48             // need to croak in DEBUG mode if char is invalid
49              
50 360           str[ix_newstr] = c; /* default always performed... */
51 360 50         if ( ix >= AvFILL(mapav) || !AvARRAY(mapav)[ix] ) {
    100          
    50          
52 1           continue;
53             } else {
54 359           SV *entry = AvARRAY(mapav)[ix];
55 359 50         if ( SvPOK( entry ) ) {
56 359           int slen = SvCUR( entry ); /* length of the string used for replacement */
57 359 50         if ( slen <= 0 ) {
58 0           continue;
59             } else {
60 359           char *replace = SvPVX( entry );
61 359           int j = 0;
62              
63             /* Check if we need to expand. */
64 359 100         if (str_size <= (ix_newstr + slen + 1) ) { /* +1 for \0 */
65             //printf( "neew to grow %d -> %d\n", str_size, ix_newstr + slen );
66 4           str_size *= 2;
67              
68 4 100         if ( str == buffer ) {
69             /* our first malloc */
70 2 50         Newx(str, str_size, char*);
71 2           strncpy( str, buffer, ix_newstr );
72             } else {
73             /* grow the string */
74 2           tmp = Perl_realloc( str, str_size );
75 2 50         if ( !tmp ) Perl_croak(aTHX_ "failed to realloc string" );
76 2           str = tmp;
77             }
78             }
79              
80             /* replace all characters except the last one, which avoids us to do a --ix_newstr after */
81 480 100         for ( ; j < slen - 1; ++j ) {
82 121           str[ix_newstr++] = replace[j];
83             }
84             /* handle the last character */
85 359           str[ix_newstr] = replace[j];
86             }
87             } /* end - SvPOK */
88             } /* end - AvFILL || AvARRAY */
89             }
90              
91 6           str[ix_newstr] = '\0'; /* add the final trailing \0 character */
92 6           reply = newSVpv( str, ix_newstr );
93              
94             /* free our tmp buffer if needed */
95 6 100         if ( str != buffer ) free(str);
96              
97 8           return reply;
98             }
99              
100             MODULE = Char__Replace PACKAGE = Char::Replace
101              
102              
103             SV*
104             replace(str, map)
105             SV *str;
106             SV *map;
107             CODE:
108 11 50         if ( str && SvPOK(str) ) {
    100          
109 8           RETVAL = _replace_str( SvPVX(str), SvCUR(str), map );
110             } else {
111 3           RETVAL = &PL_sv_undef;
112             }
113             OUTPUT:
114             RETVAL