File Coverage

srl_path.c
Criterion Covered Total %
statement 224 229 97.8
branch 122 160 76.2
condition n/a
subroutine n/a
pod n/a
total 346 389 88.9


line stmt bran cond sub pod time code
1             /* Must be defined before including Perl header files or we slow down by 2x! */
2             #define PERL_NO_GET_CONTEXT
3              
4             #ifdef __cplusplus
5             extern "C" {
6             #endif
7             #include "EXTERN.h"
8             #include "perl.h"
9             #include "XSUB.h"
10             #include "ppport.h"
11             #ifdef __cplusplus
12             }
13             #endif
14              
15             #include
16             #include
17              
18             #ifndef PERL_VERSION
19             # include
20             # if !(defined(PERL_VERSION) || (PERL_SUBVERSION > 0 && defined(PATCHLEVEL)))
21             # include
22             # endif
23             # define PERL_REVISION 5
24             # define PERL_VERSION PATCHLEVEL
25             # define PERL_SUBVERSION PERL_SUBVERSION
26             #endif
27             #if PERL_VERSION < 8
28             # define PERL_MAGIC_qr 'r' /* precompiled qr// regex */
29             # define BFD_Svs_SMG_OR_RMG SVs_RMG
30             #elif ((PERL_VERSION==8) && (PERL_SUBVERSION >= 1) || (PERL_VERSION>8))
31             # define BFD_Svs_SMG_OR_RMG SVs_SMG
32             # define MY_PLACEHOLDER PL_sv_placeholder
33             #else
34             # define BFD_Svs_SMG_OR_RMG SVs_RMG
35             # define MY_PLACEHOLDER PL_sv_undef
36             #endif
37             #if (((PERL_VERSION == 9) && (PERL_SUBVERSION >= 4)) || (PERL_VERSION > 9))
38             # define NEW_REGEX_ENGINE 1
39             #endif
40             #if (((PERL_VERSION == 8) && (PERL_SUBVERSION >= 1)) || (PERL_VERSION > 8))
41             #define MY_CAN_FIND_PLACEHOLDERS
42             #define HAS_SV2OBJ
43             #endif
44              
45             #ifndef NDEBUG
46             # if DEBUG > 1
47             # define TRACE_READER 1
48             # define TRACE_SRL_PATH 1
49             # endif
50             #endif
51              
52             #include "srl_common.h"
53             #include "srl_inline.h"
54             #include "srl_protocol.h"
55             #include "srl_path.h"
56             #include "Iterator/srl_iterator.h"
57             #include "srl_reader_error.h"
58              
59             #ifdef TRACE_SRL_PATH
60             # define SRL_PATH_TRACE(msg, args...) \
61             fprintf(stderr, "%s:%d:%s(): "msg"\n", __FILE__, __LINE__, __func__, ## args)
62             #else
63             # define SRL_PATH_TRACE(msg, args...)
64             #endif
65              
66             #define CLEAR_RESULTS(p) STMT_START { \
67             if ((p)->results) { \
68             SvREFCNT_dec((p)->results); \
69             (p)->results = NULL; \
70             } \
71             } STMT_END
72              
73             #define CLEAR_ITERATOR(p) STMT_START { \
74             if ((p)->iter && (p)->i_own_iterator) { \
75             srl_destroy_iterator(aTHX_ p->iter); \
76             } \
77             } STMT_END
78              
79             SRL_STATIC_INLINE void srl_parse_next(pTHX_ srl_path_t *path, int expr_idx, SV *route);
80             SRL_STATIC_INLINE void srl_parse_next_int(pTHX_ srl_path_t *path, int expr_idx, SV *route, IV n);
81             SRL_STATIC_INLINE void srl_parse_next_str(pTHX_ srl_path_t *path, int expr_idx, SV *route,
82             const char *str, STRLEN len);
83              
84             SRL_STATIC_INLINE void srl_parse_hash(pTHX_ srl_path_t *path, int expr_idx, SV *route);
85             SRL_STATIC_INLINE void srl_parse_hash_all(pTHX_ srl_path_t *path, int expr_idx, SV *route);
86             SRL_STATIC_INLINE void srl_parse_hash_list(pTHX_ srl_path_t *path, int expr_idx, SV *route, const char *list, STRLEN list_len);
87             SRL_STATIC_INLINE void srl_parse_hash_item(pTHX_ srl_path_t *path, int expr_idx, SV *route, const char *str, STRLEN str_len);
88              
89             SRL_STATIC_INLINE void srl_parse_array(pTHX_ srl_path_t *path, int expr_idx, SV *route);
90             SRL_STATIC_INLINE void srl_parse_array_all(pTHX_ srl_path_t *path, int expr_idx, SV *route);
91             SRL_STATIC_INLINE void srl_parse_array_list(pTHX_ srl_path_t *path, int expr_idx, SV *route, const char *list, STRLEN list_len);
92             SRL_STATIC_INLINE void srl_parse_array_range(pTHX_ srl_path_t *path, int expr_idx, SV *route, int *range);
93             SRL_STATIC_INLINE void srl_parse_array_item(pTHX_ srl_path_t *path, int expr_idx, SV *route, I32 idx);
94             SRL_STATIC_INLINE void run_until(pTHX_ srl_path_t *path, UV expected_depth, U32 expected_idx);
95              
96             SRL_STATIC_INLINE int is_all(const char *str, STRLEN len);
97             SRL_STATIC_INLINE int is_list(const char *str, STRLEN len);
98             SRL_STATIC_INLINE int is_number(const char *str, STRLEN len);
99             SRL_STATIC_INLINE int * is_range(const char *str, STRLEN len, int *out);
100             SRL_STATIC_INLINE int next_item_in_list(const char *list, STRLEN list_len,
101             const char **item_out, STRLEN *item_len_out);
102             SRL_STATIC_INLINE void print_route(SV *route, const char *str);
103              
104             srl_path_t *
105 18           srl_build_path_struct(pTHX_ HV *opt)
106             {
107 18           srl_path_t *path = NULL;
108 18           Newx(path, 1, srl_path_t);
109 18 50         if (path == NULL) croak("Out of memory");
110              
111 18           path->iter = NULL;
112 18           path->expr = NULL;
113 18           path->results = NULL;
114 18           path->i_own_iterator = 0;
115              
116             if (opt != NULL) {}
117 18           return path;
118             }
119              
120             void
121 18           srl_destroy_path(pTHX_ srl_path_t *path)
122             {
123 18 50         CLEAR_RESULTS(path);
124 18 50         CLEAR_ITERATOR(path);
    50          
125 18           Safefree(path);
126 18           }
127              
128             void
129 19           srl_path_set(pTHX_ srl_path_t *path, SV *src)
130             {
131 19           path->expr = NULL;
132 19 50         CLEAR_RESULTS(path);
133 19 100         CLEAR_ITERATOR(path);
    50          
134              
135 19 50         if (sv_isobject(src) && sv_isa(src, "Sereal::Path::Iterator")) {
    0          
136 0 0         path->iter = INT2PTR(srl_iterator_ptr, SvIV((SV*) SvRV(src)));
137 0           path->i_own_iterator = 0;
138 19 50         } else if (SvPOK(src)) {
139 19           path->iter = srl_build_iterator_struct(aTHX_ NULL);
140 19           path->i_own_iterator = 1;
141 19           srl_iterator_set(aTHX_ path->iter, src);
142             } else {
143 0           croak("Sereal::Path: input should be either Sereal::Path::Iterator object or encoded Sereal document");
144             }
145 19           }
146              
147             void
148 60           srl_path_traverse(pTHX_ srl_path_t *path, AV *expr, SV *route)
149             {
150             SV *route_copy;
151 60 50         if (!path->iter) croak("No document to traverse");
152              
153             assert(expr != NULL);
154             assert(route != NULL);
155              
156 60 50         CLEAR_RESULTS(path);
157              
158 60           path->results = newAV();
159 60           path->expr = expr;
160 60           route_copy = sv_2mortal(newSVsv(route));
161              
162 60           srl_iterator_reset(aTHX_ path->iter);
163 60           srl_parse_next(aTHX_ path, 0, route_copy);
164 60           }
165              
166             SV *
167 60           srl_path_results(pTHX_ srl_path_t *path)
168             {
169 60 50         AV *results = path->results ? path->results : newAV();
170 60           path->results = NULL;
171 60           return sv_2mortal(newRV_noinc((SV*) results));
172             }
173              
174             SRL_STATIC_INLINE void
175 219           srl_parse_next(pTHX_ srl_path_t *path, int expr_idx, SV *route)
176             {
177             U32 type;
178 219           srl_iterator_t *iter = path->iter;
179              
180             assert(route != NULL);
181             SRL_PATH_TRACE("expr_idx=%d", expr_idx);
182              
183 219 50         if (srl_iterator_eof(aTHX_ iter)) return;
184 219 100         if (expr_idx > av_len(path->expr)) { /* scaned entiry expr */
185             SV *res;
186 129           print_route(route, "to decode");
187 129           res = srl_iterator_decode(aTHX_ iter);
188 129           SvREFCNT_inc(res);
189 129           av_push(path->results, res); /* TODO store route if needed */
190 129           return;
191             }
192              
193 90           type = srl_iterator_info(aTHX_ iter, NULL, NULL, NULL);
194 90 100         if ((type & SRL_ITERATOR_INFO_HASH) == SRL_ITERATOR_INFO_HASH) {
195 36           srl_iterator_step_in(aTHX_ iter, 1);
196 36           srl_parse_hash(aTHX_ path, expr_idx, route);
197 54 50         } else if ((type & SRL_ITERATOR_INFO_ARRAY) == SRL_ITERATOR_INFO_ARRAY) {
198 54           srl_iterator_step_in(aTHX_ iter, 1);
199 54           srl_parse_array(aTHX_ path, expr_idx, route);
200             }
201             }
202              
203             SRL_STATIC_INLINE void
204 33           srl_parse_next_str(pTHX_ srl_path_t *path, int expr_idx, SV *route,
205             const char *str, STRLEN len)
206             {
207 33           STRLEN route_len = SvCUR(route);
208 33           sv_catpvf(route, ";%.*s", (int) len, str); /* append parsed object to route */
209 33           srl_parse_next(aTHX_ path, expr_idx, route);
210 33           SvCUR_set(route, route_len); /* restore original value */
211 33           }
212              
213             SRL_STATIC_INLINE void
214 126           srl_parse_next_int(pTHX_ srl_path_t *path, int expr_idx, SV *route, IV n)
215             {
216 126           STRLEN route_len = SvCUR(route);
217 126           sv_catpvf(route, ";[%"UVuf"]", n); /* append parsed object to route */
218 126           srl_parse_next(aTHX_ path, expr_idx, route);
219 126           SvCUR_set(route, route_len); /* restore original value */
220 126           }
221              
222             SRL_STATIC_INLINE void
223 36           srl_parse_hash(pTHX_ srl_path_t *path, int expr_idx, SV *route)
224             {
225             const char *loc_str;
226             STRLEN loc_len;
227             SV *loc;
228              
229             assert(route != NULL);
230             assert(expr_idx >= 0);
231             assert(expr_idx <= av_len(path->expr));
232              
233 36           loc = *av_fetch(path->expr, expr_idx, 0);
234 36 50         loc_str = SvPV(loc, loc_len);
235              
236 36 100         if (is_all(loc_str, loc_len)) { /* * */
237 8           srl_parse_hash_all(aTHX_ path, expr_idx, route);
238 28 100         } else if (is_list(loc_str, loc_len)) { /* [name1,name2] */
239 5           srl_parse_hash_list(aTHX_ path, expr_idx, route, loc_str, loc_len);
240             } else { /* name */
241 23           srl_parse_hash_item(aTHX_ path, expr_idx, route, loc_str, loc_len);
242             }
243 36           }
244              
245             SRL_STATIC_INLINE void
246 8           srl_parse_hash_all(pTHX_ srl_path_t *path, int expr_idx, SV *route)
247             {
248 8           srl_iterator_ptr iter = path->iter;
249 8           IV depth = srl_iterator_stack_depth(aTHX_ iter);
250 8           U32 length = srl_iterator_stack_length(aTHX_ iter);
251 8           const char *item = NULL;
252             STRLEN item_len;
253             U32 idx;
254              
255             SRL_PATH_TRACE("parse all items in hash of size=%d at depth=%"IVdf, length, depth);
256              
257 32 100         for (idx = 0; idx < length; idx += 2) {
258 24           run_until(aTHX_ path, depth, idx);
259 24           srl_iterator_hash_key(aTHX_ iter, &item, &item_len);
260             SRL_PATH_TRACE("walk over item=%.*s in hash at depth=%"IVdf,
261             (int) item_len, item, srl_iterator_stack_depth(aTHX_ iter));
262 24           srl_parse_next_int(aTHX_ path, expr_idx + 1, route, idx);
263             }
264 8           }
265              
266             SRL_STATIC_INLINE void
267 5           srl_parse_hash_list(pTHX_ srl_path_t *path, int expr_idx, SV *route,
268             const char *list, STRLEN list_len)
269             {
270             STRLEN item_len;
271 5           const char *item = NULL;
272 5           srl_iterator_ptr iter = path->iter;
273 5           IV depth = srl_iterator_stack_depth(aTHX_ iter);
274              
275             SRL_PATH_TRACE("parse items '%.*s' in hash of size=%d at depth=%"IVdf,
276             (int) list_len, list, srl_iterator_stack_length(aTHX_ iter), depth);
277              
278 17 100         while (next_item_in_list(list, list_len, &item, &item_len)) {
279             assert(srl_iterator_stack_depth(aTHX_ iter) == depth);
280 12 50         if (item_len == 0) continue;
281              
282             SRL_PATH_TRACE("scan for item=%.*s in hash at depth=%"IVdf,
283             (int) item_len, item, srl_iterator_stack_depth(aTHX_ iter));
284              
285 12 50         if (srl_iterator_hash_exists(aTHX_ iter, item, item_len) != SRL_ITER_NOT_FOUND) {
286 12           srl_parse_next_str(aTHX_ path, expr_idx + 1, route, item, item_len);
287             }
288             }
289 5           }
290              
291             SRL_STATIC_INLINE void
292 23           srl_parse_hash_item(pTHX_ srl_path_t *path, int expr_idx, SV *route,
293             const char *str, STRLEN str_len)
294             {
295 23           srl_iterator_ptr iter = path->iter;
296             SRL_PATH_TRACE("parse item '%.*s' in hash of size=%d at depth=%"IVdf,
297             (int) str_len, str,
298             srl_iterator_stack_length(aTHX_ iter),
299             srl_iterator_stack_depth(aTHX_ iter));
300              
301 23 100         if (srl_iterator_hash_exists(aTHX_ iter, str, str_len) != SRL_ITER_NOT_FOUND) {
302 21           srl_parse_next_str(aTHX_ path, expr_idx + 1, route, str, str_len);
303             }
304 23           }
305              
306             SRL_STATIC_INLINE void
307 54           srl_parse_array(pTHX_ srl_path_t *path, int expr_idx, SV *route)
308             {
309             int range[3];
310             const char *loc_str;
311             STRLEN loc_len;
312             SV *loc;
313              
314             assert(route != NULL);
315             assert(expr_idx >= 0);
316             assert(expr_idx <= av_len(path->expr));
317              
318 54           loc = *av_fetch(path->expr, expr_idx, 0);
319 54 50         loc_str = SvPV(loc, loc_len);
320              
321 54 100         if (is_all(loc_str, loc_len)) { /* * */
322 10           srl_parse_array_all(aTHX_ path, expr_idx, route);
323 44 100         } else if (is_number(loc_str, loc_len)) { /* [10] */
324 27           srl_parse_array_item(aTHX_ path, expr_idx, route, atoi(loc_str));
325 17 100         } else if (is_list(loc_str, loc_len)) { /* [0,1,2] */
326 12           srl_parse_array_list(aTHX_ path, expr_idx, route, loc_str, loc_len);
327 5 50         } else if (is_range(loc_str, loc_len, (int*) &range)) { /* [start:stop:step] */
328 5           srl_parse_array_range(aTHX_ path, expr_idx, route, (int*) &range);
329             }
330 54           }
331              
332             SRL_STATIC_INLINE void
333 10           srl_parse_array_all(pTHX_ srl_path_t *path, int expr_idx, SV *route)
334             {
335             U32 idx;
336 10           srl_iterator_ptr iter = path->iter;
337 10           IV depth = srl_iterator_stack_depth(aTHX_ iter);
338 10           U32 length = srl_iterator_stack_length(aTHX_ iter);
339              
340             SRL_PATH_TRACE("parse all items in array of size=%d at depth=%"IVdf, length, depth);
341              
342 47 100         for (idx = 0; idx < length; ++idx) {
343 37           run_until(aTHX_ path, depth, idx);
344              
345             SRL_PATH_TRACE("walk over item=%d in array at depth=%d",
346             idx, (int) srl_iterator_stack_depth(aTHX_ iter));
347              
348 37           srl_parse_next_int(aTHX_ path, expr_idx + 1, route, idx);
349             }
350 10           }
351              
352             SRL_STATIC_INLINE void
353 12           srl_parse_array_list(pTHX_ srl_path_t *path, int expr_idx, SV *route,
354             const char *list, STRLEN list_len)
355             {
356             I32 idx;
357             STRLEN item_len;
358 12           const char *item = NULL;
359 12           srl_iterator_ptr iter = path->iter;
360 12           IV depth = srl_iterator_stack_depth(aTHX_ iter);
361              
362             SRL_PATH_TRACE("parse items '%.*s' in array of size=%d at depth=%"IVdf,
363             (int) list_len, list, srl_iterator_stack_length(aTHX_ iter), depth);
364              
365 46 100         while (next_item_in_list(list, list_len, &item, &item_len)) {
366 34 50         if (item_len == 0) continue;
367              
368 34           idx = atoi(item);
369             SRL_PATH_TRACE("scan for item=%d in array at depth=%"IVdf,
370             idx, srl_iterator_stack_depth(aTHX_ iter));
371              
372 34 50         if (srl_iterator_array_exists(aTHX_ iter, idx) != SRL_ITER_NOT_FOUND) {
373 34           srl_iterator_array_goto(aTHX_ iter, idx);
374 34           srl_parse_next_int(aTHX_ path, expr_idx + 1, route, idx);
375             }
376             }
377 12           }
378              
379             SRL_STATIC_INLINE void
380 5           srl_parse_array_range(pTHX_ srl_path_t *path, int expr_idx, SV *route, int *range)
381             {
382             I32 idx, start, stop, step;
383 5           srl_iterator_ptr iter = path->iter;
384 5           U32 length = srl_iterator_stack_length(aTHX_ iter);
385 5           IV depth = srl_iterator_stack_depth(aTHX_ iter);
386              
387 5           start = range[0];
388 5           stop = range[1];
389 5           step = range[2];
390              
391             # define SRL_MIN(a,b) (((a)<(b))?(a):(b))
392             # define SRL_MAX(a,b) (((a)>(b))?(a):(b))
393 5 100         start = start < 0 ? SRL_MAX(0, start + (I32) length) : SRL_MIN((I32) length, start);
394 5 50         stop = stop < 0 ? SRL_MAX(0, stop + (I32) length) : SRL_MIN((I32) length, stop);
395 5 50         step = step ? step : 1;
396              
397 5 50         if (step < 0) croak("negative step in not supported");
398              
399             SRL_PATH_TRACE("parse items '%d:%d:%d' in array of size=%d at depth=%"IVdf,
400             start, stop, step, length, depth);
401              
402 14 100         for (idx = start; idx < stop; idx += step) {
403 9           run_until(aTHX_ path, depth, idx);
404              
405             SRL_PATH_TRACE("walk over item=%d in array at depth=%d",
406             idx, (int) srl_iterator_stack_depth(aTHX_ iter));
407              
408 9           srl_parse_next_int(aTHX_ path, expr_idx + 1, route, idx);
409             }
410 5           }
411              
412             SRL_STATIC_INLINE void
413 27           srl_parse_array_item(pTHX_ srl_path_t *path, int expr_idx, SV *route, I32 idx)
414             {
415 27           srl_iterator_ptr iter = path->iter;
416             SRL_PATH_TRACE("parse item %d in array of size=%d at depth=%"IVdf,
417             idx, srl_iterator_stack_length(aTHX_ iter), srl_iterator_stack_depth(aTHX_ iter));
418              
419 27 100         if (srl_iterator_array_exists(aTHX_ iter, idx) != SRL_ITER_NOT_FOUND) {
420 22           srl_iterator_array_goto(aTHX_ iter, idx);
421 22           srl_parse_next_int(aTHX_ path, expr_idx + 1, route, idx);
422             }
423 27           }
424              
425             SRL_STATIC_INLINE void
426 70           run_until(pTHX_ srl_path_t *path, UV expected_depth, U32 expected_idx)
427             {
428             U32 idx;
429 70           srl_iterator_ptr iter = path->iter;
430 70           IV depth = srl_iterator_stack_depth(aTHX_ iter);
431              
432             SRL_PATH_TRACE("expected_depth=%"UVuf" expected_idx=%u at depth=%"IVdf,
433             expected_depth, expected_idx, depth);
434              
435 70 50         if ((IV) expected_depth > depth) {
436 0           croak("run_until: expected_depth > depth (%"UVuf" > %"IVdf")", expected_depth, depth);
437             }
438              
439 70           srl_iterator_step_out(aTHX_ iter, depth - expected_depth);
440             assert((IV) expected_depth == srl_iterator_stack_depth(aTHX_ iter));
441              
442 70           idx = srl_iterator_stack_index(aTHX_ iter);
443 70 50         if (expected_idx < idx) {
444 0           croak("run_until: expected_idx < idx (%u < %d))", expected_idx, idx);
445             }
446              
447 70           srl_iterator_next(aTHX_ iter, expected_idx - idx);
448             assert(expected_idx == srl_iterator_stack_index(aTHX_ iter));
449 70           }
450              
451             SRL_STATIC_INLINE int
452 90           is_all(const char *str, STRLEN len)
453             {
454 90 100         return len == 1 ? str[0] == '*' : 0;
    100          
455             }
456              
457             SRL_STATIC_INLINE int
458 45           is_list(const char *str, STRLEN len)
459             {
460             STRLEN i;
461 119 100         for (i = 0; i < len; ++i) {
462 91 100         if (str[i] == ',') return 1;
463             }
464              
465 28           return 0;
466             }
467              
468 36           int * _is_range(const char *str, STRLEN len, int *out) { return is_range(str, len, out); }
469              
470             SRL_STATIC_INLINE int *
471 23           is_range(const char *str, STRLEN len, int *out)
472             {
473             char *ptr;
474             STRLEN pos[2];
475             STRLEN i, ndel;
476             STRLEN start_len, stop_len, step_len;
477 23           int valid = 0;
478              
479 97 100         for (i = 0, ndel = 0; i < len; ++i) {
480 76 100         if (str[i] == ':') {
481 28 100         if (ndel >= 2) return NULL;
482 26           pos[ndel++] = i;
483             }
484             }
485              
486 21           switch (ndel) {
487             case 2: /* [start:stop:step] */
488 5           start_len = pos[0];
489 5           stop_len = pos[1] - pos[0] - 1;
490 5           step_len = len - pos[1] - 1;
491             assert(start_len + stop_len + step_len + 2 == len);
492              
493 1 50         valid = (start_len != 0 || stop_len != 0 || step_len != 0)
    50          
494 4 50         && (start_len == 0 || is_number(str, start_len))
    50          
495 4 50         && (stop_len == 0 || is_number(str + pos[0] + 1, stop_len))
    50          
496 10 100         && (step_len == 0 || is_number(str + pos[1] + 1, step_len));
    100          
    100          
497              
498 5 100         if (!valid) return NULL;
499              
500 3           ptr = strndup(str, len);
501 3           ptr[pos[0]] = '\0';
502 3           ptr[pos[1]] = '\0';
503              
504 3 50         out[0] = start_len == 0 ? 0 : atoi(ptr); /* start */
505 3 50         out[1] = stop_len == 0 ? 0x7FFFFFFF : atoi(ptr+ pos[0] + 1); /* stop */
506 3 100         out[2] = step_len == 0 ? 1 : atoi(ptr + pos[1] + 1); /* step */
507 3           free((void*) ptr);
508              
509 3           return out;
510              
511             case 1: /* [start:stop] */
512 12           start_len = pos[0];
513 12           stop_len = len - pos[0] - 1;
514             assert(start_len + stop_len + 1 == len);
515              
516 3 100         valid = (start_len != 0 || stop_len != 0)
517 11 100         && (start_len == 0 || is_number(str, pos[0]))
    50          
518 24 100         && (stop_len == 0 || is_number(str + pos[0] + 1, stop_len));
    100          
    100          
519              
520 12 100         if (!valid) return NULL;
521              
522 10           ptr = strndup(str, len);
523 10           ptr[pos[0]] = '\0';
524              
525 10 100         out[0] = start_len == 0 ? 0 : atoi(ptr); /* start */
526 10 100         out[1] = stop_len == 0 ? 0x7FFFFFFF : atoi(ptr+ pos[0] + 1); /* stop */
527 10           out[2] = 1;
528 10           free((void*) ptr);
529              
530 10           return out;
531             }
532              
533 23           return NULL;
534             }
535              
536             SRL_STATIC_INLINE int
537 71           is_number(const char *str, STRLEN len)
538             {
539             STRLEN i;
540 71 100         if (*str == '-') {
541 15           str++;
542 15           len--;
543             }
544              
545 141 100         for (i = 0; i < len; ++i) {
546 89 100         if (str[i] < '0' || str[i] > '9')
    100          
547 19           return 0;
548             }
549              
550 52           return len != 0;
551             }
552              
553             SRL_STATIC_INLINE int
554 63           next_item_in_list(const char *list, STRLEN list_len, const char **item_out, STRLEN *item_len_out)
555             {
556 126           const char *start_pos = *item_out
557 46           ? *item_out + *item_len_out + 1
558 63 100         : list;
559              
560             assert(start_pos >= list);
561              
562 63 100         if (start_pos - list >= (ptrdiff_t) list_len) return 0;
563 46           list_len -= (start_pos - list);
564 46           list = start_pos;
565              
566 102 100         while (list_len-- && *list != ',') list++;
    100          
567              
568 46           *item_out = start_pos;
569 46           *item_len_out = (list - start_pos);
570 46           return 1;
571             }
572              
573             SRL_STATIC_INLINE void
574 129           print_route(SV *route, const char *str)
575             {
576             #ifdef TRACE_SRL_PATH
577             STRLEN len;
578             const char *ptr = SvPV(route, len);
579             SRL_PATH_TRACE("route (%s): %.*s", str, (int) len, ptr);
580             #endif
581 129           }