File Coverage

Declare.xs
Criterion Covered Total %
statement 191 222 86.0
branch 115 220 52.2
condition n/a
subroutine n/a
pod n/a
total 306 442 69.2


line stmt bran cond sub pod time code
1             #define PERL_NO_GET_CONTEXT 1
2             #include "EXTERN.h"
3             #include "perl.h"
4             #include "XSUB.h"
5             #include "hook_op_check.h"
6             #undef printf
7             #include "stolen_chunk_of_toke.c"
8             #include
9             #include
10              
11             #define PERL_VERSION_DECIMAL(r,v,s) (r*1000000 + v*1000 + s)
12             #define PERL_DECIMAL_VERSION \
13             PERL_VERSION_DECIMAL(PERL_REVISION,PERL_VERSION,PERL_SUBVERSION)
14             #define PERL_VERSION_GE(r,v,s) \
15             (PERL_DECIMAL_VERSION >= PERL_VERSION_DECIMAL(r,v,s))
16              
17             #ifndef Newx
18             # define Newx(v,n,t) New(0,v,n,t)
19             #endif /* !Newx */
20              
21             #define DD_DEBUGf_UPDATED_LINESTR 1
22             #define DD_DEBUGf_TRACE 2
23              
24             #define DD_DEBUG_UPDATED_LINESTR (dd_debug & DD_DEBUGf_UPDATED_LINESTR)
25             #define DD_DEBUG_TRACE (dd_debug & DD_DEBUGf_TRACE)
26             static int dd_debug = 0;
27              
28             #define DD_CONST_VIA_RV2CV PERL_VERSION_GE(5,11,2)
29              
30             #define DD_GROW_VIA_BLOCKHOOK PERL_VERSION_GE(5,13,3)
31              
32             #define LEX_NORMAL 10
33             #define LEX_INTERPNORMAL 9
34              
35             /* please try not to have a line longer than this :) */
36              
37             #define DD_PREFERRED_LINESTR_SIZE 16384
38              
39             /* flag to trigger removal of temporary declaree sub */
40              
41             static int in_declare = 0;
42              
43             /* in 5.10, PL_parser will be NULL if we aren't parsing, and PL_lex_stuff
44             is a lookup into it - so if anything else we can use to tell, so we
45             need to be a bit more careful if PL_parser exists */
46              
47             #define DD_AM_LEXING_CHECK (PL_lex_state == LEX_NORMAL || PL_lex_state == LEX_INTERPNORMAL)
48              
49             #if defined(PL_parser) || defined(PERL_5_9_PLUS)
50             #define DD_HAVE_PARSER PL_parser
51             #define DD_HAVE_LEX_STUFF (PL_parser && PL_lex_stuff)
52             #define DD_AM_LEXING (PL_parser && DD_AM_LEXING_CHECK)
53             #else
54             #define DD_HAVE_PARSER 1
55             #define DD_HAVE_LEX_STUFF PL_lex_stuff
56             #define DD_AM_LEXING DD_AM_LEXING_CHECK
57             #endif
58              
59             /* thing that decides whether we're dealing with a declarator */
60              
61 10720           int dd_is_declarator(pTHX_ char* name) {
62             HV* is_declarator;
63             SV** is_declarator_pack_ref;
64             HV* is_declarator_pack_hash;
65             SV** is_declarator_flag_ref;
66             int dd_flags;
67             char* curstash_name;
68              
69 10720           is_declarator = get_hv("Devel::Declare::declarators", FALSE);
70              
71 10720 50         if (!is_declarator)
72 0           return -1;
73              
74             /* $declarators{$current_package_name} */
75              
76 10720 50         curstash_name = HvNAME(PL_curstash);
    50          
    50          
    0          
    50          
    50          
77 10720 50         if (!curstash_name)
78 0           return -1;
79              
80 10720           is_declarator_pack_ref = hv_fetch(is_declarator, curstash_name,
81             strlen(curstash_name), FALSE);
82              
83 10720 100         if (!is_declarator_pack_ref || !SvROK(*is_declarator_pack_ref))
    50          
84 10459           return -1; /* not a hashref */
85              
86 261           is_declarator_pack_hash = (HV*) SvRV(*is_declarator_pack_ref);
87              
88             /* $declarators{$current_package_name}{$name} */
89              
90 261           is_declarator_flag_ref = hv_fetch(
91             is_declarator_pack_hash, name,
92             strlen(name), FALSE
93             );
94              
95             /* requires SvIOK as well as TRUE since flags not being an int is useless */
96              
97 370 100         if (!is_declarator_flag_ref
    50          
    50          
    50          
    50          
98 109 50         || !SvIOK(*is_declarator_flag_ref)
99 218 50         || !SvTRUE(*is_declarator_flag_ref))
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    0          
    0          
    50          
    0          
100 152           return -1;
101              
102 109           dd_flags = SvIVX(*is_declarator_flag_ref);
103              
104 109           return dd_flags;
105             }
106              
107             /* callback thingy */
108              
109 128           void dd_linestr_callback (pTHX_ char* type, char* name) {
110              
111 128           char* linestr = SvPVX(PL_linestr);
112 128           int offset = PL_bufptr - linestr;
113              
114 128           dSP;
115              
116 128           ENTER;
117 128           SAVETMPS;
118              
119 128 50         PUSHMARK(SP);
120 128 50         XPUSHs(sv_2mortal(newSVpv(type, 0)));
121 128 50         XPUSHs(sv_2mortal(newSVpv(name, 0)));
122 128 50         XPUSHs(sv_2mortal(newSViv(offset)));
123 128           PUTBACK;
124              
125 128           call_pv("Devel::Declare::linestr_callback", G_VOID|G_DISCARD);
126              
127 127 50         FREETMPS;
128 127           LEAVE;
129 127           }
130              
131 384           char* dd_get_linestr(pTHX) {
132 384 50         if (!DD_HAVE_PARSER) {
133 0           return NULL;
134             }
135 384           return SvPVX(PL_linestr);
136             }
137              
138 352           void dd_set_linestr(pTHX_ char* new_value) {
139 352           unsigned int new_len = strlen(new_value);
140              
141 352 50         if (SvLEN(PL_linestr) < new_len) {
142 0 0         croak("PL_linestr not long enough, was Devel::Declare loaded soon enough in %s",
143 0           CopFILE(&PL_compiling)
144             );
145             }
146              
147              
148 352           memcpy(SvPVX(PL_linestr), new_value, new_len+1);
149              
150 352           SvCUR_set(PL_linestr, new_len);
151              
152 352           PL_bufend = SvPVX(PL_linestr) + new_len;
153              
154 352 100         if ( DD_DEBUG_UPDATED_LINESTR && PERLDB_LINE && PL_curstash != PL_debstash) {
    50          
    50          
155             /* Cribbed from toke.c */
156 4 50         AV *fileav = CopFILEAV(&PL_compiling);
157 4 50         if (fileav) {
158 4           SV * const sv = NEWSV(85,0);
159              
160 4           sv_upgrade(sv, SVt_PVMG);
161 4           sv_setpvn(sv,PL_bufptr,PL_bufend-PL_bufptr);
162 4           (void)SvIOK_on(sv);
163 4           SvIV_set(sv, 0);
164 4           av_store(fileav,(I32)CopLINE(&PL_compiling),sv);
165             }
166             }
167 352           }
168              
169 59           char* dd_get_lex_stuff(pTHX) {
170 59 50         return (DD_HAVE_LEX_STUFF ? SvPVX(PL_lex_stuff) : "");
    100          
171             }
172              
173 59           void dd_clear_lex_stuff(pTHX) {
174 59 50         if (DD_HAVE_PARSER)
175 59           PL_lex_stuff = (SV*)NULL;
176 59           }
177              
178 258           char* dd_get_curstash_name(pTHX) {
179 258 50         return HvNAME(PL_curstash);
    50          
    50          
    0          
    50          
    50          
180             }
181              
182 31           int dd_get_linestr_offset(pTHX) {
183             char* linestr;
184 31 50         if (!DD_HAVE_PARSER) {
185 0           return -1;
186             }
187 31           linestr = SvPVX(PL_linestr);
188 31           return PL_bufptr - linestr;
189             }
190              
191 70           char* dd_move_past_token (pTHX_ char* s) {
192              
193             /*
194             * buffer will be at the beginning of the declarator, -unless- the
195             * declarator is at EOL in which case it'll be the next useful line
196             * so we don't short-circuit out if we don't find the declarator
197             */
198              
199 70 50         while (s < PL_bufend && isSPACE(*s)) s++;
    50          
200 70 100         if (memEQ(s, PL_tokenbuf, strlen(PL_tokenbuf)))
201 66           s += strlen(PL_tokenbuf);
202 70           return s;
203             }
204              
205 70           int dd_toke_move_past_token (pTHX_ int offset) {
206 70           char* base_s = SvPVX(PL_linestr) + offset;
207 70           char* s = dd_move_past_token(aTHX_ base_s);
208 70           return s - base_s;
209             }
210              
211 144           int dd_toke_scan_word(pTHX_ int offset, int handle_package) {
212             char tmpbuf[sizeof PL_tokenbuf];
213 144           char* base_s = SvPVX(PL_linestr) + offset;
214             STRLEN len;
215 144           char* s = scan_word(base_s, tmpbuf, sizeof tmpbuf, handle_package, &len);
216 144           return s - base_s;
217             }
218              
219 0           int dd_toke_scan_ident(pTHX_ int offset) {
220             char tmpbuf[sizeof PL_tokenbuf];
221 0           char* base_s = SvPVX(PL_linestr) + offset;
222 0           char* s = scan_ident(base_s, PL_bufend, tmpbuf, sizeof tmpbuf, 0);
223 0           return s - base_s;
224             }
225              
226 60           int dd_toke_scan_str(pTHX_ int offset) {
227 60           char* old_pvx = SvPVX(PL_linestr);
228 60           SV* line_copy = sv_2mortal(newSVsv(PL_linestr));
229 60           char* base_s = SvPVX(PL_linestr) + offset;
230 60           char* s = scan_str(base_s, FALSE, FALSE);
231 60 50         if(SvPVX(PL_linestr) != old_pvx)
232 0           croak("PL_linestr reallocated during scan_str, "
233             "Devel::Declare can't continue");
234 60 100         if (!s)
235 2           return 0;
236 58 100         if (s <= base_s || memcmp(SvPVX(line_copy), SvPVX(PL_linestr), offset)) {
    100          
237 16           s += SvCUR(line_copy);
238 16           sv_catsv(line_copy, PL_linestr);
239 16 50         dd_set_linestr(aTHX_ SvPV_nolen(line_copy));
240             }
241 58           return s - base_s;
242             }
243              
244 318           int dd_toke_skipspace(pTHX_ int offset) {
245 318           char* old_pvx = SvPVX(PL_linestr);
246 318           char* base_s = SvPVX(PL_linestr) + offset;
247 318           char* s = skipspace_force(base_s);
248 318 50         if(SvPVX(PL_linestr) != old_pvx)
249 0           croak("PL_linestr reallocated during skipspace, "
250             "Devel::Declare can't continue");
251 318           return s - base_s;
252             }
253              
254 80           static void call_done_declare(pTHX) {
255 80           dSP;
256              
257 80 50         if (DD_DEBUG_TRACE) {
258 0           printf("Deconstructing declare\n");
259 0           printf("PL_bufptr: %s\n", PL_bufptr);
260 0           printf("bufend at: %i\n", (int)(PL_bufend - PL_bufptr));
261 0           printf("linestr: %s\n", SvPVX(PL_linestr));
262 0           printf("linestr len: %i\n", (int)(PL_bufend - SvPVX(PL_linestr)));
263             }
264              
265 80           ENTER;
266 80           SAVETMPS;
267              
268 80 50         PUSHMARK(SP);
269              
270 80           call_pv("Devel::Declare::done_declare", G_VOID|G_DISCARD);
271              
272 80 50         FREETMPS;
273 80           LEAVE;
274              
275 80 50         if (DD_DEBUG_TRACE) {
276 0           printf("PL_bufptr: %s\n", PL_bufptr);
277 0           printf("bufend at: %i\n", (int)(PL_bufend - PL_bufptr));
278 0           printf("linestr: %s\n", SvPVX(PL_linestr));
279 0           printf("linestr len: %i\n", (int)(PL_bufend - SvPVX(PL_linestr)));
280 0           printf("actual len: %i\n", (int)strlen(PL_bufptr));
281             }
282 80           }
283              
284             static int dd_handle_const(pTHX_ char *name);
285              
286             #ifdef CV_NAME_NOTQUAL /* 5.21.5 */
287             # define Gv_or_CvNAME(g) (isGV(g) \
288             ? GvNAME(g) \
289             : SvPV_nolen(cv_name((CV *)SvRV(g), NULL, CV_NAME_NOTQUAL)))
290             #elif defined(CvNAMED) /* 5.21.4 */
291             # define Gv_or_CvNAME(g) (isGV(g) \
292             ? GvNAME(g) \
293             : CvNAMED(SvRV(g)) \
294             ? HEK_KEY(CvNAME_HEK((CV *)SvRV(g))) \
295             : GvNAME(CvGV(SvRV(g))))
296             #else
297             # define Gv_or_CvNAME(g) GvNAME(g)
298             #endif
299              
300             /* replacement PL_check rv2cv entry */
301              
302 12249           STATIC OP *dd_ck_rv2cv(pTHX_ OP *o, void *user_data) {
303             OP* kid;
304             int dd_flags;
305             char *gvname;
306              
307             PERL_UNUSED_VAR(user_data);
308              
309 12249 50         if (!DD_AM_LEXING)
    50          
    0          
310 0           return o; /* not lexing? */
311              
312 12249 100         if (in_declare) {
313 25           call_done_declare(aTHX);
314 25           return o;
315             }
316              
317 12224           kid = cUNOPo->op_first;
318              
319 12224 100         if (kid->op_type != OP_GV) /* not a GV so ignore */
320 1495           return o;
321              
322 10729 100         if (!isGV(kGVOP_gv)
323 64 50         && (!SvROK(kGVOP_gv) || SvTYPE(SvRV(kGVOP_gv)) != SVt_PVCV))
    100          
324 9           return o;
325              
326 10720 100         gvname = Gv_or_CvNAME(kGVOP_gv);
    50          
327              
328 10720 50         if (DD_DEBUG_TRACE) {
329 0 0         printf("Checking GV %s -> %s\n", HvNAME(GvSTASH(kGVOP_gv)), gvname);
    0          
    0          
    0          
    0          
    0          
330             }
331              
332 10720           dd_flags = dd_is_declarator(aTHX_ gvname);
333              
334 10720 100         if (dd_flags == -1)
335 10611           return o;
336              
337 109 50         if (DD_DEBUG_TRACE) {
338 0           printf("dd_flags are: %i\n", dd_flags);
339 0           printf("PL_tokenbuf: %s\n", PL_tokenbuf);
340             }
341              
342             #if DD_CONST_VIA_RV2CV
343 109 100         if (PL_expect != XOPERATOR) {
344 95 100         if (!dd_handle_const(aTHX_ Gv_or_CvNAME(kGVOP_gv)))
    50          
    100          
345 1           return o;
346 93           CopLINE(PL_curcop) = PL_copline;
347             /* The parser behaviour that we're simulating depends on what comes
348             after the declarator. */
349 93 100         if (*skipspace(PL_bufptr + strlen(gvname)) != '(') {
350 75 100         if (in_declare) {
351 55           call_done_declare(aTHX);
352             } else {
353 20           dd_linestr_callback(aTHX_ "rv2cv", gvname);
354             }
355             }
356 93           return o;
357             }
358             #endif /* DD_CONST_VIA_RV2CV */
359              
360 14           dd_linestr_callback(aTHX_ "rv2cv", gvname);
361              
362 14           return o;
363             }
364              
365             #if DD_GROW_VIA_BLOCKHOOK
366              
367 16719           static void dd_block_start(pTHX_ int full)
368             {
369             PERL_UNUSED_VAR(full);
370 16719 100         if (SvLEN(PL_linestr) < DD_PREFERRED_LINESTR_SIZE)
371 1110           (void) lex_grow_linestr(DD_PREFERRED_LINESTR_SIZE);
372 16719           }
373              
374             #else /* !DD_GROW_VIA_BLOCKHOOK */
375              
376             OP* dd_pp_entereval(pTHX) {
377             dSP;
378             STRLEN len;
379             const char* s;
380             SV *sv;
381             #ifdef PERL_5_9_PLUS
382             SV *saved_hh = NULL;
383             if (PL_op->op_private & OPpEVAL_HAS_HH) {
384             saved_hh = POPs;
385             }
386             #endif
387             sv = POPs;
388             if (SvPOK(sv)) {
389             if (DD_DEBUG_TRACE) {
390             printf("mangling eval sv\n");
391             }
392             if (SvREADONLY(sv))
393             sv = sv_2mortal(newSVsv(sv));
394             s = SvPVX(sv);
395             len = SvCUR(sv);
396             if (!len || s[len-1] != ';') {
397             if (!(SvFLAGS(sv) & SVs_TEMP))
398             sv = sv_2mortal(newSVsv(sv));
399             sv_catpvn(sv, "\n;", 2);
400             }
401             SvGROW(sv, DD_PREFERRED_LINESTR_SIZE);
402             }
403             PUSHs(sv);
404             #ifdef PERL_5_9_PLUS
405             if (PL_op->op_private & OPpEVAL_HAS_HH) {
406             PUSHs(saved_hh);
407             }
408             #endif
409             return PL_ppaddr[OP_ENTEREVAL](aTHX);
410             }
411              
412             STATIC OP *dd_ck_entereval(pTHX_ OP *o, void *user_data) {
413             PERL_UNUSED_VAR(user_data);
414              
415             if (o->op_ppaddr == PL_ppaddr[OP_ENTEREVAL])
416             o->op_ppaddr = dd_pp_entereval;
417             return o;
418             }
419              
420             #endif /* !DD_GROW_VIA_BLOCKHOOK */
421              
422 34           static I32 dd_filter_realloc(pTHX_ int idx, SV *sv, int maxlen)
423             {
424             SV *filter_datasv;
425 34           const I32 count = FILTER_READ(idx+1, sv, maxlen);
426 34 50         SvGROW(sv, DD_PREFERRED_LINESTR_SIZE);
    100          
427             /* Filters can only be deleted in the correct order (reverse of the
428             order in which they were added). Insisting on deleting the filter
429             here would break if another filter were added after ours and is
430             still around. Not deleting the filter at all would break if another
431             filter were added earlier and attempts to delete itself later.
432             We can play nicely to the maximum possible extent by deleting our
433             filter iff it is currently deletable (i.e., it is on the top of
434             the filter stack). Can still run into trouble in more complex
435             situations, but can't avoid that. */
436 68 50         if (PL_rsfp_filters && AvFILLp(PL_rsfp_filters) >= 0 &&
    50          
    50          
437 68 50         (filter_datasv = FILTER_DATA(AvFILLp(PL_rsfp_filters))) &&
    100          
438 34           IoANY(filter_datasv) == FPTR2DPTR(void *, dd_filter_realloc)) {
439 30           filter_del(dd_filter_realloc);
440             }
441 34           return count;
442             }
443              
444 95           static int dd_handle_const(pTHX_ char *name) {
445 95 50         switch (PL_lex_inwhat) {
446             case OP_QR:
447             case OP_MATCH:
448             case OP_SUBST:
449             case OP_TRANS:
450             case OP_BACKTICK:
451             case OP_STRINGIFY:
452 0           return 0;
453             break;
454             default:
455 95           break;
456             }
457              
458 95 50         if (strnEQ(PL_bufptr, "->", 2)) {
459 0           return 0;
460             }
461              
462             {
463             char buf[256];
464             STRLEN len;
465 95           char *s = PL_bufptr;
466 95           STRLEN old_offset = PL_bufptr - SvPVX(PL_linestr);
467              
468 95           s = scan_word(s, buf, sizeof buf, FALSE, &len);
469 95 50         if (strnEQ(buf, name, len)) {
470             char *d;
471 95           SV *inject = newSVpvn(SvPVX(PL_linestr), PL_bufptr - SvPVX(PL_linestr));
472 95           sv_catpvn(inject, buf, len);
473              
474 95           d = peekspace(s);
475 95           sv_catpvn(inject, s, d - s);
476              
477 95 50         if ((PL_bufend - d) >= 2 && strnEQ(d, "=>", 2)) {
    100          
478 1           return 0;
479             }
480              
481 94           sv_catpv(inject, d);
482 94 50         dd_set_linestr(aTHX_ SvPV_nolen(inject));
483 94           PL_bufptr = SvPVX(PL_linestr) + old_offset;
484 94           SvREFCNT_dec (inject);
485             }
486             }
487              
488 94           dd_linestr_callback(aTHX_ "const", name);
489              
490 93           return 1;
491             }
492              
493             #if !DD_CONST_VIA_RV2CV
494              
495             STATIC OP *dd_ck_const(pTHX_ OP *o, void *user_data) {
496             int dd_flags;
497             char* name;
498              
499             PERL_UNUSED_VAR(user_data);
500              
501             if (DD_HAVE_PARSER && PL_expect == XOPERATOR) {
502             return o;
503             }
504              
505             /* if this is set, we just grabbed a delimited string or something,
506             not a bareword, so NO TOUCHY */
507              
508             if (DD_HAVE_LEX_STUFF)
509             return o;
510              
511             /* don't try and look this up if it's not a string const */
512             if (!SvPOK(cSVOPo->op_sv))
513             return o;
514              
515             name = SvPVX(cSVOPo->op_sv);
516              
517             dd_flags = dd_is_declarator(aTHX_ name);
518              
519             if (dd_flags == -1)
520             return o;
521              
522             dd_handle_const(aTHX_ name);
523              
524             return o;
525             }
526              
527             #endif /* !DD_CONST_VIA_RV2CV */
528              
529 63           STATIC void dd_initialize(pTHX) {
530             static int initialized = 0;
531 63 100         if (!initialized) {
532 32           initialized = 1;
533             #if DD_GROW_VIA_BLOCKHOOK
534             {
535             static BHK bhk;
536             #if PERL_VERSION_GE(5,13,6)
537 32           BhkENTRY_set(&bhk, bhk_start, dd_block_start);
538             #else /* <5.13.6 */
539             BhkENTRY_set(&bhk, start, dd_block_start);
540             #endif /* <5.13.6 */
541 32           Perl_blockhook_register(aTHX_ &bhk);
542             }
543             #else /* !DD_GROW_VIA_BLOCKHOOK */
544             hook_op_check(OP_ENTEREVAL, dd_ck_entereval, NULL);
545             #endif /* !DD_GROW_VIA_BLOCKHOOK */
546 32           hook_op_check(OP_RV2CV, dd_ck_rv2cv, NULL);
547             #if !DD_CONST_VIA_RV2CV
548             hook_op_check(OP_CONST, dd_ck_const, NULL);
549             #endif /* !DD_CONST_VIA_RV2CV */
550             }
551 63           }
552              
553             MODULE = Devel::Declare PACKAGE = Devel::Declare
554              
555             PROTOTYPES: DISABLE
556              
557             void
558             initialize()
559             CODE:
560 32           dd_initialize(aTHX);
561              
562             void
563             setup()
564             CODE:
565 31           dd_initialize(aTHX);
566 31           filter_add(dd_filter_realloc, NULL);
567              
568             char*
569             get_linestr()
570             CODE:
571 384           RETVAL = dd_get_linestr(aTHX);
572             OUTPUT:
573             RETVAL
574              
575             void
576             set_linestr(char* new_value)
577             CODE:
578 242           dd_set_linestr(aTHX_ new_value);
579              
580             char*
581             get_lex_stuff()
582             CODE:
583 59           RETVAL = dd_get_lex_stuff(aTHX);
584             OUTPUT:
585             RETVAL
586              
587             void
588             clear_lex_stuff()
589             CODE:
590 59           dd_clear_lex_stuff(aTHX);
591              
592             char*
593             get_curstash_name()
594             CODE:
595 258           RETVAL = dd_get_curstash_name(aTHX);
596             OUTPUT:
597             RETVAL
598              
599             int
600             get_linestr_offset()
601             CODE:
602 31           RETVAL = dd_get_linestr_offset(aTHX);
603             OUTPUT:
604             RETVAL
605              
606             int
607             toke_scan_word(int offset, int handle_package)
608             CODE:
609 144           RETVAL = dd_toke_scan_word(aTHX_ offset, handle_package);
610             OUTPUT:
611             RETVAL
612              
613             int
614             toke_move_past_token(int offset);
615             CODE:
616 70           RETVAL = dd_toke_move_past_token(aTHX_ offset);
617             OUTPUT:
618             RETVAL
619              
620             SV*
621             toke_scan_str(int offset);
622             PREINIT:
623             int len;
624             CODE:
625 60           len = dd_toke_scan_str(aTHX_ offset);
626 60 100         RETVAL = len ? newSViv(len) : &PL_sv_undef;
627             OUTPUT:
628             RETVAL
629              
630             int
631             toke_scan_ident(int offset)
632             CODE:
633 0           RETVAL = dd_toke_scan_ident(aTHX_ offset);
634             OUTPUT:
635             RETVAL
636              
637             int
638             toke_skipspace(int offset)
639             CODE:
640 318           RETVAL = dd_toke_skipspace(aTHX_ offset);
641             OUTPUT:
642             RETVAL
643              
644             int
645             get_in_declare()
646             CODE:
647 0           RETVAL = in_declare;
648             OUTPUT:
649             RETVAL
650              
651             void
652             set_in_declare(int value)
653             CODE:
654 160           in_declare = value;
655              
656             BOOT:
657             {
658             char *endptr;
659 32           char *debug_str = getenv ("DD_DEBUG");
660 32 100         if (debug_str) {
661 1           dd_debug = strtol (debug_str, &endptr, 10);
662 1 50         if (*endptr != '\0') {
663 0           dd_debug = 0;
664             }
665             }
666             }