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