line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
#include "EXTERN.h" |
2
|
|
|
|
|
|
|
#include "perl.h" |
3
|
|
|
|
|
|
|
#include "XSUB.h" |
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
// C99 required |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
//#define BENCHMARK |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
#define ASN_BOOLEAN 0x01 |
10
|
|
|
|
|
|
|
#define ASN_INTEGER32 0x02 |
11
|
|
|
|
|
|
|
#define ASN_OCTET_STRING 0x04 |
12
|
|
|
|
|
|
|
#define ASN_NULL 0x05 |
13
|
|
|
|
|
|
|
#define ASN_OBJECT_IDENTIFIER 0x06 |
14
|
|
|
|
|
|
|
#define ASN_SEQUENCE 0x30 |
15
|
|
|
|
|
|
|
#define ASN_IPADDRESS 0x40 |
16
|
|
|
|
|
|
|
#define ASN_COUNTER32 0x41 |
17
|
|
|
|
|
|
|
#define ASN_UNSIGNED32 0x42 |
18
|
|
|
|
|
|
|
#define ASN_TIMETICKS 0x43 |
19
|
|
|
|
|
|
|
#define ASN_OPAQUE 0x44 |
20
|
|
|
|
|
|
|
#define ASN_COUNTER64 0x46 |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
#define MAX_OID_STRLEN 4096 |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
#define HAVE_VERSIONSORT defined (_GNU_SOURCE) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1 |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
static SV *cur_bufobj; |
27
|
|
|
|
|
|
|
static SV *msg, *bufsv; |
28
|
|
|
|
|
|
|
static int errflag, leading_dot; |
29
|
|
|
|
|
|
|
static U8 *buf, *cur; |
30
|
|
|
|
|
|
|
static STRLEN len, rem; |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
typedef SV *BUFOBJ; |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////// |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
#if 0 |
37
|
|
|
|
|
|
|
if (msg) |
38
|
|
|
|
|
|
|
croak ("recursive invocation of Net::SNMP::XS parser is not supported"); |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
void |
42
|
|
|
|
|
|
|
clr_msg () |
43
|
|
|
|
|
|
|
CODE: |
44
|
|
|
|
|
|
|
SvREFCNT_dec (msg); msg = 0; |
45
|
|
|
|
|
|
|
buf = cur = (U8 *)""; |
46
|
|
|
|
|
|
|
len = rem = 0; |
47
|
|
|
|
|
|
|
#endif |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
static void |
50
|
0
|
|
|
|
|
|
clear_bufobj (void) |
51
|
|
|
|
|
|
|
{ |
52
|
|
|
|
|
|
|
// serialise our state back |
53
|
0
|
0
|
|
|
|
|
if (msg && SvROK (msg)) |
|
|
0
|
|
|
|
|
|
54
|
|
|
|
|
|
|
{ |
55
|
0
|
|
|
|
|
|
SV *idx_sv = *hv_fetch ((HV *)cur_bufobj, "_index" , sizeof ("_index" ) - 1, 1); |
56
|
0
|
|
|
|
|
|
sv_setiv (idx_sv, cur - buf); |
57
|
|
|
|
|
|
|
} |
58
|
|
|
|
|
|
|
|
59
|
0
|
|
|
|
|
|
SvREFCNT_dec (msg); |
60
|
0
|
|
|
|
|
|
msg = 0; |
61
|
0
|
|
|
|
|
|
cur_bufobj = 0; |
62
|
0
|
|
|
|
|
|
} |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
static void |
65
|
0
|
|
|
|
|
|
switch_bufobj (BUFOBJ neu) |
66
|
|
|
|
|
|
|
{ |
67
|
0
|
|
|
|
|
|
clear_bufobj (); |
68
|
|
|
|
|
|
|
|
69
|
0
|
|
|
|
|
|
msg = newSVsv (neu); |
70
|
0
|
|
|
|
|
|
cur_bufobj = SvRV (msg); |
71
|
0
|
|
|
|
|
|
sv_rvweaken (msg); |
72
|
|
|
|
|
|
|
|
73
|
0
|
|
|
|
|
|
errflag = 0; |
74
|
0
|
|
|
|
|
|
leading_dot = -1; |
75
|
|
|
|
|
|
|
|
76
|
0
|
0
|
|
|
|
|
IV index = SvIV (*hv_fetch ((HV *)cur_bufobj, "_index" , sizeof ("_index" ) - 1, 1)); |
77
|
0
|
|
|
|
|
|
bufsv = *hv_fetch ((HV *)cur_bufobj, "_buffer", sizeof ("_buffer") - 1, 1); |
78
|
|
|
|
|
|
|
|
79
|
0
|
0
|
|
|
|
|
buf = SvPVbyte (bufsv, len); |
80
|
0
|
|
|
|
|
|
cur = buf + index; |
81
|
0
|
|
|
|
|
|
rem = len - index; |
82
|
0
|
|
|
|
|
|
} |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////// |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
static SV * |
87
|
23
|
|
|
|
|
|
x_get_cv (SV *cb_sv) |
88
|
|
|
|
|
|
|
{ |
89
|
|
|
|
|
|
|
HV *st; |
90
|
|
|
|
|
|
|
GV *gvp; |
91
|
23
|
|
|
|
|
|
CV *cv = sv_2cv (cb_sv, &st, &gvp, 0); |
92
|
|
|
|
|
|
|
|
93
|
23
|
50
|
|
|
|
|
if (!cv) |
94
|
0
|
|
|
|
|
|
croak ("CODE reference expected"); |
95
|
|
|
|
|
|
|
|
96
|
23
|
|
|
|
|
|
return (SV *)cv; |
97
|
|
|
|
|
|
|
} |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
static void |
100
|
0
|
|
|
|
|
|
error (const char *errmsg) |
101
|
|
|
|
|
|
|
{ |
102
|
0
|
|
|
|
|
|
errflag = 1; |
103
|
|
|
|
|
|
|
|
104
|
0
|
0
|
|
|
|
|
if (!msg) |
105
|
0
|
|
|
|
|
|
croak ("Net::SNMP::XS fatal error, parser called without parsing context"); |
106
|
|
|
|
|
|
|
|
107
|
0
|
|
|
|
|
|
dSP; |
108
|
0
|
0
|
|
|
|
|
PUSHMARK (SP); |
109
|
0
|
0
|
|
|
|
|
EXTEND (SP, 2); |
110
|
0
|
|
|
|
|
|
PUSHs (msg); |
111
|
0
|
|
|
|
|
|
PUSHs (sv_2mortal (newSVpv (errmsg, 0))); |
112
|
0
|
|
|
|
|
|
PUTBACK; |
113
|
0
|
|
|
|
|
|
call_method ("_error", G_VOID | G_DISCARD); |
114
|
0
|
|
|
|
|
|
} |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
static int |
117
|
0
|
|
|
|
|
|
need (int count) |
118
|
|
|
|
|
|
|
{ |
119
|
0
|
0
|
|
|
|
|
if (count < 0 || (int)rem < count) |
|
|
0
|
|
|
|
|
|
120
|
|
|
|
|
|
|
{ |
121
|
0
|
|
|
|
|
|
error ("Unexpected end of message buffer"); |
122
|
0
|
|
|
|
|
|
return 0; |
123
|
|
|
|
|
|
|
} |
124
|
|
|
|
|
|
|
|
125
|
0
|
|
|
|
|
|
return 1; |
126
|
|
|
|
|
|
|
} |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
static U8 * |
129
|
0
|
|
|
|
|
|
getn (int count, const U8 *errres) |
130
|
|
|
|
|
|
|
{ |
131
|
0
|
0
|
|
|
|
|
if (!need (count)) |
132
|
0
|
|
|
|
|
|
return (U8 *)errres; |
133
|
|
|
|
|
|
|
|
134
|
0
|
|
|
|
|
|
U8 *res = cur; |
135
|
|
|
|
|
|
|
|
136
|
0
|
|
|
|
|
|
cur += count; |
137
|
0
|
|
|
|
|
|
rem -= count; |
138
|
|
|
|
|
|
|
|
139
|
0
|
|
|
|
|
|
return res; |
140
|
|
|
|
|
|
|
} |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
static U8 |
143
|
0
|
|
|
|
|
|
get8 (void) |
144
|
|
|
|
|
|
|
{ |
145
|
0
|
0
|
|
|
|
|
if (rem <= 0) |
146
|
|
|
|
|
|
|
{ |
147
|
0
|
|
|
|
|
|
error ("Unexpected end of message buffer"); |
148
|
0
|
|
|
|
|
|
return 0; |
149
|
|
|
|
|
|
|
} |
150
|
|
|
|
|
|
|
|
151
|
0
|
|
|
|
|
|
rem--; |
152
|
0
|
|
|
|
|
|
return *cur++; |
153
|
|
|
|
|
|
|
} |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
static U32 |
156
|
0
|
|
|
|
|
|
getb (void) |
157
|
|
|
|
|
|
|
{ |
158
|
0
|
|
|
|
|
|
U32 res = 0; |
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
for (;;) |
161
|
|
|
|
|
|
|
{ |
162
|
0
|
|
|
|
|
|
U8 c = get8 (); |
163
|
0
|
|
|
|
|
|
res = (res << 7) | (c & 0x7f); |
164
|
|
|
|
|
|
|
|
165
|
0
|
0
|
|
|
|
|
if (!(c & 0x80)) |
166
|
0
|
|
|
|
|
|
return res; |
167
|
0
|
|
|
|
|
|
} |
168
|
|
|
|
|
|
|
} |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
#ifdef BENCHMARK |
171
|
|
|
|
|
|
|
static double t1; |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
static double |
174
|
|
|
|
|
|
|
tstamp (void) |
175
|
|
|
|
|
|
|
{ |
176
|
|
|
|
|
|
|
struct timeval tv; |
177
|
|
|
|
|
|
|
gettimeofday (&tv, 0); |
178
|
|
|
|
|
|
|
return tv.tv_sec + tv.tv_usec * 0.000001; |
179
|
|
|
|
|
|
|
} |
180
|
|
|
|
|
|
|
#endif |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
static U32 |
183
|
0
|
|
|
|
|
|
process_length (void) |
184
|
|
|
|
|
|
|
{ |
185
|
0
|
|
|
|
|
|
U32 res = get8 (); |
186
|
|
|
|
|
|
|
|
187
|
0
|
0
|
|
|
|
|
if (res & 0x80) |
188
|
|
|
|
|
|
|
{ |
189
|
0
|
|
|
|
|
|
int cnt = res & 0x7f; |
190
|
0
|
|
|
|
|
|
res = 0; |
191
|
|
|
|
|
|
|
|
192
|
0
|
|
|
|
|
|
switch (cnt) |
193
|
|
|
|
|
|
|
{ |
194
|
|
|
|
|
|
|
case 0: |
195
|
0
|
|
|
|
|
|
error ("Indefinite ASN.1 lengths not supported"); |
196
|
0
|
|
|
|
|
|
return 0; |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
default: |
199
|
0
|
|
|
|
|
|
error ("ASN.1 length too long"); |
200
|
0
|
|
|
|
|
|
return 0; |
201
|
|
|
|
|
|
|
|
202
|
0
|
|
|
|
|
|
case 4: res = (res << 8) | get8 (); |
203
|
0
|
|
|
|
|
|
case 3: res = (res << 8) | get8 (); |
204
|
0
|
|
|
|
|
|
case 2: res = (res << 8) | get8 (); |
205
|
0
|
|
|
|
|
|
case 1: res = (res << 8) | get8 (); |
206
|
|
|
|
|
|
|
} |
207
|
|
|
|
|
|
|
} |
208
|
|
|
|
|
|
|
|
209
|
0
|
|
|
|
|
|
return res; |
210
|
|
|
|
|
|
|
} |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
static U32 |
213
|
0
|
|
|
|
|
|
process_integer32 (void) |
214
|
|
|
|
|
|
|
{ |
215
|
0
|
|
|
|
|
|
U32 length = process_length (); |
216
|
|
|
|
|
|
|
|
217
|
0
|
0
|
|
|
|
|
if (length <= 0) |
218
|
|
|
|
|
|
|
{ |
219
|
0
|
|
|
|
|
|
error ("INTEGER32 length equal to zero"); |
220
|
0
|
|
|
|
|
|
return 0; |
221
|
|
|
|
|
|
|
} |
222
|
|
|
|
|
|
|
|
223
|
0
|
|
|
|
|
|
U8 *data = getn (length, 0); |
224
|
|
|
|
|
|
|
|
225
|
0
|
0
|
|
|
|
|
if (!data) |
226
|
0
|
|
|
|
|
|
return 0; |
227
|
|
|
|
|
|
|
|
228
|
0
|
0
|
|
|
|
|
if (length > 5 || (length > 4 && data [0])) |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
229
|
|
|
|
|
|
|
{ |
230
|
0
|
|
|
|
|
|
error ("INTEGER32 length too long"); |
231
|
0
|
|
|
|
|
|
return 0; |
232
|
|
|
|
|
|
|
} |
233
|
|
|
|
|
|
|
|
234
|
0
|
0
|
|
|
|
|
U32 res = data [0] & 0x80 ? 0xffffffff : 0; |
235
|
|
|
|
|
|
|
|
236
|
0
|
0
|
|
|
|
|
while (length--) |
237
|
0
|
|
|
|
|
|
res = (res << 8) | *data++; |
238
|
|
|
|
|
|
|
|
239
|
0
|
|
|
|
|
|
return res; |
240
|
|
|
|
|
|
|
} |
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
static SV * |
243
|
0
|
|
|
|
|
|
process_integer32_sv (void) |
244
|
|
|
|
|
|
|
{ |
245
|
0
|
|
|
|
|
|
return newSViv ((I32)process_integer32 ()); |
246
|
|
|
|
|
|
|
} |
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
static SV * |
249
|
0
|
|
|
|
|
|
process_unsigned32_sv (void) |
250
|
|
|
|
|
|
|
{ |
251
|
0
|
|
|
|
|
|
return newSVuv ((U32)process_integer32 ()); |
252
|
|
|
|
|
|
|
} |
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
#if IVSIZE >= 8 |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
static U64TYPE |
257
|
0
|
|
|
|
|
|
process_integer64 (void) |
258
|
|
|
|
|
|
|
{ |
259
|
0
|
|
|
|
|
|
U32 length = process_length (); |
260
|
|
|
|
|
|
|
|
261
|
0
|
0
|
|
|
|
|
if (length <= 0) |
262
|
|
|
|
|
|
|
{ |
263
|
0
|
|
|
|
|
|
error ("INTEGER64 length equal to zero"); |
264
|
0
|
|
|
|
|
|
return 0; |
265
|
|
|
|
|
|
|
} |
266
|
|
|
|
|
|
|
|
267
|
0
|
|
|
|
|
|
U8 *data = getn (length, 0); |
268
|
|
|
|
|
|
|
|
269
|
0
|
0
|
|
|
|
|
if (!data) |
270
|
0
|
|
|
|
|
|
return 0; |
271
|
|
|
|
|
|
|
|
272
|
0
|
0
|
|
|
|
|
if (length > 9 || (length > 8 && data [0])) |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
273
|
|
|
|
|
|
|
{ |
274
|
0
|
|
|
|
|
|
error ("INTEGER64 length too long"); |
275
|
0
|
|
|
|
|
|
return 0; |
276
|
|
|
|
|
|
|
} |
277
|
|
|
|
|
|
|
|
278
|
0
|
0
|
|
|
|
|
U64TYPE res = data [0] & 0x80 ? 0xffffffffffffffff : 0; |
279
|
|
|
|
|
|
|
|
280
|
0
|
0
|
|
|
|
|
while (length--) |
281
|
0
|
|
|
|
|
|
res = (res << 8) | *data++; |
282
|
|
|
|
|
|
|
|
283
|
0
|
|
|
|
|
|
return res; |
284
|
|
|
|
|
|
|
} |
285
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
static SV * |
287
|
0
|
|
|
|
|
|
process_integer64_sv (void) |
288
|
|
|
|
|
|
|
{ |
289
|
0
|
|
|
|
|
|
return newSViv ((I64TYPE)process_integer64 ()); |
290
|
|
|
|
|
|
|
} |
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
static SV * |
293
|
0
|
|
|
|
|
|
process_unsigned64_sv (void) |
294
|
|
|
|
|
|
|
{ |
295
|
0
|
|
|
|
|
|
return newSVuv ((U64TYPE)process_integer64 ()); |
296
|
|
|
|
|
|
|
} |
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
#endif |
299
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
static SV * |
301
|
0
|
|
|
|
|
|
process_octet_string_sv (void) |
302
|
|
|
|
|
|
|
{ |
303
|
0
|
|
|
|
|
|
U32 length = process_length (); |
304
|
|
|
|
|
|
|
|
305
|
0
|
|
|
|
|
|
U8 *data = getn (length, 0); |
306
|
0
|
0
|
|
|
|
|
if (!data) |
307
|
|
|
|
|
|
|
{ |
308
|
0
|
|
|
|
|
|
error ("OCTET STRING too long"); |
309
|
0
|
|
|
|
|
|
return &PL_sv_undef; |
310
|
|
|
|
|
|
|
} |
311
|
|
|
|
|
|
|
|
312
|
0
|
|
|
|
|
|
return newSVpvn (data, length); |
313
|
|
|
|
|
|
|
} |
314
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
static char * |
316
|
0
|
|
|
|
|
|
write_uv (char *buf, U32 u) |
317
|
|
|
|
|
|
|
{ |
318
|
|
|
|
|
|
|
// the one-digit case is absolutely predominant |
319
|
0
|
0
|
|
|
|
|
if (u < 10) |
320
|
0
|
|
|
|
|
|
*buf++ = u + '0'; |
321
|
|
|
|
|
|
|
else |
322
|
0
|
|
|
|
|
|
buf += sprintf (buf, "%u", (unsigned int)u); |
323
|
|
|
|
|
|
|
|
324
|
0
|
|
|
|
|
|
return buf; |
325
|
|
|
|
|
|
|
} |
326
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
static SV * |
328
|
0
|
|
|
|
|
|
process_object_identifier_sv (void) |
329
|
|
|
|
|
|
|
{ |
330
|
0
|
|
|
|
|
|
U32 length = process_length (); |
331
|
|
|
|
|
|
|
|
332
|
0
|
0
|
|
|
|
|
if (length <= 0) |
333
|
|
|
|
|
|
|
{ |
334
|
0
|
|
|
|
|
|
error ("OBJECT IDENTIFIER length equal to zero"); |
335
|
0
|
|
|
|
|
|
return &PL_sv_undef; |
336
|
|
|
|
|
|
|
} |
337
|
|
|
|
|
|
|
|
338
|
0
|
|
|
|
|
|
U8 *end = cur + length; |
339
|
0
|
|
|
|
|
|
U32 w = getb (); |
340
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
static char oid[MAX_OID_STRLEN]; // must be static |
342
|
0
|
|
|
|
|
|
char *app = oid; |
343
|
|
|
|
|
|
|
|
344
|
0
|
0
|
|
|
|
|
if (leading_dot < 0) |
345
|
0
|
0
|
|
|
|
|
leading_dot = SvTRUE (*hv_fetch ((HV *)SvRV (msg), "_leading_dot", sizeof ("_leading_dot") - 1, 1)); |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
346
|
|
|
|
|
|
|
|
347
|
0
|
|
|
|
|
|
*app = '.'; app += ! ! leading_dot; |
348
|
0
|
|
|
|
|
|
app = write_uv (app, (U8)w / 40); |
349
|
0
|
|
|
|
|
|
*app++ = '.'; |
350
|
0
|
|
|
|
|
|
app = write_uv (app, (U8)w % 40); |
351
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
// we assume an oid component is never > 64 bytes |
353
|
0
|
0
|
|
|
|
|
while (cur < end && oid + sizeof (oid) - app > 64) |
|
|
0
|
|
|
|
|
|
354
|
|
|
|
|
|
|
{ |
355
|
0
|
|
|
|
|
|
w = getb (); |
356
|
0
|
|
|
|
|
|
*app++ = '.'; |
357
|
0
|
|
|
|
|
|
app = write_uv (app, w); |
358
|
|
|
|
|
|
|
} |
359
|
|
|
|
|
|
|
|
360
|
0
|
|
|
|
|
|
return newSVpvn (oid, app - oid); |
361
|
|
|
|
|
|
|
} |
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
static AV *av_type; |
364
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
static SV * |
366
|
0
|
|
|
|
|
|
process_sv (int *found) |
367
|
|
|
|
|
|
|
{ |
368
|
0
|
|
|
|
|
|
int type = get8 (); |
369
|
|
|
|
|
|
|
|
370
|
0
|
|
|
|
|
|
*found = type; |
371
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
SV *res; |
373
|
|
|
|
|
|
|
|
374
|
0
|
|
|
|
|
|
switch (type) |
375
|
|
|
|
|
|
|
{ |
376
|
|
|
|
|
|
|
case ASN_OBJECT_IDENTIFIER: |
377
|
0
|
|
|
|
|
|
res = process_object_identifier_sv (); |
378
|
0
|
|
|
|
|
|
break; |
379
|
|
|
|
|
|
|
|
380
|
|
|
|
|
|
|
case ASN_INTEGER32: |
381
|
0
|
|
|
|
|
|
res = process_integer32_sv (); |
382
|
0
|
|
|
|
|
|
break; |
383
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
case ASN_UNSIGNED32: |
385
|
|
|
|
|
|
|
case ASN_COUNTER32: |
386
|
|
|
|
|
|
|
case ASN_TIMETICKS: |
387
|
0
|
|
|
|
|
|
res = process_unsigned32_sv (); |
388
|
0
|
|
|
|
|
|
break; |
389
|
|
|
|
|
|
|
|
390
|
|
|
|
|
|
|
case ASN_SEQUENCE: |
391
|
0
|
|
|
|
|
|
res = newSVuv (process_length ()); |
392
|
0
|
|
|
|
|
|
break; |
393
|
|
|
|
|
|
|
|
394
|
|
|
|
|
|
|
case ASN_OCTET_STRING: |
395
|
|
|
|
|
|
|
case ASN_OPAQUE: |
396
|
0
|
|
|
|
|
|
res = process_octet_string_sv (); |
397
|
0
|
|
|
|
|
|
break; |
398
|
|
|
|
|
|
|
|
399
|
|
|
|
|
|
|
default: |
400
|
|
|
|
|
|
|
{ |
401
|
0
|
0
|
|
|
|
|
if (type > AvFILLp (av_type) |
402
|
0
|
0
|
|
|
|
|
|| AvARRAY (av_type)[type] == 0 |
403
|
0
|
0
|
|
|
|
|
|| AvARRAY (av_type)[type] == &PL_sv_undef) |
404
|
|
|
|
|
|
|
{ |
405
|
0
|
|
|
|
|
|
error ("Unknown ASN.1 type"); |
406
|
0
|
|
|
|
|
|
return &PL_sv_undef; |
407
|
|
|
|
|
|
|
} |
408
|
|
|
|
|
|
|
|
409
|
0
|
|
|
|
|
|
dSP; |
410
|
0
|
0
|
|
|
|
|
PUSHMARK (SP); |
411
|
0
|
0
|
|
|
|
|
EXTEND (SP, 2); |
412
|
0
|
|
|
|
|
|
PUSHs (msg); |
413
|
0
|
|
|
|
|
|
PUSHs (sv_2mortal (newSViv (type))); |
414
|
0
|
|
|
|
|
|
PUTBACK; |
415
|
0
|
|
|
|
|
|
int count = call_sv (AvARRAY (av_type)[type], G_SCALAR); |
416
|
0
|
|
|
|
|
|
SPAGAIN; |
417
|
0
|
0
|
|
|
|
|
res = count ? SvREFCNT_inc (TOPs) : &PL_sv_undef; |
418
|
|
|
|
|
|
|
} |
419
|
|
|
|
|
|
|
} |
420
|
|
|
|
|
|
|
|
421
|
0
|
0
|
|
|
|
|
return errflag ? &PL_sv_undef : res; |
422
|
|
|
|
|
|
|
} |
423
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////// |
425
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
#if HAVE_VERSIONSORT |
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
static int |
429
|
0
|
|
|
|
|
|
oid_lex_cmp (const void *a_, const void *b_) |
430
|
|
|
|
|
|
|
{ |
431
|
0
|
|
|
|
|
|
const char *a = SvPVX (*(SV **)a_); |
432
|
0
|
|
|
|
|
|
const char *b = SvPVX (*(SV **)b_); |
433
|
|
|
|
|
|
|
|
434
|
0
|
|
|
|
|
|
a += *a == '.'; |
435
|
0
|
|
|
|
|
|
b += *b == '.'; |
436
|
|
|
|
|
|
|
|
437
|
0
|
|
|
|
|
|
return strverscmp (a, b); |
438
|
|
|
|
|
|
|
} |
439
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
#endif |
441
|
|
|
|
|
|
|
|
442
|
|
|
|
|
|
|
MODULE = Net::SNMP::XS PACKAGE = Net::SNMP::XS |
443
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
PROTOTYPES: ENABLE |
445
|
|
|
|
|
|
|
|
446
|
|
|
|
|
|
|
BOOT: |
447
|
1
|
|
|
|
|
|
av_type = newAV (); |
448
|
|
|
|
|
|
|
|
449
|
|
|
|
|
|
|
void |
450
|
|
|
|
|
|
|
set_type (int type, SV *cv) |
451
|
|
|
|
|
|
|
CODE: |
452
|
23
|
|
|
|
|
|
cv = x_get_cv (cv); |
453
|
|
|
|
|
|
|
assert (SvTYPE (cv) == SVt_PVCV); |
454
|
23
|
|
|
|
|
|
av_store (av_type, type, SvREFCNT_inc_NN (cv)); |
455
|
|
|
|
|
|
|
|
456
|
|
|
|
|
|
|
MODULE = Net::SNMP::XS PACKAGE = Net::SNMP::Message |
457
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
void |
459
|
|
|
|
|
|
|
_buffer_append (BUFOBJ self, SV *value) |
460
|
|
|
|
|
|
|
ALIAS: |
461
|
|
|
|
|
|
|
_buffer_put = 1 |
462
|
|
|
|
|
|
|
PPCODE: |
463
|
|
|
|
|
|
|
{ |
464
|
|
|
|
|
|
|
STRLEN vlen; |
465
|
0
|
0
|
|
|
|
|
const char *vstr = SvPVbyte (value, vlen); |
466
|
|
|
|
|
|
|
|
467
|
0
|
0
|
|
|
|
|
if (ix) |
468
|
0
|
|
|
|
|
|
sv_insert (bufsv, 0, 0, vstr, vlen); |
469
|
|
|
|
|
|
|
else |
470
|
0
|
|
|
|
|
|
sv_catpvn (bufsv, vstr, vlen); |
471
|
|
|
|
|
|
|
|
472
|
0
|
0
|
|
|
|
|
buf = SvPVbyte (bufsv, len); |
473
|
0
|
|
|
|
|
|
cur = buf; |
474
|
0
|
|
|
|
|
|
rem = len; |
475
|
|
|
|
|
|
|
|
476
|
0
|
|
|
|
|
|
SV *len_sv = *hv_fetch ((HV *)cur_bufobj, "_length", sizeof ("_length") - 1, 1); |
477
|
0
|
|
|
|
|
|
sv_setiv (len_sv, len); |
478
|
|
|
|
|
|
|
|
479
|
|
|
|
|
|
|
// some callers test for defined'ness of the returnvalue. *sigh* |
480
|
0
|
0
|
|
|
|
|
XPUSHs (&PL_sv_yes); |
481
|
|
|
|
|
|
|
} |
482
|
|
|
|
|
|
|
|
483
|
|
|
|
|
|
|
void |
484
|
|
|
|
|
|
|
_buffer_get (BUFOBJ self, int count = -1) |
485
|
|
|
|
|
|
|
PPCODE: |
486
|
|
|
|
|
|
|
{ |
487
|
|
|
|
|
|
|
// grrr. |
488
|
0
|
0
|
|
|
|
|
if (count < 0) |
489
|
|
|
|
|
|
|
{ |
490
|
0
|
|
|
|
|
|
hv_delete ((HV *)SvRV (self), "_index" , 6, G_DISCARD); |
491
|
0
|
|
|
|
|
|
hv_delete ((HV *)SvRV (self), "_length", 7, G_DISCARD); |
492
|
0
|
0
|
|
|
|
|
XPUSHs (sv_2mortal (newSVsv (bufsv))); |
493
|
0
|
|
|
|
|
|
sv_setpvn (bufsv, "", 0); |
494
|
|
|
|
|
|
|
|
495
|
0
|
|
|
|
|
|
buf = ""; |
496
|
0
|
|
|
|
|
|
cur = buf; |
497
|
0
|
|
|
|
|
|
rem = 0; |
498
|
|
|
|
|
|
|
|
499
|
0
|
|
|
|
|
|
XSRETURN (1); |
500
|
|
|
|
|
|
|
} |
501
|
|
|
|
|
|
|
|
502
|
0
|
|
|
|
|
|
char *data = getn (count, 0); |
503
|
|
|
|
|
|
|
|
504
|
0
|
0
|
|
|
|
|
if (data) |
505
|
0
|
0
|
|
|
|
|
XPUSHs (sv_2mortal (newSVpvn (data, count))); |
506
|
|
|
|
|
|
|
} |
507
|
|
|
|
|
|
|
|
508
|
|
|
|
|
|
|
U32 |
509
|
|
|
|
|
|
|
index (BUFOBJ self, int ndx = -1) |
510
|
|
|
|
|
|
|
CODE: |
511
|
|
|
|
|
|
|
{ |
512
|
0
|
0
|
|
|
|
|
if (ndx >= 0 && ndx < len) |
|
|
0
|
|
|
|
|
|
513
|
|
|
|
|
|
|
{ |
514
|
0
|
|
|
|
|
|
cur = buf + ndx; |
515
|
0
|
|
|
|
|
|
rem = len - ndx; |
516
|
|
|
|
|
|
|
} |
517
|
|
|
|
|
|
|
|
518
|
0
|
|
|
|
|
|
RETVAL = cur - buf; |
519
|
|
|
|
|
|
|
} |
520
|
|
|
|
|
|
|
OUTPUT: |
521
|
|
|
|
|
|
|
RETVAL |
522
|
|
|
|
|
|
|
|
523
|
|
|
|
|
|
|
U32 |
524
|
|
|
|
|
|
|
_process_length (BUFOBJ self, ...) |
525
|
|
|
|
|
|
|
ALIAS: |
526
|
|
|
|
|
|
|
_process_sequence = 0 |
527
|
|
|
|
|
|
|
CODE: |
528
|
0
|
|
|
|
|
|
RETVAL = process_length (); |
529
|
|
|
|
|
|
|
OUTPUT: |
530
|
|
|
|
|
|
|
RETVAL |
531
|
|
|
|
|
|
|
|
532
|
|
|
|
|
|
|
SV * |
533
|
|
|
|
|
|
|
_process_integer32 (BUFOBJ self, ...) |
534
|
|
|
|
|
|
|
CODE: |
535
|
0
|
|
|
|
|
|
RETVAL = process_integer32_sv (); |
536
|
|
|
|
|
|
|
OUTPUT: |
537
|
|
|
|
|
|
|
RETVAL |
538
|
|
|
|
|
|
|
|
539
|
|
|
|
|
|
|
SV * |
540
|
|
|
|
|
|
|
_process_counter (BUFOBJ self, ...) |
541
|
|
|
|
|
|
|
ALIAS: |
542
|
|
|
|
|
|
|
_process_gauge = 0 |
543
|
|
|
|
|
|
|
_process_timeticks = 0 |
544
|
|
|
|
|
|
|
CODE: |
545
|
0
|
|
|
|
|
|
RETVAL = process_unsigned32_sv (); |
546
|
|
|
|
|
|
|
OUTPUT: |
547
|
|
|
|
|
|
|
RETVAL |
548
|
|
|
|
|
|
|
|
549
|
|
|
|
|
|
|
#if IVSIZE >= 8 |
550
|
|
|
|
|
|
|
|
551
|
|
|
|
|
|
|
SV * |
552
|
|
|
|
|
|
|
_process_counter64 (BUFOBJ self, ...) |
553
|
|
|
|
|
|
|
CODE: |
554
|
0
|
|
|
|
|
|
RETVAL = process_unsigned64_sv (); |
555
|
|
|
|
|
|
|
OUTPUT: |
556
|
|
|
|
|
|
|
RETVAL |
557
|
|
|
|
|
|
|
|
558
|
|
|
|
|
|
|
#endif |
559
|
|
|
|
|
|
|
|
560
|
|
|
|
|
|
|
SV * |
561
|
|
|
|
|
|
|
_process_object_identifier (BUFOBJ self, ...) |
562
|
|
|
|
|
|
|
CODE: |
563
|
0
|
|
|
|
|
|
RETVAL = process_object_identifier_sv (); |
564
|
|
|
|
|
|
|
OUTPUT: |
565
|
|
|
|
|
|
|
RETVAL |
566
|
|
|
|
|
|
|
|
567
|
|
|
|
|
|
|
SV * |
568
|
|
|
|
|
|
|
_process_octet_string (BUFOBJ self, ...) |
569
|
|
|
|
|
|
|
ALIAS: |
570
|
|
|
|
|
|
|
_process_opaque = 0 |
571
|
|
|
|
|
|
|
CODE: |
572
|
0
|
|
|
|
|
|
RETVAL = process_octet_string_sv (); |
573
|
|
|
|
|
|
|
OUTPUT: |
574
|
|
|
|
|
|
|
RETVAL |
575
|
|
|
|
|
|
|
|
576
|
|
|
|
|
|
|
SV * |
577
|
|
|
|
|
|
|
_process_ipaddress (BUFOBJ self, ...) |
578
|
|
|
|
|
|
|
CODE: |
579
|
|
|
|
|
|
|
{ |
580
|
0
|
|
|
|
|
|
U32 length = process_length (); |
581
|
0
|
0
|
|
|
|
|
if (length != 4) |
582
|
|
|
|
|
|
|
{ |
583
|
0
|
|
|
|
|
|
error ("IP ADDRESS length not four"); |
584
|
0
|
|
|
|
|
|
XSRETURN_UNDEF; |
585
|
|
|
|
|
|
|
} |
586
|
|
|
|
|
|
|
|
587
|
0
|
|
|
|
|
|
U8 *data = getn (4, "\x00\x00\x00\x00"); |
588
|
0
|
|
|
|
|
|
RETVAL = newSVpvf ("%d.%d.%d.%d", data [0], data [1], data [2], data [3]); |
589
|
|
|
|
|
|
|
} |
590
|
|
|
|
|
|
|
OUTPUT: |
591
|
|
|
|
|
|
|
RETVAL |
592
|
|
|
|
|
|
|
|
593
|
|
|
|
|
|
|
SV * |
594
|
|
|
|
|
|
|
process (BUFOBJ self, SV *expected = &PL_sv_undef, SV *found = 0) |
595
|
|
|
|
|
|
|
CODE: |
596
|
|
|
|
|
|
|
{ |
597
|
|
|
|
|
|
|
int type; |
598
|
|
|
|
|
|
|
|
599
|
0
|
|
|
|
|
|
RETVAL = process_sv (&type); |
600
|
|
|
|
|
|
|
|
601
|
0
|
0
|
|
|
|
|
if (found) |
602
|
0
|
|
|
|
|
|
sv_setiv (found, type); |
603
|
|
|
|
|
|
|
|
604
|
0
|
0
|
|
|
|
|
if (SvOK (expected) && type != SvIV (expected)) |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
605
|
0
|
|
|
|
|
|
error ("Expected a different type than found"); |
606
|
|
|
|
|
|
|
} |
607
|
|
|
|
|
|
|
OUTPUT: |
608
|
|
|
|
|
|
|
RETVAL |
609
|
|
|
|
|
|
|
|
610
|
|
|
|
|
|
|
MODULE = Net::SNMP::XS PACKAGE = Net::SNMP::PDU |
611
|
|
|
|
|
|
|
|
612
|
|
|
|
|
|
|
SV * |
613
|
|
|
|
|
|
|
_process_var_bind_list (BUFOBJ self) |
614
|
|
|
|
|
|
|
CODE: |
615
|
|
|
|
|
|
|
{ |
616
|
0
|
0
|
|
|
|
|
if (get8 () != ASN_SEQUENCE) |
617
|
0
|
|
|
|
|
|
error ("SEQUENCE expected at beginning of VarBindList"); |
618
|
0
|
|
|
|
|
|
int seqlen = process_length (); |
619
|
0
|
|
|
|
|
|
U8 *end = cur + seqlen; |
620
|
|
|
|
|
|
|
|
621
|
0
|
|
|
|
|
|
HV *list = newHV (); |
622
|
0
|
|
|
|
|
|
AV *names = newAV (); |
623
|
0
|
|
|
|
|
|
HV *types = newHV (); |
624
|
|
|
|
|
|
|
|
625
|
0
|
|
|
|
|
|
hv_store ((HV *)cur_bufobj, "_var_bind_list" , sizeof ("_var_bind_list" ) - 1, newRV_noinc ((SV *)list ), 0); |
626
|
0
|
|
|
|
|
|
hv_store ((HV *)cur_bufobj, "_var_bind_names", sizeof ("_var_bind_names") - 1, newRV_noinc ((SV *)names), 0); |
627
|
0
|
|
|
|
|
|
hv_store ((HV *)cur_bufobj, "_var_bind_types", sizeof ("_var_bind_types") - 1, newRV_noinc ((SV *)types), 0); |
628
|
|
|
|
|
|
|
|
629
|
0
|
0
|
|
|
|
|
while (cur < end && !errflag) |
|
|
0
|
|
|
|
|
|
630
|
|
|
|
|
|
|
{ |
631
|
|
|
|
|
|
|
// SEQUENCE ObjectName ObjectSyntax |
632
|
0
|
0
|
|
|
|
|
if (get8 () != ASN_SEQUENCE) |
633
|
0
|
|
|
|
|
|
error ("SEQUENCE expected at beginning of VarBind"); |
634
|
0
|
|
|
|
|
|
process_length (); |
635
|
|
|
|
|
|
|
|
636
|
0
|
0
|
|
|
|
|
if (get8 () != ASN_OBJECT_IDENTIFIER) |
637
|
0
|
|
|
|
|
|
error ("OBJECT IDENTIFIER expected at beginning of VarBind"); |
638
|
|
|
|
|
|
|
int type, oidlen; |
639
|
0
|
|
|
|
|
|
SV *oid = process_object_identifier_sv (); |
640
|
0
|
|
|
|
|
|
SV *val = process_sv (&type); |
641
|
|
|
|
|
|
|
|
642
|
0
|
|
|
|
|
|
hv_store_ent (types, oid, newSViv (type), 0); |
643
|
0
|
|
|
|
|
|
hv_store_ent (list , oid, val, 0); |
644
|
0
|
|
|
|
|
|
av_push (names, oid); |
645
|
|
|
|
|
|
|
} |
646
|
|
|
|
|
|
|
|
647
|
|
|
|
|
|
|
// sigh - great design to do it here |
648
|
0
|
|
|
|
|
|
SV *pdu_type = *hv_fetch ((HV *)cur_bufobj, "_pdu_type" , sizeof ("_pdu_type" ) - 1, 1); |
649
|
|
|
|
|
|
|
|
650
|
0
|
0
|
|
|
|
|
if (SvIV (pdu_type) == 0xa8) // REPORT |
|
|
0
|
|
|
|
|
|
651
|
|
|
|
|
|
|
{ |
652
|
0
|
0
|
|
|
|
|
PUSHMARK (SP); |
653
|
0
|
0
|
|
|
|
|
XPUSHs (msg); |
654
|
0
|
|
|
|
|
|
PUTBACK; |
655
|
0
|
|
|
|
|
|
call_method ("_report_pdu_error", G_VOID | G_DISCARD); |
656
|
0
|
|
|
|
|
|
SPAGAIN; |
657
|
0
|
|
|
|
|
|
XSRETURN_EMPTY; |
658
|
|
|
|
|
|
|
} |
659
|
|
|
|
|
|
|
|
660
|
0
|
|
|
|
|
|
RETVAL = newRV_inc ((SV *)list); |
661
|
|
|
|
|
|
|
} |
662
|
|
|
|
|
|
|
OUTPUT: |
663
|
|
|
|
|
|
|
RETVAL |
664
|
|
|
|
|
|
|
|
665
|
|
|
|
|
|
|
MODULE = Net::SNMP::XS PACKAGE = Net::SNMP |
666
|
|
|
|
|
|
|
|
667
|
|
|
|
|
|
|
void |
668
|
|
|
|
|
|
|
oid_base_match (SV *base_, SV *oid_) |
669
|
|
|
|
|
|
|
PROTOTYPE: $$ |
670
|
|
|
|
|
|
|
ALIAS: |
671
|
|
|
|
|
|
|
oid_context_match = 0 |
672
|
|
|
|
|
|
|
PPCODE: |
673
|
|
|
|
|
|
|
{ |
674
|
0
|
0
|
|
|
|
|
if (!SvOK (base_) || !SvOK (oid_)) |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
675
|
0
|
|
|
|
|
|
XSRETURN_NO; |
676
|
|
|
|
|
|
|
|
677
|
|
|
|
|
|
|
STRLEN blen, olen; |
678
|
0
|
0
|
|
|
|
|
char *base = SvPVbyte (base_, blen); |
679
|
0
|
0
|
|
|
|
|
char *oid = SvPVbyte (oid_ , olen); |
680
|
|
|
|
|
|
|
|
681
|
0
|
|
|
|
|
|
blen -= *base == '.'; base += *base == '.'; |
682
|
0
|
|
|
|
|
|
olen -= *base == '.'; oid += *oid == '.'; |
683
|
|
|
|
|
|
|
|
684
|
0
|
0
|
|
|
|
|
if (olen < blen) |
685
|
0
|
|
|
|
|
|
XSRETURN_NO; |
686
|
|
|
|
|
|
|
|
687
|
0
|
0
|
|
|
|
|
if (memcmp (base, oid, blen)) |
688
|
0
|
|
|
|
|
|
XSRETURN_NO; |
689
|
|
|
|
|
|
|
|
690
|
0
|
0
|
|
|
|
|
if (oid [blen] && oid [blen] != '.') |
|
|
0
|
|
|
|
|
|
691
|
0
|
|
|
|
|
|
XSRETURN_NO; |
692
|
|
|
|
|
|
|
|
693
|
0
|
|
|
|
|
|
XSRETURN_YES; |
694
|
|
|
|
|
|
|
} |
695
|
|
|
|
|
|
|
|
696
|
|
|
|
|
|
|
#if HAVE_VERSIONSORT |
697
|
|
|
|
|
|
|
|
698
|
|
|
|
|
|
|
void |
699
|
|
|
|
|
|
|
oid_lex_sort (...) |
700
|
|
|
|
|
|
|
PROTOTYPE: @ |
701
|
|
|
|
|
|
|
PPCODE: |
702
|
|
|
|
|
|
|
{ |
703
|
|
|
|
|
|
|
// make sure SvPVX is valid |
704
|
|
|
|
|
|
|
int i; |
705
|
0
|
0
|
|
|
|
|
for (i = items; i--; ) |
706
|
|
|
|
|
|
|
{ |
707
|
0
|
|
|
|
|
|
SV *sv = ST (i); |
708
|
|
|
|
|
|
|
|
709
|
0
|
0
|
|
|
|
|
if (SvTYPE (sv) < SVt_PV || SvTYPE (sv) == SVt_PVAV && SvTYPE (sv) == SVt_PVHV) |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
710
|
0
|
0
|
|
|
|
|
SvPV_force_nolen (sv); |
711
|
|
|
|
|
|
|
} |
712
|
|
|
|
|
|
|
|
713
|
0
|
|
|
|
|
|
qsort (&ST (0), items, sizeof (SV *), oid_lex_cmp); |
714
|
|
|
|
|
|
|
|
715
|
0
|
0
|
|
|
|
|
EXTEND (SP, items); |
|
|
0
|
|
|
|
|
|
716
|
|
|
|
|
|
|
// we cheat somewhat by not returning copies here |
717
|
0
|
0
|
|
|
|
|
for (i = 0; i < items; ++i) |
718
|
0
|
|
|
|
|
|
PUSHs (sv_2mortal (SvREFCNT_inc (ST (i)))); |
719
|
|
|
|
|
|
|
} |
720
|
|
|
|
|
|
|
|
721
|
|
|
|
|
|
|
int |
722
|
|
|
|
|
|
|
_index_cmp (const char *a, const char *b) |
723
|
|
|
|
|
|
|
PROTOTYPE: $$ |
724
|
|
|
|
|
|
|
CODE: |
725
|
0
|
|
|
|
|
|
RETVAL = strverscmp (a, b); |
726
|
|
|
|
|
|
|
OUTPUT: |
727
|
|
|
|
|
|
|
RETVAL |
728
|
|
|
|
|
|
|
|
729
|
|
|
|
|
|
|
#endif |
730
|
|
|
|
|
|
|
|