This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Devel::PPPort: Use croak_nocontext() intead of croak() when dTHX is not declared
[perl5.git] / dist / Devel-PPPort / parts / inc / mess
1 ################################################################################
2 ##
3 ##  Copyright (C) 2017, Pali <pali@cpan.org>
4 ##
5 ##  This program is free software; you can redistribute it and/or
6 ##  modify it under the same terms as Perl itself.
7 ##
8 ################################################################################
9
10 =provides
11
12 croak_sv
13 die_sv
14 mess_sv
15 warn_sv
16
17 vmess
18 mess_nocontext
19 mess
20
21 warn_nocontext
22
23 croak_nocontext
24
25 croak_no_modify
26 Perl_croak_no_modify
27
28 croak_memory_wrap
29 croak_xs_usage
30
31 PERL_ARGS_ASSERT_CROAK_XS_USAGE
32
33 =dontwarn
34
35 NEED_mess
36 NEED_mess_nocontext
37 NEED_vmess
38 _dppp_fix_utf8_errsv
39
40 =implementation
41
42 #ifdef NEED_mess_sv
43 #define NEED_mess
44 #endif
45
46 #ifdef NEED_mess
47 #define NEED_mess_nocontext
48 #define NEED_vmess
49 #endif
50
51 #ifndef croak_sv
52 #if { VERSION >= 5.7.3 } || ( { VERSION >= 5.6.1 } && { VERSION < 5.7.0 } )
53 #  if ( { VERSION >= 5.8.0 } && { VERSION < 5.8.9 } ) || ( { VERSION >= 5.9.0 } && { VERSION < 5.10.1 } )
54 #    define _dppp_fix_utf8_errsv(errsv, sv)                     \
55         STMT_START {                                            \
56             if (sv != ERRSV)                                    \
57                 SvFLAGS(ERRSV) = (SvFLAGS(ERRSV) & ~SVf_UTF8) | \
58                                  (SvFLAGS(sv) & SVf_UTF8);      \
59         } STMT_END
60 #  else
61 #    define _dppp_fix_utf8_errsv(errsv, sv) STMT_START {} STMT_END
62 #  endif
63 #  define croak_sv(sv)                        \
64     STMT_START {                              \
65         if (SvROK(sv)) {                      \
66             sv_setsv(ERRSV, sv);              \
67             croak(NULL);                      \
68         } else {                              \
69             _dppp_fix_utf8_errsv(ERRSV, sv);  \
70             croak("%" SVf, SVfARG(sv));       \
71         }                                     \
72     } STMT_END
73 #elif { VERSION >= 5.4.0 }
74 #  define croak_sv(sv) croak("%" SVf, SVfARG(sv))
75 #else
76 #  define croak_sv(sv) croak("%s", SvPV_nolen(sv))
77 #endif
78 #endif
79
80 #ifndef die_sv
81 #if { NEED die_sv }
82 OP *
83 die_sv(pTHX_ SV *sv)
84 {
85     croak_sv(sv);
86     return (OP *)NULL;
87 }
88 #endif
89 #endif
90
91 #ifndef warn_sv
92 #if { VERSION >= 5.4.0 }
93 #  define warn_sv(sv) warn("%" SVf, SVfARG(sv))
94 #else
95 #  define warn_sv(sv) warn("%s", SvPV_nolen(sv))
96 #endif
97 #endif
98
99 #ifndef vmess
100 #if { NEED vmess }
101 SV*
102 vmess(pTHX_ const char* pat, va_list* args)
103 {
104     mess(pat, args);
105     return PL_mess_sv;
106 }
107 #endif
108 #endif
109
110 #if { VERSION < 5.6.0 }
111 #undef mess
112 #endif
113
114 #if !defined(mess_nocontext) && !defined(Perl_mess_nocontext)
115 #if { NEED mess_nocontext }
116 SV*
117 mess_nocontext(const char* pat, ...)
118 {
119     dTHX;
120     SV *sv;
121     va_list args;
122     va_start(args, pat);
123     sv = vmess(pat, &args);
124     va_end(args);
125     return sv;
126 }
127 #endif
128 #endif
129
130 #ifndef mess
131 #if { NEED mess }
132 SV*
133 mess(pTHX_ const char* pat, ...)
134 {
135     SV *sv;
136     va_list args;
137     va_start(args, pat);
138     sv = vmess(pat, &args);
139     va_end(args);
140     return sv;
141 }
142 #ifdef mess_nocontext
143 #define mess mess_nocontext
144 #else
145 #define mess Perl_mess_nocontext
146 #endif
147 #endif
148 #endif
149
150 #ifndef mess_sv
151 #if { NEED mess_sv }
152 SV *
153 mess_sv(pTHX_ SV *basemsg, bool consume)
154 {
155     SV *tmp;
156     SV *ret;
157
158     if (SvPOK(basemsg) && SvCUR(basemsg) && *(SvEND(basemsg)-1) == '\n') {
159         if (consume)
160             return basemsg;
161         ret = mess("");
162         SvSetSV_nosteal(ret, basemsg);
163         return ret;
164     }
165
166     if (consume) {
167         sv_catsv(basemsg, mess(""));
168         return basemsg;
169     }
170
171     ret = mess("");
172     tmp = newSVsv(ret);
173     SvSetSV_nosteal(ret, basemsg);
174     sv_catsv(ret, tmp);
175     sv_dec(tmp);
176     return ret;
177 }
178 #endif
179 #endif
180
181 #ifndef warn_nocontext
182 #define warn_nocontext warn
183 #endif
184
185 #ifndef croak_nocontext
186 #define croak_nocontext croak
187 #endif
188
189 #ifndef croak_no_modify
190 #define croak_no_modify() croak_nocontext("%s", PL_no_modify)
191 #define Perl_croak_no_modify() croak_no_modify()
192 #endif
193
194 #ifndef croak_memory_wrap
195 #if { VERSION >= 5.9.2 } || ( { VERSION >= 5.8.6 } && { VERSION < 5.9.0 } )
196 #  define croak_memory_wrap() croak_nocontext("%s", PL_memory_wrap)
197 #else
198 #  define croak_memory_wrap() croak_nocontext("panic: memory wrap")
199 #endif
200 #endif
201
202 #ifndef PERL_ARGS_ASSERT_CROAK_XS_USAGE
203 #define PERL_ARGS_ASSERT_CROAK_XS_USAGE assert(cv); assert(params)
204 #endif
205
206 #ifndef croak_xs_usage
207 #if { NEED croak_xs_usage }
208 void
209 croak_xs_usage(const CV *const cv, const char *const params)
210 {
211     dTHX;
212     const GV *const gv = CvGV(cv);
213
214     PERL_ARGS_ASSERT_CROAK_XS_USAGE;
215
216     if (gv) {
217         const char *const gvname = GvNAME(gv);
218         const HV *const stash = GvSTASH(gv);
219         const char *const hvname = stash ? HvNAME(stash) : NULL;
220
221         if (hvname)
222             croak("Usage: %s::%s(%s)", hvname, gvname, params);
223         else
224             croak("Usage: %s(%s)", gvname, params);
225     } else {
226         /* Pants. I don't think that it should be possible to get here. */
227         croak("Usage: CODE(0x%" UVxf ")(%s)", PTR2UV(cv), params);
228     }
229 }
230 #endif
231 #endif
232
233 =xsinit
234
235 #define NEED_die_sv
236 #define NEED_mess_sv
237 #define NEED_croak_xs_usage
238
239 =xsubs
240
241 void
242 croak_sv(sv)
243     SV *sv
244 CODE:
245     croak_sv(sv);
246
247 void
248 die_sv(sv)
249     SV *sv
250 CODE:
251     (void)die_sv(sv);
252
253 void
254 warn_sv(sv)
255     SV *sv
256 CODE:
257     warn_sv(sv);
258
259 SV *
260 mess_sv(sv, consume)
261     SV *sv
262     bool consume
263 CODE:
264     RETVAL = newSVsv(mess_sv(sv, consume));
265 OUTPUT:
266     RETVAL
267
268 void
269 croak_no_modify()
270 CODE:
271     croak_no_modify();
272
273 void
274 croak_memory_wrap()
275 CODE:
276     croak_memory_wrap();
277
278 void
279 croak_xs_usage(params)
280     char *params
281 CODE:
282     croak_xs_usage(cv, params);
283
284 =tests plan => 93
285
286 BEGIN { if ($] lt '5.006') { $^W = 0; } }
287
288 my $warn;
289 my $die;
290 local $SIG{__WARN__} = sub { $warn = $_[0] };
291 local $SIG{__DIE__} = sub { $die = $_[0] };
292
293 my $scalar_ref = \do {my $tmp = 10};
294 my $array_ref = [];
295 my $hash_ref = {};
296 my $obj = bless {}, 'Package';
297
298 undef $die;
299 ok !defined eval { Devel::PPPort::croak_sv("\xE1\n") };
300 ok $@, "\xE1\n";
301 ok $die, "\xE1\n";
302
303 undef $die;
304 ok !defined eval { Devel::PPPort::croak_sv(10) };
305 ok $@ =~ /^10 at $0 line /;
306 ok $die =~ /^10 at $0 line /;
307
308 undef $die;
309 $@ = 'should not be visible (1)';
310 ok !defined eval {
311     $@ = 'should not be visible (2)';
312     Devel::PPPort::croak_sv('');
313 };
314 ok $@ =~ /^ at $0 line /;
315 ok $die =~ /^ at $0 line /;
316
317 undef $die;
318 $@ = 'should not be visible';
319 ok !defined eval {
320     $@ = 'this must be visible';
321     Devel::PPPort::croak_sv($@)
322 };
323 ok $@ =~ /^this must be visible at $0 line /;
324 ok $die =~ /^this must be visible at $0 line /;
325
326 undef $die;
327 $@ = 'should not be visible';
328 ok !defined eval {
329     $@ = "this must be visible\n";
330     Devel::PPPort::croak_sv($@)
331 };
332 ok $@, "this must be visible\n";
333 ok $die, "this must be visible\n";
334
335 undef $die;
336 ok !defined eval { Devel::PPPort::croak_sv('') };
337 ok $@ =~ /^ at $0 line /;
338 ok $die =~ /^ at $0 line /;
339
340 undef $die;
341 ok !defined eval { Devel::PPPort::croak_sv("\xE1") };
342 ok $@ =~ /^\xE1 at $0 line /;
343 ok $die =~ /^\xE1 at $0 line /;
344
345 undef $die;
346 ok !defined eval { Devel::PPPort::croak_sv("\xC3\xA1") };
347 ok $@ =~ /^\xC3\xA1 at $0 line /;
348 ok $die =~ /^\xC3\xA1 at $0 line /;
349
350 undef $warn;
351 Devel::PPPort::warn_sv("\xE1\n");
352 ok $warn, "\xE1\n";
353
354 undef $warn;
355 Devel::PPPort::warn_sv(10);
356 ok $warn =~ /^10 at $0 line /;
357
358 undef $warn;
359 Devel::PPPort::warn_sv('');
360 ok $warn =~ /^ at $0 line /;
361
362 undef $warn;
363 Devel::PPPort::warn_sv("\xE1");
364 ok $warn =~ /^\xE1 at $0 line /;
365
366 undef $warn;
367 Devel::PPPort::warn_sv("\xC3\xA1");
368 ok $warn =~ /^\xC3\xA1 at $0 line /;
369
370 ok Devel::PPPort::mess_sv("\xE1\n", 0), "\xE1\n";
371 ok Devel::PPPort::mess_sv(do {my $tmp = "\xE1\n"}, 1), "\xE1\n";
372
373 ok Devel::PPPort::mess_sv(10, 0) =~ /^10 at $0 line /;
374 ok Devel::PPPort::mess_sv(do {my $tmp = 10}, 1) =~ /^10 at $0 line /;
375
376 ok Devel::PPPort::mess_sv('', 0) =~ /^ at $0 line /;
377 ok Devel::PPPort::mess_sv(do {my $tmp = ''}, 1) =~ /^ at $0 line /;
378
379 ok Devel::PPPort::mess_sv("\xE1", 0) =~ /^\xE1 at $0 line /;
380 ok Devel::PPPort::mess_sv(do {my $tmp = "\xE1"}, 1) =~ /^\xE1 at $0 line /;
381
382 ok Devel::PPPort::mess_sv("\xC3\xA1", 0) =~ /^\xC3\xA1 at $0 line /;
383 ok Devel::PPPort::mess_sv(do {my $tmp = "\xC3\xA1"}, 1) =~ /^\xC3\xA1 at $0 line /;
384
385 if ($] ge '5.006') {
386     BEGIN { if ($] ge '5.006' && $] lt '5.008') { require utf8; utf8->import(); } }
387
388     undef $die;
389     ok !defined eval { Devel::PPPort::croak_sv("\x{100}\n") };
390     ok $@, "\x{100}\n";
391     if ($] ne '5.008') {
392         ok $die, "\x{100}\n";
393     } else {
394         skip 'skip: broken utf8 support in die hook', 0;
395     }
396
397     undef $die;
398     ok !defined eval { Devel::PPPort::croak_sv("\x{100}") };
399     ok $@ =~ /^\x{100} at $0 line /;
400     if ($] ne '5.008') {
401         ok $die =~ /^\x{100} at $0 line /;
402     } else {
403         skip 'skip: broken utf8 support in die hook', 0;
404     }
405
406     if ($] ne '5.008') {
407         undef $warn;
408         Devel::PPPort::warn_sv("\x{100}\n");
409         ok $warn, "\x{100}\n";
410
411         undef $warn;
412         Devel::PPPort::warn_sv("\x{100}");
413         ok (my $tmp = $warn) =~ /^\x{100} at $0 line /;
414     } else {
415         skip 'skip: broken utf8 support in warn hook', 0 for 1..2;
416     }
417
418     ok Devel::PPPort::mess_sv("\x{100}\n", 0), "\x{100}\n";
419     ok Devel::PPPort::mess_sv(do {my $tmp = "\x{100}\n"}, 1), "\x{100}\n";
420
421     ok Devel::PPPort::mess_sv("\x{100}", 0) =~ /^\x{100} at $0 line /;
422     ok Devel::PPPort::mess_sv(do {my $tmp = "\x{100}"}, 1) =~ /^\x{100} at $0 line /;
423 } else {
424     skip 'skip: no utf8 support', 0 for 1..12;
425 }
426
427 if (ord('A') != 65) {
428     skip 'skip: no ASCII support', 0 for 1..24;
429 } elsif ($] ge '5.008' && $] ne '5.012000') {
430     undef $die;
431     ok !defined eval { Devel::PPPort::croak_sv(eval '"\N{U+E1}\n"') };
432     ok $@, "\xE1\n";
433     ok $die, "\xE1\n";
434
435     undef $die;
436     ok !defined eval { Devel::PPPort::croak_sv(eval '"\N{U+E1}"') };
437     ok $@ =~ /^\xE1 at $0 line /;
438     ok $die =~ /^\xE1 at $0 line /;
439
440     {
441         undef $die;
442         my $expect = eval '"\N{U+C3}\N{U+A1}\n"';
443         ok !defined eval { Devel::PPPort::croak_sv("\xC3\xA1\n") };
444         ok $@, $expect;
445         ok $die, $expect;
446     }
447
448     {
449         undef $die;
450         my $expect = eval 'qr/^\N{U+C3}\N{U+A1} at $0 line /';
451         ok !defined eval { Devel::PPPort::croak_sv("\xC3\xA1") };
452         ok $@ =~ $expect;
453         ok $die =~ $expect;
454     }
455
456     undef $warn;
457     Devel::PPPort::warn_sv(eval '"\N{U+E1}\n"');
458     ok $warn, "\xE1\n";
459
460     undef $warn;
461     Devel::PPPort::warn_sv(eval '"\N{U+E1}"');
462     ok $warn =~ /^\xE1 at $0 line /;
463
464     undef $warn;
465     Devel::PPPort::warn_sv("\xC3\xA1\n");
466     ok $warn, eval '"\N{U+C3}\N{U+A1}\n"';
467
468     undef $warn;
469     Devel::PPPort::warn_sv("\xC3\xA1");
470     ok $warn =~ eval 'qr/^\N{U+C3}\N{U+A1} at $0 line /';
471
472     ok Devel::PPPort::mess_sv(eval('"\N{U+E1}\n"'), 0), eval '"\N{U+E1}\n"';
473     ok Devel::PPPort::mess_sv(do {my $tmp = eval '"\N{U+E1}\n"'}, 1), eval '"\N{U+E1}\n"';
474
475     ok Devel::PPPort::mess_sv(eval('"\N{U+E1}"'), 0) =~ eval 'qr/^\N{U+E1} at $0 line /';
476     ok Devel::PPPort::mess_sv(do {my $tmp = eval '"\N{U+E1}"'}, 1) =~ eval 'qr/^\N{U+E1} at $0 line /';
477
478     ok Devel::PPPort::mess_sv("\xC3\xA1\n", 0), eval '"\N{U+C3}\N{U+A1}\n"';
479     ok Devel::PPPort::mess_sv(do {my $tmp = "\xC3\xA1\n"}, 1), eval '"\N{U+C3}\N{U+A1}\n"';
480
481     ok Devel::PPPort::mess_sv("\xC3\xA1", 0) =~ eval 'qr/^\N{U+C3}\N{U+A1} at $0 line /';
482     ok Devel::PPPort::mess_sv(do {my $tmp = "\xC3\xA1"}, 1) =~ eval 'qr/^\N{U+C3}\N{U+A1} at $0 line /';
483 } else {
484     skip 'skip: no support for \N{U+..} syntax', 0 for 1..24;
485 }
486
487 if ($] ge '5.007003' or ($] ge '5.006001' and $] lt '5.007')) {
488     undef $die;
489     ok !defined eval { Devel::PPPort::croak_sv($scalar_ref) };
490     ok $@ == $scalar_ref;
491     ok $die == $scalar_ref;
492
493     undef $die;
494     ok !defined eval { Devel::PPPort::croak_sv($array_ref) };
495     ok $@ == $array_ref;
496     ok $die == $array_ref;
497
498     undef $die;
499     ok !defined eval { Devel::PPPort::croak_sv($hash_ref) };
500     ok $@ == $hash_ref;
501     ok $die == $hash_ref;
502
503     undef $die;
504     ok !defined eval { Devel::PPPort::croak_sv($obj) };
505     ok $@ == $obj;
506     ok $die == $obj;
507 } else {
508     skip 'skip: no support for exceptions', 0 for 1..12;
509 }
510
511 ok !defined eval { Devel::PPPort::croak_no_modify() };
512 ok $@ =~ /^Modification of a read-only value attempted at $0 line /;
513
514 ok !defined eval { Devel::PPPort::croak_memory_wrap() };
515 ok $@ =~ /^panic: memory wrap at $0 line /;
516
517 ok !defined eval { Devel::PPPort::croak_xs_usage("params") };
518 ok $@ =~ /^Usage: Devel::PPPort::croak_xs_usage\(params\) at $0 line /;