File Coverage

Config.xs
Criterion Covered Total %
statement 64 67 95.5
branch 89 120 74.1
condition n/a
subroutine n/a
pod n/a
total 153 187 81.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             /* prototypes */
18             SV* _parse_string_field(SV *sv, int need_field);
19              
20 49           SV* _parse_string_field(SV *sv, int need_field) {
21 49           int len = SvCUR(sv);
22 49           char *ptr = (char *) SvPVX_const(sv); /* todo: preserve the const state of the pointer */
23             AV *av;
24             char *start_key, *end_key;
25             char *start_val, *end_val;
26             char *max;
27              
28 49           int is_utf8 = SvUTF8(sv);
29              
30 49           av = newAV();
31              
32 49           const char eol = '\n';
33 49           const char sep = ':'; /* customize it later */
34 49           const char comment = '#';
35 49           const char line_feed = '\r';
36              
37 49           start_key = ptr;
38 49           end_key = 0;
39 49           start_val = 0;
40 49           end_val = 0;
41              
42 49           int found_eol = 1;
43 49           int found_comment = 0;
44 49           int found_sep = 0;
45 49           int found_field = 0;
46              
47 6828 100         for ( max = ptr + len ; ptr < max; ++ptr ) {
48 6779 100         if ( ! *ptr ) continue; /* skip \0 so we can parse binaries strings */
49 6778 100         if ( *ptr == line_feed ) continue; /* ignore \r */
50              
51             //printf( "# %c\n", *ptr );
52              
53             /* skip all characters in a comment block */
54 6742 100         if ( found_comment ) {
55 522 100         if ( *ptr == eol ) found_comment = 0;
56 522           continue;
57             }
58              
59 6220 100         if ( (need_field == 0 && found_sep) || (need_field && found_sep == need_field) ) {
    100          
    100          
    100          
60 215 100         if ( *ptr == ' ' || *ptr == '\t' ) continue;
    50          
61 198 100         if (need_field == 0) found_sep = 0;
62 98           else ++found_sep; /* moving it away */
63 198           end_val = start_val = ptr;
64 198           found_field = 0;
65             }
66              
67             /* get to the first valuable char of the line */
68 6203 100         if ( found_eol ) { /* starting a line */
69             /* spaces at the beginning of a line */
70 331 50         if ( *ptr == ' ' || *ptr == '\t' || *ptr == line_feed )
    50          
    50          
71 0           continue;
72 331 100         if ( *ptr == comment ) {
73 36           found_comment = 1;
74 36           continue;
75             }
76             /* we have a real character to start the line */
77 295           found_eol = 0;
78 295           start_key = ptr;
79 295           end_key = 0;
80 295           end_val = 0;
81 295           found_sep = 0;
82 295           start_val = 0;
83 295           found_field = 0;
84             }
85              
86 6167 100         if ( *ptr == sep ) {
87             //printf ("# separator key/value\n" );
88 990 100         if (need_field) ++found_sep;
89 990 100         if ( !end_key ) {
90 234           end_key = ptr;
91 234 100         if ( !need_field) found_sep = 1;
92             }
93              
94 990 100         if ( need_field && found_sep == need_field + 2 ) {
    100          
95 80           end_val = ptr;
96 990           found_field = 1;
97             }
98              
99 5177 100         } else if ( *ptr == eol ) { /* only handle the line once we reach a \n */
100              
101             #define __PARSE_STRING_LINE_FIELD /* reuse code for the last line */ \
102             if ( ( need_field == 0 || found_field == 0) && end_val == start_val) end_val = ptr; \
103             if (end_val && *end_val == line_feed) end_val = ptr - 1; \
104             found_eol = 1; \
105             \
106             /* check if we got a key */ \
107             if ( end_key > start_key ) { \
108             /* we got a key */ \
109             av_push(av, newSVpvn_flags( start_key, (int) (end_key - start_key), is_utf8 )); \
110             \
111             /* remove the line_feed chars if any */ \
112             while ( start_val && end_val > start_val && \
113             ( ( *(end_val - 1) == line_feed ) || ( *(end_val - 1) == ' ' ) || ( *(end_val - 1) == '\t' ) ) \
114             ) { \
115             --end_val; \
116             } \
117             /* only add the value if we have a key */ \
118             if ( start_val && ( (int ) ( end_val - start_val ) ) ) { \
119             av_push(av, newSVpvn_flags( start_val, (int) (end_val - start_val), is_utf8 )); \
120             } else { \
121             av_push(av, &PL_sv_undef); \
122             } \
123             } \
124             /* end of __PARSE_STRING_LINE_FIELD */
125              
126 284 100         __PARSE_STRING_LINE_FIELD
    100          
    50          
    50          
    50          
    100          
    100          
    100          
    100          
    100          
    50          
    100          
    100          
127              
128 277           start_key = 0;
129             }
130              
131             } /* end main for loop for *ptr */
132              
133             /* handle the last entry */
134 49 100         if ( start_key ) {
135 18 50         __PARSE_STRING_LINE_FIELD
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
136             }
137              
138 49           return (SV*) (newRV_noinc((SV*) av));
139             }
140              
141             MODULE = Colon__Config PACKAGE = Colon::Config
142              
143             SV*
144             read(sv, ...)
145             SV *sv;
146             CODE:
147 99 50         if ( sv && SvPOK(sv) ) {
    50          
148 50           int field = 0;
149 50 100         if ( items > 2 )
150 1           Perl_croak( "Too many arguments when calling 'Config::Colon::read'." );
151 49 100         if ( items == 2 ) {
152 25           SV *sv_field = ST(1);
153 25 50         if ( !SvOK(sv_field) || !SvIOK(sv_field) )
    0          
    0          
    50          
154 0           Perl_croak( "Config::Colon::read - Second argument must be one integer." );
155 25 50         field = SvIV(sv_field);
156             }
157 49           RETVAL = _parse_string_field( sv, field );
158             } else {
159 0           RETVAL = &PL_sv_undef;
160             }
161             OUTPUT:
162             RETVAL
163