line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
#include "EXTERN.h" |
2
|
|
|
|
|
|
|
#include "perl.h" |
3
|
|
|
|
|
|
|
#include "XSUB.h" |
4
|
|
|
|
|
|
|
#include "ppport.h" |
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
#define SAVE_AND_REPLACE_PP_IF_UNSET(real_function, op_to_replace, overload_function, OP_replace_mutex) do {\ |
7
|
|
|
|
|
|
|
MUTEX_LOCK(&OP_replace_mutex);\ |
8
|
|
|
|
|
|
|
if (!real_function) {\ |
9
|
|
|
|
|
|
|
real_function = PL_ppaddr[op_to_replace];\ |
10
|
|
|
|
|
|
|
}\ |
11
|
|
|
|
|
|
|
if (PL_ppaddr[op_to_replace] != overload_function) {\ |
12
|
|
|
|
|
|
|
PL_ppaddr[op_to_replace] = overload_function;\ |
13
|
|
|
|
|
|
|
}\ |
14
|
|
|
|
|
|
|
else {\ |
15
|
|
|
|
|
|
|
/* Would be nice if we could warn here. */\ |
16
|
|
|
|
|
|
|
}\ |
17
|
|
|
|
|
|
|
MUTEX_UNLOCK(&OP_replace_mutex);\ |
18
|
|
|
|
|
|
|
} while (0) |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
#define overload_open_die_with_xs_sub 1 |
21
|
|
|
|
|
|
|
#define overload_open_max_function_pointers 2 |
22
|
|
|
|
|
|
|
OP* (*stuff_array[overload_open_max_function_pointers])(pTHX); |
23
|
|
|
|
|
|
|
/* Declare function pointers for OP's */ |
24
|
|
|
|
|
|
|
OP* (*real_pp_open)(pTHX) = NULL; |
25
|
|
|
|
|
|
|
OP* (*real_pp_sysopen)(pTHX) = NULL; |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
#define overload_open_max_args 99 |
28
|
|
|
|
|
|
|
#ifdef USE_ITHREADS |
29
|
|
|
|
|
|
|
static perl_mutex OP_OPEN_replace_mutex; |
30
|
|
|
|
|
|
|
static perl_mutex OP_SYSOPEN_replace_mutex; |
31
|
|
|
|
|
|
|
#endif |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
OP * (*real_pp_open)(pTHX); |
34
|
|
|
|
|
|
|
OP * (*real_pp_sysopen)(pTHX); |
35
|
|
|
|
|
|
|
SV * cached_hook_open = NULL; |
36
|
|
|
|
|
|
|
SV * cached_hook_sysopen = NULL; |
37
|
|
|
|
|
|
|
CV * cached_code_hook_open = NULL; |
38
|
|
|
|
|
|
|
CV * cached_code_hook_sysopen = NULL; |
39
|
15
|
|
|
|
|
|
bool overload_is_sysopen(char *opname) { |
40
|
15
|
|
|
|
|
|
return strcmp(opname, "sysopen") == 0; |
41
|
|
|
|
|
|
|
} |
42
|
15
|
|
|
|
|
|
bool overload_is_open(char *opname) { |
43
|
15
|
|
|
|
|
|
return strcmp(opname, "open") == 0; |
44
|
|
|
|
|
|
|
} |
45
|
15
|
|
|
|
|
|
void set_cached_hooks_for_op (char *opname, SV *hook, CV *code_hook) { |
46
|
15
|
100
|
|
|
|
|
if (overload_is_open(opname)) { |
47
|
10
|
|
|
|
|
|
cached_hook_open = hook; |
48
|
10
|
|
|
|
|
|
cached_code_hook_open = code_hook; |
49
|
|
|
|
|
|
|
} |
50
|
15
|
100
|
|
|
|
|
if (overload_is_sysopen(opname)) { |
51
|
5
|
|
|
|
|
|
cached_hook_sysopen = hook; |
52
|
5
|
|
|
|
|
|
cached_code_hook_sysopen = code_hook; |
53
|
|
|
|
|
|
|
} |
54
|
15
|
|
|
|
|
|
} |
55
|
16
|
|
|
|
|
|
OP * overload_allopen(char *opname, char *global, OP* (*real_pp_func)(pTHX)) { |
56
|
16
|
|
|
|
|
|
SV *hook = get_sv(global, 0); |
57
|
|
|
|
|
|
|
/* If the hook evaluates as false, we should just call the original |
58
|
|
|
|
|
|
|
* function ( AKA overload::open->prehook_open() has not been called yet ) */ |
59
|
16
|
50
|
|
|
|
|
if ( !hook || !SvTRUE( hook ) ) { |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
60
|
3
|
|
|
|
|
|
set_cached_hooks_for_op(opname, NULL, NULL); |
61
|
3
|
|
|
|
|
|
return real_pp_func(aTHXR); |
62
|
|
|
|
|
|
|
} |
63
|
|
|
|
|
|
|
/* Check to make sure we have a coderef */ |
64
|
13
|
50
|
|
|
|
|
if ( !SvROK( hook ) || SvTYPE( SvRV(hook) ) != SVt_PVCV ) { |
|
|
50
|
|
|
|
|
|
65
|
0
|
|
|
|
|
|
set_cached_hooks_for_op(opname, NULL, NULL); |
66
|
0
|
|
|
|
|
|
warn("override::open expected a code reference, but got something else"); |
67
|
0
|
|
|
|
|
|
return real_pp_func(aTHXR); |
68
|
|
|
|
|
|
|
} |
69
|
|
|
|
|
|
|
/* Get the CV* that the reference refers to */ |
70
|
13
|
|
|
|
|
|
CV* code_hook = (CV*) SvRV(hook); |
71
|
13
|
100
|
|
|
|
|
if ( CvISXSUB( code_hook ) ) { |
72
|
|
|
|
|
|
|
if ( overload_open_die_with_xs_sub ) |
73
|
1
|
|
|
|
|
|
die("overload::open error. Cowardly refusing to hook an XS sub into %s", opname); |
74
|
|
|
|
|
|
|
return real_pp_func(aTHXR); |
75
|
|
|
|
|
|
|
} |
76
|
|
|
|
|
|
|
/* Found suitable hook. We can cache in now */ |
77
|
12
|
|
|
|
|
|
set_cached_hooks_for_op(opname, hook, code_hook); |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
/* CvDEPTH > 0 that means our hook is calling OP_OPEN. This is ok |
80
|
|
|
|
|
|
|
* just ensure we direct things to the original function */ |
81
|
|
|
|
|
|
|
/* calling on the cached allows us to check the depth for both of the code functions */ |
82
|
12
|
100
|
|
|
|
|
if (cached_code_hook_open) { |
83
|
11
|
100
|
|
|
|
|
if ( 0 < CvDEPTH( cached_code_hook_open ) ) { |
84
|
3
|
|
|
|
|
|
return real_pp_func(aTHXR); |
85
|
|
|
|
|
|
|
} |
86
|
|
|
|
|
|
|
} |
87
|
9
|
100
|
|
|
|
|
if (cached_code_hook_sysopen) { |
88
|
6
|
50
|
|
|
|
|
if ( 0 < CvDEPTH( cached_code_hook_sysopen ) ) { |
89
|
0
|
|
|
|
|
|
return real_pp_func(aTHXR); |
90
|
|
|
|
|
|
|
} |
91
|
|
|
|
|
|
|
} |
92
|
|
|
|
|
|
|
/* Once more for paranoia */ |
93
|
9
|
50
|
|
|
|
|
if ( 0 < CvDEPTH( code_hook ) ) { |
94
|
0
|
|
|
|
|
|
return real_pp_func(aTHXR); |
95
|
|
|
|
|
|
|
} |
96
|
9
|
|
|
|
|
|
SV **sp = PL_stack_sp; |
97
|
9
|
|
|
|
|
|
ENTER; |
98
|
|
|
|
|
|
|
/* Save the temporaries stack */ |
99
|
9
|
|
|
|
|
|
SAVETMPS; |
100
|
|
|
|
|
|
|
/* sp (stack pointer) is used by some macros we call below. mysp is *ours* */ |
101
|
|
|
|
|
|
|
/* Save the stack pointer location */ |
102
|
9
|
|
|
|
|
|
SV **mysp = PL_stack_sp; |
103
|
|
|
|
|
|
|
/* Save the number of items (number of arguments) */ |
104
|
9
|
50
|
|
|
|
|
PUSHMARK(sp); |
105
|
9
|
|
|
|
|
|
ssize_t myitems = *PL_markstack_ptr; |
106
|
9
|
50
|
|
|
|
|
if (myitems < 0) { |
107
|
0
|
|
|
|
|
|
DIE(aTHXR_ "panic: overload::open internal error. This should not happen."); |
108
|
|
|
|
|
|
|
} |
109
|
9
|
50
|
|
|
|
|
EXTEND(sp, myitems); |
|
|
50
|
|
|
|
|
|
110
|
|
|
|
|
|
|
ssize_t c; |
111
|
35
|
100
|
|
|
|
|
for ( c = 0; c < myitems; c++) { |
112
|
|
|
|
|
|
|
/* We are going from last to first */ |
113
|
26
|
|
|
|
|
|
ssize_t i = myitems - 1 - c; |
114
|
26
|
|
|
|
|
|
mPUSHs( newSVsv(*(mysp - i)) ); |
115
|
|
|
|
|
|
|
} |
116
|
|
|
|
|
|
|
/* PL_stack_sp = sp */ |
117
|
9
|
|
|
|
|
|
PUTBACK; /* Closing bracket for XSUB arguments */ |
118
|
9
|
|
|
|
|
|
I32 count = call_sv( (SV*)code_hook, G_VOID | G_DISCARD|G_EVAL |G_KEEPERR); |
119
|
|
|
|
|
|
|
/* G_VOID and G_DISCARD should cause us to not ask for any return |
120
|
|
|
|
|
|
|
* arguments from the call. */ |
121
|
9
|
50
|
|
|
|
|
if (count) warn("call_sv was not supposed to get any arguments"); |
122
|
|
|
|
|
|
|
/* The purpose of the macro "SPAGAIN" is to refresh the local copy of |
123
|
|
|
|
|
|
|
* the stack pointer. This is necessary because it is possible that |
124
|
|
|
|
|
|
|
* the memory allocated to the Perl stack has been reallocated during |
125
|
|
|
|
|
|
|
* the *call_pv* call */ |
126
|
|
|
|
|
|
|
/* sp = PL_stack_sp */ |
127
|
9
|
|
|
|
|
|
SPAGAIN; |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
/* FREETMPS cleans up all stuff on the temporaries stack added since SAVETMPS was called */ |
130
|
9
|
50
|
|
|
|
|
FREETMPS; |
131
|
9
|
|
|
|
|
|
LEAVE; |
132
|
9
|
|
|
|
|
|
return real_pp_func(aTHXR); |
133
|
|
|
|
|
|
|
} |
134
|
|
|
|
|
|
|
|
135
|
11
|
|
|
|
|
|
PP(pp_overload_open) { |
136
|
11
|
|
|
|
|
|
return overload_allopen("open", "overload::open::GLOBAL_OPEN", real_pp_open); |
137
|
|
|
|
|
|
|
} |
138
|
|
|
|
|
|
|
|
139
|
5
|
|
|
|
|
|
PP(pp_overload_sysopen) { |
140
|
5
|
|
|
|
|
|
return overload_allopen("sysopen", "overload::open::GLOBAL_SYSOPEN", |
141
|
|
|
|
|
|
|
real_pp_sysopen); |
142
|
|
|
|
|
|
|
} |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
MODULE = overload::open PACKAGE = overload::open PREFIX = overload_open_ |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
PROTOTYPES: ENABLE |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
void |
149
|
|
|
|
|
|
|
_test_xs_function(...) |
150
|
|
|
|
|
|
|
CODE: |
151
|
0
|
|
|
|
|
|
printf("running test xs function\n"); |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
void |
154
|
|
|
|
|
|
|
_install_open() |
155
|
|
|
|
|
|
|
CODE: |
156
|
5
|
50
|
|
|
|
|
SAVE_AND_REPLACE_PP_IF_UNSET(real_pp_open, OP_OPEN, Perl_pp_overload_open, OP_OPEN_replace_mutex); |
|
|
50
|
|
|
|
|
|
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
void |
159
|
|
|
|
|
|
|
_install_sysopen() |
160
|
|
|
|
|
|
|
CODE: |
161
|
5
|
50
|
|
|
|
|
SAVE_AND_REPLACE_PP_IF_UNSET(real_pp_sysopen, OP_SYSOPEN, Perl_pp_overload_sysopen, OP_SYSOPEN_replace_mutex); |
|
|
50
|
|
|
|
|
|