This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Devel-PPPort: Rmv impediment to compiling under C++11
[perl5.git] / dist / Devel-PPPort / parts / inc / magic
CommitLineData
adfe19db
MHM
1################################################################################
2##
b2049988 3## Version 3.x, Copyright (C) 2004-2013, Marcus Holland-Moritz.
adfe19db
MHM
4## Version 2.x, Copyright (C) 2001, Paul Marquess.
5## Version 1.x, Copyright (C) 1999, Kenneth Albanowski.
6##
7## This program is free software; you can redistribute it and/or
8## modify it under the same terms as Perl itself.
9##
10################################################################################
11
12=provides
13
ea4b7f32
JH
14mg_findext
15sv_unmagicext
16
adfe19db
MHM
17__UNDEFINED__
18/sv_\w+_mg/
679ad62d 19sv_magic_portable
ea4b7f32
JH
20MUTABLE_PTR
21MUTABLE_SV
adfe19db
MHM
22
23=implementation
24
25__UNDEFINED__ SvGETMAGIC(x) STMT_START { if (SvGMAGICAL(x)) mg_get(x); } STMT_END
26
ea4b7f32
JH
27/* Some random bits for sv_unmagicext. These should probably be pulled in for
28 real and organized at some point */
29
30__UNDEFINED__ HEf_SVKEY -2
31
94e22bd6 32#ifndef MUTABLE_PTR
ea4b7f32
JH
33#if defined(__GNUC__) && !defined(PERL_GCC_BRACE_GROUPS_FORBIDDEN)
34# define MUTABLE_PTR(p) ({ void *_p = (p); _p; })
35#else
36# define MUTABLE_PTR(p) ((void *) (p))
37#endif
94e22bd6 38#endif
ea4b7f32 39
94e22bd6 40__UNDEFINED__ MUTABLE_SV(p) ((SV *)MUTABLE_PTR(p))
ea4b7f32
JH
41
42/* end of random bits */
43
adfe19db
MHM
44__UNDEFINED__ PERL_MAGIC_sv '\0'
45__UNDEFINED__ PERL_MAGIC_overload 'A'
46__UNDEFINED__ PERL_MAGIC_overload_elem 'a'
47__UNDEFINED__ PERL_MAGIC_overload_table 'c'
48__UNDEFINED__ PERL_MAGIC_bm 'B'
49__UNDEFINED__ PERL_MAGIC_regdata 'D'
50__UNDEFINED__ PERL_MAGIC_regdatum 'd'
51__UNDEFINED__ PERL_MAGIC_env 'E'
52__UNDEFINED__ PERL_MAGIC_envelem 'e'
53__UNDEFINED__ PERL_MAGIC_fm 'f'
54__UNDEFINED__ PERL_MAGIC_regex_global 'g'
55__UNDEFINED__ PERL_MAGIC_isa 'I'
56__UNDEFINED__ PERL_MAGIC_isaelem 'i'
57__UNDEFINED__ PERL_MAGIC_nkeys 'k'
58__UNDEFINED__ PERL_MAGIC_dbfile 'L'
59__UNDEFINED__ PERL_MAGIC_dbline 'l'
60__UNDEFINED__ PERL_MAGIC_mutex 'm'
61__UNDEFINED__ PERL_MAGIC_shared 'N'
62__UNDEFINED__ PERL_MAGIC_shared_scalar 'n'
63__UNDEFINED__ PERL_MAGIC_collxfrm 'o'
64__UNDEFINED__ PERL_MAGIC_tied 'P'
65__UNDEFINED__ PERL_MAGIC_tiedelem 'p'
66__UNDEFINED__ PERL_MAGIC_tiedscalar 'q'
67__UNDEFINED__ PERL_MAGIC_qr 'r'
68__UNDEFINED__ PERL_MAGIC_sig 'S'
69__UNDEFINED__ PERL_MAGIC_sigelem 's'
70__UNDEFINED__ PERL_MAGIC_taint 't'
71__UNDEFINED__ PERL_MAGIC_uvar 'U'
72__UNDEFINED__ PERL_MAGIC_uvar_elem 'u'
73__UNDEFINED__ PERL_MAGIC_vstring 'V'
74__UNDEFINED__ PERL_MAGIC_vec 'v'
75__UNDEFINED__ PERL_MAGIC_utf8 'w'
76__UNDEFINED__ PERL_MAGIC_substr 'x'
77__UNDEFINED__ PERL_MAGIC_defelem 'y'
78__UNDEFINED__ PERL_MAGIC_glob '*'
79__UNDEFINED__ PERL_MAGIC_arylen '#'
80__UNDEFINED__ PERL_MAGIC_pos '.'
81__UNDEFINED__ PERL_MAGIC_backref '<'
82__UNDEFINED__ PERL_MAGIC_ext '~'
83
84/* That's the best we can do... */
adfe19db
MHM
85__UNDEFINED__ sv_catpvn_nomg sv_catpvn
86__UNDEFINED__ sv_catsv_nomg sv_catsv
87__UNDEFINED__ sv_setsv_nomg sv_setsv
88__UNDEFINED__ sv_pvn_nomg sv_pvn
89__UNDEFINED__ SvIV_nomg SvIV
90__UNDEFINED__ SvUV_nomg SvUV
91
92#ifndef sv_catpv_mg
93# define sv_catpv_mg(sv, ptr) \
94 STMT_START { \
95 SV *TeMpSv = sv; \
96 sv_catpv(TeMpSv,ptr); \
97 SvSETMAGIC(TeMpSv); \
98 } STMT_END
99#endif
100
101#ifndef sv_catpvn_mg
102# define sv_catpvn_mg(sv, ptr, len) \
103 STMT_START { \
104 SV *TeMpSv = sv; \
105 sv_catpvn(TeMpSv,ptr,len); \
106 SvSETMAGIC(TeMpSv); \
107 } STMT_END
108#endif
109
110#ifndef sv_catsv_mg
111# define sv_catsv_mg(dsv, ssv) \
112 STMT_START { \
113 SV *TeMpSv = dsv; \
114 sv_catsv(TeMpSv,ssv); \
115 SvSETMAGIC(TeMpSv); \
116 } STMT_END
117#endif
118
119#ifndef sv_setiv_mg
120# define sv_setiv_mg(sv, i) \
121 STMT_START { \
122 SV *TeMpSv = sv; \
123 sv_setiv(TeMpSv,i); \
124 SvSETMAGIC(TeMpSv); \
125 } STMT_END
126#endif
127
128#ifndef sv_setnv_mg
129# define sv_setnv_mg(sv, num) \
130 STMT_START { \
131 SV *TeMpSv = sv; \
132 sv_setnv(TeMpSv,num); \
133 SvSETMAGIC(TeMpSv); \
134 } STMT_END
135#endif
136
137#ifndef sv_setpv_mg
138# define sv_setpv_mg(sv, ptr) \
139 STMT_START { \
140 SV *TeMpSv = sv; \
141 sv_setpv(TeMpSv,ptr); \
142 SvSETMAGIC(TeMpSv); \
143 } STMT_END
144#endif
145
146#ifndef sv_setpvn_mg
147# define sv_setpvn_mg(sv, ptr, len) \
148 STMT_START { \
149 SV *TeMpSv = sv; \
150 sv_setpvn(TeMpSv,ptr,len); \
151 SvSETMAGIC(TeMpSv); \
152 } STMT_END
153#endif
154
155#ifndef sv_setsv_mg
156# define sv_setsv_mg(dsv, ssv) \
157 STMT_START { \
158 SV *TeMpSv = dsv; \
159 sv_setsv(TeMpSv,ssv); \
160 SvSETMAGIC(TeMpSv); \
161 } STMT_END
162#endif
163
164#ifndef sv_setuv_mg
165# define sv_setuv_mg(sv, i) \
166 STMT_START { \
167 SV *TeMpSv = sv; \
168 sv_setuv(TeMpSv,i); \
169 SvSETMAGIC(TeMpSv); \
170 } STMT_END
171#endif
172
173#ifndef sv_usepvn_mg
174# define sv_usepvn_mg(sv, ptr, len) \
175 STMT_START { \
176 SV *TeMpSv = sv; \
177 sv_usepvn(TeMpSv,ptr,len); \
178 SvSETMAGIC(TeMpSv); \
179 } STMT_END
180#endif
181
f2ab5a41
MHM
182__UNDEFINED__ SvVSTRING_mg(sv) (SvMAGICAL(sv) ? mg_find(sv, PERL_MAGIC_vstring) : NULL)
183
679ad62d
MHM
184/* Hint: sv_magic_portable
185 * This is a compatibility function that is only available with
186 * Devel::PPPort. It is NOT in the perl core.
187 * Its purpose is to mimic the 5.8.0 behaviour of sv_magic() when
188 * it is being passed a name pointer with namlen == 0. In that
189 * case, perl 5.8.0 and later store the pointer, not a copy of it.
190 * The compatibility can be provided back to perl 5.004. With
191 * earlier versions, the code will not compile.
192 */
193
194#if { VERSION < 5.004 }
195
196 /* code that uses sv_magic_portable will not compile */
197
198#elif { VERSION < 5.8.0 }
199
c83e6f19
MHM
200# define sv_magic_portable(sv, obj, how, name, namlen) \
201 STMT_START { \
202 SV *SvMp_sv = (sv); \
203 char *SvMp_name = (char *) (name); \
204 I32 SvMp_namlen = (namlen); \
205 if (SvMp_name && SvMp_namlen == 0) \
206 { \
207 MAGIC *mg; \
208 sv_magic(SvMp_sv, obj, how, 0, 0); \
209 mg = SvMAGIC(SvMp_sv); \
210 mg->mg_len = -42; /* XXX: this is the tricky part */ \
211 mg->mg_ptr = SvMp_name; \
212 } \
213 else \
214 { \
215 sv_magic(SvMp_sv, obj, how, SvMp_name, SvMp_namlen); \
216 } \
679ad62d
MHM
217 } STMT_END
218
219#else
220
221# define sv_magic_portable(a, b, c, d, e) sv_magic(a, b, c, d, e)
222
223#endif
224
ea4b7f32
JH
225#if !defined(mg_findext)
226#if { NEED mg_findext }
227
228MAGIC *
744ef08f 229mg_findext(SV * sv, int type, const MGVTBL *vtbl) {
ea4b7f32
JH
230 if (sv) {
231 MAGIC *mg;
232
233#ifdef AvPAD_NAMELIST
744ef08f 234 assert(!(SvTYPE(sv) == SVt_PVAV && AvPAD_NAMELIST(sv)));
ea4b7f32
JH
235#endif
236
237 for (mg = SvMAGIC (sv); mg; mg = mg->mg_moremagic) {
238 if (mg->mg_type == type && mg->mg_virtual == vtbl)
239 return mg;
240 }
241 }
242
243 return NULL;
244}
245
246#endif
247#endif
248
249#if !defined(sv_unmagicext)
250#if { NEED sv_unmagicext }
251
252int
253sv_unmagicext(pTHX_ SV *const sv, const int type, MGVTBL *vtbl)
254{
255 MAGIC* mg;
256 MAGIC** mgp;
257
258 if (SvTYPE(sv) < SVt_PVMG || !SvMAGIC(sv))
259 return 0;
260 mgp = &(SvMAGIC(sv));
261 for (mg = *mgp; mg; mg = *mgp) {
262 const MGVTBL* const virt = mg->mg_virtual;
263 if (mg->mg_type == type && virt == vtbl) {
264 *mgp = mg->mg_moremagic;
265 if (virt && virt->svt_free)
266 virt->svt_free(aTHX_ sv, mg);
267 if (mg->mg_ptr && mg->mg_type != PERL_MAGIC_regex_global) {
268 if (mg->mg_len > 0)
269 Safefree(mg->mg_ptr);
270 else if (mg->mg_len == HEf_SVKEY) /* Questionable on older perls... */
271 SvREFCNT_dec(MUTABLE_SV(mg->mg_ptr));
272 else if (mg->mg_type == PERL_MAGIC_utf8)
273 Safefree(mg->mg_ptr);
274 }
275 if (mg->mg_flags & MGf_REFCOUNTED)
276 SvREFCNT_dec(mg->mg_obj);
277 Safefree(mg);
278 }
279 else
280 mgp = &mg->mg_moremagic;
281 }
282 if (SvMAGIC(sv)) {
283 if (SvMAGICAL(sv)) /* if we're under save_magic, wait for restore_magic; */
284 mg_magical(sv); /* else fix the flags now */
285 }
286 else {
287 SvMAGICAL_off(sv);
288 SvFLAGS(sv) |= (SvFLAGS(sv) & (SVp_IOK|SVp_NOK|SVp_POK)) >> PRIVSHIFT;
289 }
290 return 0;
291}
292
293#endif
294#endif
295
296=xsinit
297
298#define NEED_mg_findext
299#define NEED_sv_unmagicext
300
301#ifndef STATIC
302#define STATIC static
303#endif
304
305STATIC MGVTBL null_mg_vtbl = {
306 NULL, /* get */
307 NULL, /* set */
308 NULL, /* len */
309 NULL, /* clear */
310 NULL, /* free */
311#if MGf_COPY
312 NULL, /* copy */
313#endif /* MGf_COPY */
314#if MGf_DUP
315 NULL, /* dup */
316#endif /* MGf_DUP */
317#if MGf_LOCAL
318 NULL, /* local */
319#endif /* MGf_LOCAL */
320};
321
322STATIC MGVTBL other_mg_vtbl = {
323 NULL, /* get */
324 NULL, /* set */
325 NULL, /* len */
326 NULL, /* clear */
327 NULL, /* free */
328#if MGf_COPY
329 NULL, /* copy */
330#endif /* MGf_COPY */
331#if MGf_DUP
332 NULL, /* dup */
333#endif /* MGf_DUP */
334#if MGf_LOCAL
335 NULL, /* local */
336#endif /* MGf_LOCAL */
337};
338
adfe19db
MHM
339=xsubs
340
ea4b7f32
JH
341SV *
342new_with_other_mg(package, ...)
343 SV *package
344 PREINIT:
345 HV *self;
346 HV *stash;
347 SV *self_ref;
ea4b7f32
JH
348 const char *data = "hello\0";
349 MAGIC *mg;
350 CODE:
351 self = newHV();
352 stash = gv_stashpv(SvPV_nolen(package), 0);
353
354 self_ref = newRV_noinc((SV*)self);
355
356 sv_magic((SV*)self, NULL, PERL_MAGIC_ext, data, strlen(data));
357 mg = mg_find((SV*)self, PERL_MAGIC_ext);
494d0b3d
MH
358 if (mg)
359 mg->mg_virtual = &other_mg_vtbl;
360 else
361 croak("No mg!");
ea4b7f32
JH
362
363 RETVAL = sv_bless(self_ref, stash);
364 OUTPUT:
365 RETVAL
366
367SV *
368new_with_mg(package, ...)
369 SV *package
370 PREINIT:
371 HV *self;
372 HV *stash;
373 SV *self_ref;
ea4b7f32
JH
374 const char *data = "hello\0";
375 MAGIC *mg;
376 CODE:
377 self = newHV();
378 stash = gv_stashpv(SvPV_nolen(package), 0);
379
380 self_ref = newRV_noinc((SV*)self);
381
382 sv_magic((SV*)self, NULL, PERL_MAGIC_ext, data, strlen(data));
383 mg = mg_find((SV*)self, PERL_MAGIC_ext);
494d0b3d
MH
384 if (mg)
385 mg->mg_virtual = &null_mg_vtbl;
386 else
387 croak("No mg!");
ea4b7f32
JH
388
389 RETVAL = sv_bless(self_ref, stash);
390 OUTPUT:
391 RETVAL
392
393void
394remove_null_magic(self)
395 SV *self
396 PREINIT:
397 HV *obj;
398 PPCODE:
399 obj = (HV*) SvRV(self);
400
401 sv_unmagicext((SV*)obj, PERL_MAGIC_ext, &null_mg_vtbl);
402
403void
404remove_other_magic(self)
405 SV *self
406 PREINIT:
407 HV *obj;
408 PPCODE:
409 obj = (HV*) SvRV(self);
410
411 sv_unmagicext((SV*)obj, PERL_MAGIC_ext, &other_mg_vtbl);
412
413void
414as_string(self)
415 SV *self
416 PREINIT:
417 HV *obj;
418 MAGIC *mg;
419 PPCODE:
420 obj = (HV*) SvRV(self);
421
422 if ((mg = mg_findext((SV*)obj, PERL_MAGIC_ext, &null_mg_vtbl))) {
423 XPUSHs(sv_2mortal(newSVpv(mg->mg_ptr, strlen(mg->mg_ptr))));
424 } else {
744ef08f 425 XPUSHs(sv_2mortal(newSVpvs("Sorry, your princess is in another castle.")));
ea4b7f32
JH
426 }
427
adfe19db
MHM
428void
429sv_catpv_mg(sv, string)
b2049988
MHM
430 SV *sv;
431 char *string;
432 CODE:
433 sv_catpv_mg(sv, string);
adfe19db
MHM
434
435void
436sv_catpvn_mg(sv, sv2)
b2049988
MHM
437 SV *sv;
438 SV *sv2;
439 PREINIT:
440 char *str;
441 STRLEN len;
442 CODE:
443 str = SvPV(sv2, len);
444 sv_catpvn_mg(sv, str, len);
adfe19db
MHM
445
446void
447sv_catsv_mg(sv, sv2)
b2049988
MHM
448 SV *sv;
449 SV *sv2;
450 CODE:
451 sv_catsv_mg(sv, sv2);
adfe19db
MHM
452
453void
454sv_setiv_mg(sv, iv)
b2049988
MHM
455 SV *sv;
456 IV iv;
457 CODE:
458 sv_setiv_mg(sv, iv);
adfe19db
MHM
459
460void
461sv_setnv_mg(sv, nv)
b2049988
MHM
462 SV *sv;
463 NV nv;
464 CODE:
465 sv_setnv_mg(sv, nv);
adfe19db
MHM
466
467void
468sv_setpv_mg(sv, pv)
b2049988
MHM
469 SV *sv;
470 char *pv;
471 CODE:
472 sv_setpv_mg(sv, pv);
adfe19db
MHM
473
474void
475sv_setpvn_mg(sv, sv2)
b2049988
MHM
476 SV *sv;
477 SV *sv2;
478 PREINIT:
479 char *str;
480 STRLEN len;
481 CODE:
482 str = SvPV(sv2, len);
483 sv_setpvn_mg(sv, str, len);
adfe19db
MHM
484
485void
486sv_setsv_mg(sv, sv2)
b2049988
MHM
487 SV *sv;
488 SV *sv2;
489 CODE:
490 sv_setsv_mg(sv, sv2);
adfe19db
MHM
491
492void
493sv_setuv_mg(sv, uv)
b2049988
MHM
494 SV *sv;
495 UV uv;
496 CODE:
497 sv_setuv_mg(sv, uv);
adfe19db
MHM
498
499void
500sv_usepvn_mg(sv, sv2)
b2049988
MHM
501 SV *sv;
502 SV *sv2;
503 PREINIT:
504 char *str, *copy;
505 STRLEN len;
506 CODE:
507 str = SvPV(sv2, len);
508 New(42, copy, len+1, char);
509 Copy(str, copy, len+1, char);
510 sv_usepvn_mg(sv, copy, len);
adfe19db 511
f2ab5a41
MHM
512int
513SvVSTRING_mg(sv)
b2049988
MHM
514 SV *sv;
515 CODE:
516 RETVAL = SvVSTRING_mg(sv) != NULL;
517 OUTPUT:
518 RETVAL
f2ab5a41 519
679ad62d
MHM
520int
521sv_magic_portable(sv)
b2049988
MHM
522 SV *sv
523 PREINIT:
524 MAGIC *mg;
525 const char *foo = "foo";
526 CODE:
679ad62d 527#if { VERSION >= 5.004 }
b2049988
MHM
528 sv_magic_portable(sv, 0, '~', foo, 0);
529 mg = mg_find(sv, '~');
494d0b3d
MH
530 if (!mg)
531 croak("No mg!");
532
b2049988 533 RETVAL = mg->mg_ptr == foo;
679ad62d 534#else
b2049988
MHM
535 sv_magic(sv, 0, '~', (char *) foo, strlen(foo));
536 mg = mg_find(sv, '~');
537 RETVAL = strEQ(mg->mg_ptr, foo);
679ad62d 538#endif
b2049988
MHM
539 sv_unmagic(sv, '~');
540 OUTPUT:
541 RETVAL
679ad62d 542
ea4b7f32
JH
543=tests plan => 23
544
545# Find proper magic
546ok(my $obj1 = Devel::PPPort->new_with_mg());
547ok(Devel::PPPort::as_string($obj1), 'hello');
548
549# Find with no magic
550my $obj = bless {}, 'Fake::Class';
551ok(Devel::PPPort::as_string($obj), "Sorry, your princess is in another castle.");
552
553# Find with other magic (not the magic we are looking for)
554ok($obj = Devel::PPPort->new_with_other_mg());
555ok(Devel::PPPort::as_string($obj), "Sorry, your princess is in another castle.");
556
557# Okay, attempt to remove magic that isn't there
558Devel::PPPort::remove_other_magic($obj1);
559ok(Devel::PPPort::as_string($obj1), 'hello');
560
561# Remove magic that IS there
562Devel::PPPort::remove_null_magic($obj1);
563ok(Devel::PPPort::as_string($obj1), "Sorry, your princess is in another castle.");
564
565# Removing when no magic present
566Devel::PPPort::remove_null_magic($obj1);
567ok(Devel::PPPort::as_string($obj1), "Sorry, your princess is in another castle.");
adfe19db
MHM
568
569use Tie::Hash;
570my %h;
571tie %h, 'Tie::StdHash';
572$h{foo} = 'foo';
573$h{bar} = '';
574
575&Devel::PPPort::sv_catpv_mg($h{foo}, 'bar');
576ok($h{foo}, 'foobar');
577
578&Devel::PPPort::sv_catpvn_mg($h{bar}, 'baz');
579ok($h{bar}, 'baz');
580
581&Devel::PPPort::sv_catsv_mg($h{foo}, '42');
582ok($h{foo}, 'foobar42');
583
584&Devel::PPPort::sv_setiv_mg($h{bar}, 42);
585ok($h{bar}, 42);
586
587&Devel::PPPort::sv_setnv_mg($h{PI}, 3.14159);
588ok(abs($h{PI} - 3.14159) < 0.01);
589
590&Devel::PPPort::sv_setpv_mg($h{mhx}, 'mhx');
591ok($h{mhx}, 'mhx');
592
593&Devel::PPPort::sv_setpvn_mg($h{mhx}, 'Marcus');
594ok($h{mhx}, 'Marcus');
595
596&Devel::PPPort::sv_setsv_mg($h{sv}, 'SV');
597ok($h{sv}, 'SV');
598
599&Devel::PPPort::sv_setuv_mg($h{sv}, 4711);
600ok($h{sv}, 4711);
601
602&Devel::PPPort::sv_usepvn_mg($h{sv}, 'Perl');
603ok($h{sv}, 'Perl');
604
49ef49fe
CBW
605# v1 is treated as a bareword in older perls...
606my $ver = do { local $SIG{'__WARN__'} = sub {}; eval qq[v1.2.0] };
607ok($] < 5.009 || $@ eq '');
608ok($] < 5.009 || Devel::PPPort::SvVSTRING_mg($ver));
f2ab5a41
MHM
609ok(!Devel::PPPort::SvVSTRING_mg(4711));
610
679ad62d
MHM
611my $foo = 'bar';
612ok(Devel::PPPort::sv_magic_portable($foo));
613ok($foo eq 'bar');