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