]> git.vpit.fr Git - perl/modules/indirect.git/blob - indirect.xs
Consting
[perl/modules/indirect.git] / indirect.xs
1 #define PERL_NO_GET_CONTEXT
2 #include "EXTERN.h"
3 #include "perl.h"
4 #include "XSUB.h"
5
6 #ifndef SvPVX_const
7 # define SvPVX_const SvPVX
8 #endif
9
10 STATIC U32 indirect_initialized = 0;
11 STATIC U32 indirect_hash = 0;
12
13 STATIC const char indirect_msg[] = "Indirect call of method \"%s\" on object \"%s\"";
14
15 STATIC HV *indirect_map = NULL;
16 STATIC const char *indirect_linestr = NULL;
17
18 STATIC UV indirect_hint(pTHX) {
19 #define indirect_hint() indirect_hint(aTHX)
20  SV *id = Perl_refcounted_he_fetch(aTHX_ PL_curcop->cop_hints_hash,
21                                          NULL,
22                                          "indirect", 8,
23                                          0,
24                                          indirect_hash);
25  return SvOK(id) ? SvUV(id) : 0;
26 }
27
28 STATIC void indirect_map_store(pTHX_ const OP *o, const char *src, SV *sv) {
29 #define indirect_map_store(O, S, N) indirect_map_store(aTHX_ (O), (S), (N))
30  char buf[32];
31  const char *pl_linestr;
32  SV *val;
33
34  /* When lex_inwhat is set, we're in a quotelike environment (qq, qr, but not q)
35   * In this case the linestr has temporarly changed, but the old buffer should
36   * still be alive somewhere. */
37
38  if (!PL_parser->lex_inwhat) {
39   pl_linestr = SvPVX_const(PL_parser->linestr);
40   if (indirect_linestr != pl_linestr) {
41    hv_clear(indirect_map);
42    indirect_linestr = pl_linestr;
43   }
44  }
45
46  val = newSVsv(sv);
47  SvUPGRADE(val, SVt_PVIV);
48  SvUVX(val) = PTR2UV(src);
49  if (!hv_store(indirect_map, buf, sprintf(buf, "%u", PTR2UV(o)), val, 0))
50   SvREFCNT_dec(val);
51 }
52
53 STATIC const char *indirect_map_fetch(pTHX_ const OP *o, SV ** const name) {
54 #define indirect_map_fetch(O, S) indirect_map_fetch(aTHX_ (O), (S))
55  char buf[32];
56  SV **val;
57
58  if (indirect_linestr != SvPVX(PL_parser->linestr))
59   return NULL;
60
61  val = hv_fetch(indirect_map, buf, sprintf(buf, "%u", PTR2UV(o)), 0);
62  if (!val) {
63   *name = NULL;
64   return NULL;
65  }
66
67  *name = *val;
68  return INT2PTR(const char *, SvUVX(*val));
69 }
70
71 STATIC const char *indirect_find(pTHX_ SV *sv, const char *s) {
72 #define indirect_find(N, S) indirect_find(aTHX_ (N), (S))
73  STRLEN len;
74  const char *p = NULL, *r = SvPV_const(sv, len);
75
76  if (!len)
77   return s;
78
79  p = strstr(s, r);
80  while (p) {
81   p += len;
82   if (!isALNUM(*p))
83    break;
84   p = strstr(p + 1, r);
85  }
86
87  return p;
88 }
89
90 STATIC OP *(*indirect_old_ck_const)(pTHX_ OP *) = 0;
91
92 STATIC OP *indirect_ck_const(pTHX_ OP *o) {
93  if (indirect_hint()) {
94   SV *sv = cSVOPo_sv;
95   if (SvPOK(sv) && (SvTYPE(sv) >= SVt_PV))
96    indirect_map_store(o, indirect_find(sv, PL_parser->oldbufptr), sv);
97  }
98
99  return CALL_FPTR(indirect_old_ck_const)(aTHX_ o);
100 }
101
102 STATIC OP *(*indirect_old_ck_rv2sv)(pTHX_ OP *) = 0;
103
104 STATIC OP *indirect_ck_rv2sv(pTHX_ OP *o) {
105  if (indirect_hint()) {
106   OP *op = cUNOPo->op_first;
107   SV *name = cSVOPx_sv(op);
108   if (SvPOK(name) && (SvTYPE(name) >= SVt_PV)) {
109    SV *sv = sv_2mortal(newSVpvn("$", 1));
110    sv_catsv(sv, name);
111    indirect_map_store(o, indirect_find(sv, PL_parser->oldbufptr), sv);
112   }
113  }
114
115  return CALL_FPTR(indirect_old_ck_rv2sv)(aTHX_ o);
116 }
117
118 STATIC OP *(*indirect_old_ck_padany)(pTHX_ OP *) = 0;
119
120 STATIC OP *indirect_ck_padany(pTHX_ OP *o) {
121  if (indirect_hint()) {
122   SV *sv;
123   const char *s = PL_parser->oldbufptr, *t = PL_parser->bufptr - 1;
124
125   while (s < t && isSPACE(*s)) ++s;
126   while (t > s && isSPACE(*t)) --t;
127   sv = sv_2mortal(newSVpvn(s, t - s + 1));
128
129   indirect_map_store(o, s, sv);
130  }
131
132  return CALL_FPTR(indirect_old_ck_padany)(aTHX_ o);
133 }
134
135 STATIC OP *(*indirect_old_ck_method)(pTHX_ OP *) = 0;
136
137 STATIC OP *indirect_ck_method(pTHX_ OP *o) {
138  if (indirect_hint()) {
139   OP *op = cUNOPo->op_first;
140   SV *sv;
141   const char *s = indirect_map_fetch(op, &sv);
142   if (!s) {
143    sv = cSVOPx_sv(op);
144    if (!SvPOK(sv) || (SvTYPE(sv) < SVt_PV))
145     goto done;
146    sv = sv_mortalcopy(sv);
147    s  = indirect_find(sv, PL_parser->oldbufptr);
148   }
149   o = CALL_FPTR(indirect_old_ck_method)(aTHX_ o);
150   /* o may now be a method_named */
151   indirect_map_store(o, s, sv);
152   return o;
153  }
154
155 done:
156  return CALL_FPTR(indirect_old_ck_method)(aTHX_ o);
157 }
158
159 STATIC OP *(*indirect_old_ck_entersub)(pTHX_ OP *) = 0;
160
161 STATIC OP *indirect_ck_entersub(pTHX_ OP *o) {
162  LISTOP *op;
163  OP *om, *oo;
164  UV hint = indirect_hint();
165
166  if (hint) {
167   const char *pm, *po;
168   SV *svm, *svo;
169   op = (LISTOP *) o;
170   while (op->op_type != OP_PUSHMARK)
171    op = (LISTOP *) op->op_first;
172   oo = op->op_sibling;
173   om = oo;
174   while (om->op_sibling)
175    om = om->op_sibling;
176   if (om->op_type == OP_METHOD)
177    om = cUNOPx(om)->op_first;
178   else if (om->op_type != OP_METHOD_NAMED)
179    goto done;
180   pm = indirect_map_fetch(om, &svm);
181   po = indirect_map_fetch(oo, &svo);
182   if (pm && po && pm < po)
183    ((hint == 2) ? croak : warn)(indirect_msg, SvPV_nolen(svm), SvPV_nolen(svo));
184  }
185
186 done:
187  return CALL_FPTR(indirect_old_ck_entersub)(aTHX_ o);
188 }
189
190 MODULE = indirect      PACKAGE = indirect
191
192 PROTOTYPES: DISABLE
193
194 BOOT:
195 {
196  if (!indirect_initialized++) {
197   PERL_HASH(indirect_hash, "indirect", 8);
198   indirect_map = newHV();
199   indirect_old_ck_const    = PL_check[OP_CONST];
200   PL_check[OP_CONST]       = MEMBER_TO_FPTR(indirect_ck_const);
201   indirect_old_ck_rv2sv    = PL_check[OP_RV2SV];
202   PL_check[OP_RV2SV]       = MEMBER_TO_FPTR(indirect_ck_rv2sv);
203   indirect_old_ck_padany   = PL_check[OP_PADANY];
204   PL_check[OP_PADANY]      = MEMBER_TO_FPTR(indirect_ck_padany);
205   indirect_old_ck_method   = PL_check[OP_METHOD];
206   PL_check[OP_METHOD]      = MEMBER_TO_FPTR(indirect_ck_method);
207   indirect_old_ck_entersub = PL_check[OP_ENTERSUB];
208   PL_check[OP_ENTERSUB]    = MEMBER_TO_FPTR(indirect_ck_entersub);
209  }
210 }