line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
/* |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
Library of typemap functions for C arrays, idea is to provide |
4
|
|
|
|
|
|
|
automatic conversion between references to perl arrays and C arrays. |
5
|
|
|
|
|
|
|
If the argument is a scalar this is automatically detected and handles |
6
|
|
|
|
|
|
|
as a one element array. |
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
Thanks go to Tim Bunce for the pointer to gv.h so I could figure |
9
|
|
|
|
|
|
|
out how to handle glob values. |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
Karl Glazebrook [kgb@aaoepp.aao.gov.au] |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
Dec 95: Add double precision arrays - frossie@jach.hawaii.edu |
15
|
|
|
|
|
|
|
Dec 96: Add 'ref to scalar is binary' handling - kgb@aaoepp.aao.gov.au |
16
|
|
|
|
|
|
|
Jan 97: Handles undefined values as zero - kgb@aaoepp.aao.gov.au |
17
|
|
|
|
|
|
|
Feb 97: Fixed a few type cast howlers+bugs - kgb@aaoepp.aao.gov.au |
18
|
|
|
|
|
|
|
Apr 97: Add support for unsigned char and shorts- timj@jach.hawaii.edu |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
*/ |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
#include "EXTERN.h" /* std perl include */ |
24
|
|
|
|
|
|
|
#include "perl.h" /* std perl include */ |
25
|
|
|
|
|
|
|
#include "XSUB.h" /* XSUB include */ |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
/* Functions defined in this module, see header comments on each one |
29
|
|
|
|
|
|
|
for more details: */ |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
#include "arrays.h" |
32
|
|
|
|
|
|
|
|
33
|
360
|
|
|
|
|
|
int is_scalar_ref (SV* arg) { /* Utility to determine if ref to scalar */ |
34
|
|
|
|
|
|
|
SV* foo; |
35
|
360
|
50
|
|
|
|
|
if (!SvROK(arg)) |
36
|
0
|
|
|
|
|
|
return 0; |
37
|
360
|
|
|
|
|
|
foo = SvRV(arg); |
38
|
360
|
100
|
|
|
|
|
if (SvPOK(foo)) |
39
|
110
|
|
|
|
|
|
return 1; |
40
|
|
|
|
|
|
|
else |
41
|
250
|
|
|
|
|
|
return 0; |
42
|
|
|
|
|
|
|
} |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
/* #################################################################################### |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
pack1D - argument is perl scalar variable and one char pack type. |
48
|
|
|
|
|
|
|
If it is a reference to a 1D array pack it and return pointer. |
49
|
|
|
|
|
|
|
If it is a glob pack the 1D array of the same name. |
50
|
|
|
|
|
|
|
If it is a scalar pack as 1 element array. |
51
|
|
|
|
|
|
|
If it is a reference to a scalar then assume scalar is prepacked binary data |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
[1D-ness is checked - routine croaks if any of the array elements |
54
|
|
|
|
|
|
|
themselves are references.] |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
Can be used in a typemap file (uses mortal scratch space and perl |
57
|
|
|
|
|
|
|
arrays know how big they are), e.g.: |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
TYPEMAP |
60
|
|
|
|
|
|
|
int * T_INTP |
61
|
|
|
|
|
|
|
float * T_FLOATP |
62
|
|
|
|
|
|
|
double * T_DOUBLEP |
63
|
|
|
|
|
|
|
INPUT |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
T_INTP |
66
|
|
|
|
|
|
|
$var = ($type)pack1D($arg,'i') |
67
|
|
|
|
|
|
|
T_FLOATP |
68
|
|
|
|
|
|
|
$var = ($type)pack1D($arg,'f') |
69
|
|
|
|
|
|
|
T_DOUBLEP |
70
|
|
|
|
|
|
|
$var = ($type)pack1D($arg,'d') |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
*/ |
73
|
|
|
|
|
|
|
|
74
|
203
|
|
|
|
|
|
void* pack1D ( SV* arg, char packtype ) { |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
int iscalar; |
77
|
|
|
|
|
|
|
float scalar; |
78
|
|
|
|
|
|
|
double dscalar; |
79
|
|
|
|
|
|
|
short sscalar; |
80
|
|
|
|
|
|
|
unsigned char uscalar; |
81
|
|
|
|
|
|
|
AV* array; |
82
|
|
|
|
|
|
|
I32 i,n; |
83
|
|
|
|
|
|
|
SV* work; |
84
|
|
|
|
|
|
|
SV** work2; |
85
|
|
|
|
|
|
|
double nval; |
86
|
|
|
|
|
|
|
STRLEN len; |
87
|
|
|
|
|
|
|
|
88
|
203
|
100
|
|
|
|
|
if (is_scalar_ref(arg)) /* Scalar ref */ |
89
|
110
|
50
|
|
|
|
|
return (void*) SvPV(SvRV(arg), len); |
90
|
|
|
|
|
|
|
|
91
|
93
|
50
|
|
|
|
|
if (packtype!='f' && packtype!='i' && packtype!='d' && packtype!='s' |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
92
|
0
|
0
|
|
|
|
|
&& packtype != 'u') |
93
|
0
|
|
|
|
|
|
croak("Programming error: invalid type conversion specified to pack1D"); |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
/* |
96
|
|
|
|
|
|
|
Create a work char variable - be cunning and make it a mortal *SV |
97
|
|
|
|
|
|
|
which will go away automagically when we leave the current |
98
|
|
|
|
|
|
|
context, i.e. no need to malloc and worry about freeing - thus |
99
|
|
|
|
|
|
|
we can use pack1D in a typemap! |
100
|
|
|
|
|
|
|
*/ |
101
|
|
|
|
|
|
|
|
102
|
93
|
|
|
|
|
|
work = sv_2mortal(newSVpv("", 0)); |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
/* Is arg a scalar? Return scalar*/ |
105
|
|
|
|
|
|
|
|
106
|
93
|
50
|
|
|
|
|
if (!SvROK(arg) && SvTYPE(arg)!=SVt_PVGV) { |
|
|
0
|
|
|
|
|
|
107
|
|
|
|
|
|
|
|
108
|
0
|
0
|
|
|
|
|
if (packtype=='f') { |
109
|
0
|
0
|
|
|
|
|
scalar = (float) SvNV(arg); /* Get the scalar value */ |
110
|
0
|
|
|
|
|
|
sv_setpvn(work, (char *) &scalar, sizeof(float)); /* Pack it in */ |
111
|
|
|
|
|
|
|
} |
112
|
0
|
0
|
|
|
|
|
if (packtype=='i') { |
113
|
0
|
0
|
|
|
|
|
iscalar = (int) SvNV(arg); /* Get the scalar value */ |
114
|
0
|
|
|
|
|
|
sv_setpvn(work, (char *) &iscalar, sizeof(int)); /* Pack it in */ |
115
|
|
|
|
|
|
|
} |
116
|
0
|
0
|
|
|
|
|
if (packtype=='d') { |
117
|
0
|
0
|
|
|
|
|
dscalar = (double) SvNV(arg); /*Get the scalar value */ |
118
|
0
|
|
|
|
|
|
sv_setpvn(work, (char *) &dscalar, sizeof(double)); /* Pack it in */ |
119
|
|
|
|
|
|
|
} |
120
|
0
|
0
|
|
|
|
|
if (packtype=='s') { |
121
|
0
|
0
|
|
|
|
|
sscalar = (short) SvNV(arg); /*Get the scalar value */ |
122
|
0
|
|
|
|
|
|
sv_setpvn(work, (char *) &sscalar, sizeof(short)); /* Pack it in */ |
123
|
|
|
|
|
|
|
} |
124
|
0
|
0
|
|
|
|
|
if (packtype=='u') { |
125
|
0
|
0
|
|
|
|
|
uscalar = (unsigned char) SvNV(arg); /*Get the scalar value */ |
126
|
0
|
|
|
|
|
|
sv_setpvn(work, (char *) &uscalar, sizeof(char)); /* Pack it in */ |
127
|
|
|
|
|
|
|
} |
128
|
0
|
0
|
|
|
|
|
return (void *) SvPV(work, PL_na); /* Return the pointer */ |
129
|
|
|
|
|
|
|
} |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
/* Is it a glob or reference to an array? */ |
132
|
|
|
|
|
|
|
|
133
|
93
|
50
|
|
|
|
|
if (SvTYPE(arg)==SVt_PVGV || (SvROK(arg) && SvTYPE(SvRV(arg))==SVt_PVAV)) { |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
134
|
|
|
|
|
|
|
|
135
|
93
|
50
|
|
|
|
|
if (SvTYPE(arg)==SVt_PVGV) { |
136
|
0
|
0
|
|
|
|
|
array = (AV *) GvAVn((GV*) arg); /* glob */ |
137
|
|
|
|
|
|
|
}else{ |
138
|
93
|
|
|
|
|
|
array = (AV *) SvRV(arg); /* reference */ |
139
|
|
|
|
|
|
|
} |
140
|
|
|
|
|
|
|
|
141
|
93
|
|
|
|
|
|
n = av_len(array); |
142
|
|
|
|
|
|
|
|
143
|
93
|
50
|
|
|
|
|
if (packtype=='f') |
144
|
0
|
0
|
|
|
|
|
SvGROW( work, sizeof(float)*(n+1) ); /* Pregrow for efficiency */ |
|
|
0
|
|
|
|
|
|
145
|
93
|
50
|
|
|
|
|
if (packtype=='i') |
146
|
0
|
0
|
|
|
|
|
SvGROW( work, sizeof(int)*(n+1) ); |
|
|
0
|
|
|
|
|
|
147
|
93
|
50
|
|
|
|
|
if (packtype=='d') |
148
|
93
|
50
|
|
|
|
|
SvGROW( work, sizeof(double)*(n+1) ); |
|
|
100
|
|
|
|
|
|
149
|
93
|
50
|
|
|
|
|
if (packtype=='s') |
150
|
0
|
0
|
|
|
|
|
SvGROW( work, sizeof(short)*(n+1) ); |
|
|
0
|
|
|
|
|
|
151
|
93
|
50
|
|
|
|
|
if (packtype=='u') |
152
|
0
|
0
|
|
|
|
|
SvGROW( work, sizeof(char)*(n+1) ); |
|
|
0
|
|
|
|
|
|
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
/* Pack array into string */ |
156
|
|
|
|
|
|
|
|
157
|
591165
|
100
|
|
|
|
|
for(i=0; i<=n; i++) { |
158
|
|
|
|
|
|
|
|
159
|
591072
|
|
|
|
|
|
work2 = av_fetch( array, i, 0 ); /* Fetch */ |
160
|
591072
|
50
|
|
|
|
|
if (work2==NULL) |
161
|
0
|
|
|
|
|
|
nval = 0.0; /* Undefined */ |
162
|
|
|
|
|
|
|
else { |
163
|
591072
|
50
|
|
|
|
|
if (SvROK(*work2)) |
164
|
0
|
|
|
|
|
|
goto errexit; /* Croak if reference [i.e. not 1D] */ |
165
|
591072
|
100
|
|
|
|
|
nval = SvNV(*work2); |
166
|
|
|
|
|
|
|
} |
167
|
|
|
|
|
|
|
|
168
|
591072
|
50
|
|
|
|
|
if (packtype=='f') { |
169
|
0
|
|
|
|
|
|
scalar = (float) nval; |
170
|
0
|
|
|
|
|
|
sv_catpvn( work, (char *) &scalar, sizeof(float)); |
171
|
|
|
|
|
|
|
} |
172
|
591072
|
50
|
|
|
|
|
if (packtype=='i') { |
173
|
0
|
|
|
|
|
|
iscalar = (int) nval; |
174
|
0
|
|
|
|
|
|
sv_catpvn( work, (char *) &iscalar, sizeof(int)); |
175
|
|
|
|
|
|
|
} |
176
|
591072
|
50
|
|
|
|
|
if (packtype=='d') { |
177
|
591072
|
|
|
|
|
|
dscalar = (double) nval; |
178
|
591072
|
|
|
|
|
|
sv_catpvn( work, (char *) &dscalar, sizeof(double)); |
179
|
|
|
|
|
|
|
} |
180
|
591072
|
50
|
|
|
|
|
if (packtype=='s') { |
181
|
0
|
|
|
|
|
|
sscalar = (short) nval; |
182
|
0
|
|
|
|
|
|
sv_catpvn( work, (char *) &sscalar, sizeof(short)); |
183
|
|
|
|
|
|
|
} |
184
|
591072
|
50
|
|
|
|
|
if (packtype=='u') { |
185
|
0
|
|
|
|
|
|
uscalar = (unsigned char) nval; |
186
|
0
|
|
|
|
|
|
sv_catpvn( work, (char *) &uscalar, sizeof(char)); |
187
|
|
|
|
|
|
|
} |
188
|
|
|
|
|
|
|
} |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
/* Return a pointer to the byte array */ |
191
|
|
|
|
|
|
|
|
192
|
93
|
50
|
|
|
|
|
return (void *) SvPV(work, PL_na); |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
} |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
errexit: |
197
|
|
|
|
|
|
|
|
198
|
203
|
|
|
|
|
|
croak("Routine can only handle scalar values or refs to 1D arrays of scalars"); |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
} |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
/* ##################################################################################### |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
pack2D - argument is perl scalar variable and one char pack type. |
207
|
|
|
|
|
|
|
If it is a reference to a 1D/2D array pack it and return pointer. |
208
|
|
|
|
|
|
|
If it is a glob pack the 1D/2D array of the same name. |
209
|
|
|
|
|
|
|
If it is a scalar assume it is a prepacked array and return pointer |
210
|
|
|
|
|
|
|
to char part of scalar. |
211
|
|
|
|
|
|
|
If it is a reference to a scalar then assume scalar is prepacked binary data |
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
[2Dness is checked - program croaks if any of the array elements |
214
|
|
|
|
|
|
|
themselves are references. Packs each row sequentially even if |
215
|
|
|
|
|
|
|
they are not all the same dimension - it is up to the programmer |
216
|
|
|
|
|
|
|
to decide if this is sensible or not.] |
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
Can be used in a typemap file (uses mortal scratch space and perl |
219
|
|
|
|
|
|
|
arrays know how big they are), e.g.: |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
TYPEMAP |
222
|
|
|
|
|
|
|
int2D * T_INT2DP |
223
|
|
|
|
|
|
|
float2D * T_FLOAT2DP |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
INPUT |
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
T_INT2DP |
228
|
|
|
|
|
|
|
$var = ($type)pack2D($arg,'i') |
229
|
|
|
|
|
|
|
T_FLOAT2DP |
230
|
|
|
|
|
|
|
$var = ($type)pack2D($arg,'f') |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
[int2D/float2D would be typedef'd to int/float] |
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
*/ |
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
|
237
|
10
|
|
|
|
|
|
void* pack2D ( SV* arg, char packtype ) { |
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
int iscalar; |
240
|
|
|
|
|
|
|
float scalar; |
241
|
|
|
|
|
|
|
short sscalar; |
242
|
|
|
|
|
|
|
double dscalar; |
243
|
|
|
|
|
|
|
unsigned char uscalar; |
244
|
|
|
|
|
|
|
AV* array; |
245
|
|
|
|
|
|
|
AV* array2; |
246
|
|
|
|
|
|
|
I32 i,j,n,m; |
247
|
|
|
|
|
|
|
SV* work; |
248
|
|
|
|
|
|
|
SV** work2; |
249
|
|
|
|
|
|
|
double nval; |
250
|
|
|
|
|
|
|
int isref; |
251
|
|
|
|
|
|
|
STRLEN len; |
252
|
|
|
|
|
|
|
|
253
|
10
|
50
|
|
|
|
|
if (is_scalar_ref(arg)) /* Scalar ref */ |
254
|
0
|
0
|
|
|
|
|
return (void*) SvPV(SvRV(arg), len); |
255
|
|
|
|
|
|
|
|
256
|
10
|
50
|
|
|
|
|
if (packtype!='f' && packtype!='i' && packtype!='d' && packtype!='s' |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
257
|
0
|
0
|
|
|
|
|
&& packtype!='u') |
258
|
0
|
|
|
|
|
|
croak("Programming error: invalid type conversion specified to pack2D"); |
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
/* Is arg a scalar? Return pointer to char part */ |
261
|
|
|
|
|
|
|
|
262
|
10
|
50
|
|
|
|
|
if (!SvROK(arg) && SvTYPE(arg)!=SVt_PVGV) { return (void *) SvPV(arg, PL_na); } |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
/* |
265
|
|
|
|
|
|
|
Create a work char variable - be cunning and make it a mortal *SV |
266
|
|
|
|
|
|
|
which will go away automagically when we leave the current |
267
|
|
|
|
|
|
|
context, i.e. no need to malloc and worry about freeing - thus |
268
|
|
|
|
|
|
|
we can use pack2D in a typemap! |
269
|
|
|
|
|
|
|
*/ |
270
|
|
|
|
|
|
|
|
271
|
10
|
|
|
|
|
|
work = sv_2mortal(newSVpv("", 0)); |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
/* Is it a glob or reference to an array? */ |
274
|
|
|
|
|
|
|
|
275
|
10
|
50
|
|
|
|
|
if (SvTYPE(arg)==SVt_PVGV || (SvROK(arg) && SvTYPE(SvRV(arg))==SVt_PVAV)) { |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
276
|
|
|
|
|
|
|
|
277
|
10
|
50
|
|
|
|
|
if (SvTYPE(arg)==SVt_PVGV) { |
278
|
0
|
0
|
|
|
|
|
array = GvAVn((GV*) arg); /* glob */ |
279
|
|
|
|
|
|
|
}else{ |
280
|
10
|
|
|
|
|
|
array = (AV *) SvRV(arg); /* reference */ |
281
|
|
|
|
|
|
|
} |
282
|
|
|
|
|
|
|
|
283
|
10
|
|
|
|
|
|
n = av_len(array); |
284
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
/* Pack array into string */ |
286
|
|
|
|
|
|
|
|
287
|
250
|
100
|
|
|
|
|
for(i=0; i<=n; i++) { /* Loop over 1st dimension */ |
288
|
|
|
|
|
|
|
|
289
|
240
|
|
|
|
|
|
work2 = av_fetch( array, i, 0 ); /* Fetch */ |
290
|
|
|
|
|
|
|
|
291
|
240
|
50
|
|
|
|
|
isref = work2!=NULL && SvROK(*work2); /* Is is a reference */ |
|
|
50
|
|
|
|
|
|
292
|
|
|
|
|
|
|
|
293
|
240
|
50
|
|
|
|
|
if (isref) { |
294
|
240
|
|
|
|
|
|
array2 = (AV *) SvRV(*work2); /* array of 2nd dimension */ |
295
|
240
|
|
|
|
|
|
m = av_len(array2); /* Length */ |
296
|
|
|
|
|
|
|
}else{ |
297
|
0
|
|
|
|
|
|
m=0; /* 1D array */ |
298
|
0
|
0
|
|
|
|
|
nval = SvNV(*work2); |
299
|
|
|
|
|
|
|
} |
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
/* Pregrow storage for efficiency on first row - note assumes |
302
|
|
|
|
|
|
|
array is rectangular but better than nothing */ |
303
|
|
|
|
|
|
|
|
304
|
240
|
100
|
|
|
|
|
if (i==0) { |
305
|
10
|
50
|
|
|
|
|
if (packtype=='f') |
306
|
0
|
0
|
|
|
|
|
SvGROW( work, sizeof(float)*(n+1)*(m+1) ); |
|
|
0
|
|
|
|
|
|
307
|
10
|
50
|
|
|
|
|
if (packtype=='i') |
308
|
0
|
0
|
|
|
|
|
SvGROW( work, sizeof(int)*(n+1)*(m+1) ); |
|
|
0
|
|
|
|
|
|
309
|
10
|
50
|
|
|
|
|
if (packtype=='s') |
310
|
0
|
0
|
|
|
|
|
SvGROW( work, sizeof(short)*(n+1)*(m+1) ); |
|
|
0
|
|
|
|
|
|
311
|
10
|
50
|
|
|
|
|
if (packtype=='u') |
312
|
0
|
0
|
|
|
|
|
SvGROW( work, sizeof(char)*(n+1)*(m+1) ); |
|
|
0
|
|
|
|
|
|
313
|
10
|
50
|
|
|
|
|
if (packtype=='d') |
314
|
10
|
50
|
|
|
|
|
SvGROW( work, sizeof(double)*(n+1)*(m+1) ); |
|
|
50
|
|
|
|
|
|
315
|
|
|
|
|
|
|
} |
316
|
|
|
|
|
|
|
|
317
|
7920
|
100
|
|
|
|
|
for(j=0; j<=m; j++) { /* Loop over 2nd dimension */ |
318
|
|
|
|
|
|
|
|
319
|
7680
|
50
|
|
|
|
|
if (isref) { |
320
|
7680
|
|
|
|
|
|
work2 = av_fetch( array2, j, 0 ); /* Fetch element */ |
321
|
7680
|
50
|
|
|
|
|
if (work2==NULL) |
322
|
0
|
|
|
|
|
|
nval = 0.0; /* Undefined */ |
323
|
|
|
|
|
|
|
else { |
324
|
7680
|
50
|
|
|
|
|
if (SvROK(*work2)) |
325
|
0
|
|
|
|
|
|
goto errexit; /* Croak if reference [i.e. not 1D] */ |
326
|
7680
|
100
|
|
|
|
|
nval = SvNV(*work2); |
327
|
|
|
|
|
|
|
} |
328
|
|
|
|
|
|
|
} |
329
|
|
|
|
|
|
|
|
330
|
7680
|
50
|
|
|
|
|
if (packtype=='d') { |
331
|
7680
|
|
|
|
|
|
dscalar = (double) nval; |
332
|
7680
|
|
|
|
|
|
sv_catpvn( work, (char *) &dscalar, sizeof(double)); |
333
|
|
|
|
|
|
|
} |
334
|
7680
|
50
|
|
|
|
|
if (packtype=='f') { |
335
|
0
|
|
|
|
|
|
scalar = (float) nval; |
336
|
0
|
|
|
|
|
|
sv_catpvn( work, (char *) &scalar, sizeof(float)); |
337
|
|
|
|
|
|
|
} |
338
|
7680
|
50
|
|
|
|
|
if (packtype=='i') { |
339
|
0
|
|
|
|
|
|
iscalar = (int) nval; |
340
|
0
|
|
|
|
|
|
sv_catpvn( work, (char *) &iscalar, sizeof(int)); |
341
|
|
|
|
|
|
|
} |
342
|
7680
|
50
|
|
|
|
|
if (packtype=='s') { |
343
|
0
|
|
|
|
|
|
sscalar = (short) nval; |
344
|
0
|
|
|
|
|
|
sv_catpvn( work, (char *) &sscalar, sizeof(short)); |
345
|
|
|
|
|
|
|
} |
346
|
7680
|
50
|
|
|
|
|
if (packtype=='u') { |
347
|
0
|
|
|
|
|
|
uscalar = (unsigned char) nval; |
348
|
0
|
|
|
|
|
|
sv_catpvn( work, (char *) &uscalar, sizeof(char)); |
349
|
|
|
|
|
|
|
} |
350
|
|
|
|
|
|
|
} |
351
|
|
|
|
|
|
|
} |
352
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
/* Return a pointer to the byte array */ |
354
|
|
|
|
|
|
|
|
355
|
10
|
50
|
|
|
|
|
return (void *) SvPV(work, PL_na); |
356
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
} |
358
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
errexit: |
360
|
|
|
|
|
|
|
|
361
|
10
|
|
|
|
|
|
croak("Routine can only handle scalar packed char values or refs to 1D or 2D arrays"); |
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
} |
364
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
/* ################################################################################### |
366
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
packND - argument is perl scalar variable and one char pack type. |
368
|
|
|
|
|
|
|
arg is treated as a reference to an array of arbitrary dimensions. |
369
|
|
|
|
|
|
|
Pointer to packed data is returned. |
370
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
It is packed recursively, i.e. if an element is a scalar it is |
372
|
|
|
|
|
|
|
packed on the end of the string, if it is a reference the array it |
373
|
|
|
|
|
|
|
points to is packed on the end with further recursive traversal. For |
374
|
|
|
|
|
|
|
a 2D input will produce the same result as pack2D though without, |
375
|
|
|
|
|
|
|
obviously, dimensional checking. Since we don't know in advance how |
376
|
|
|
|
|
|
|
big it is we can't preallocate the storage so this may be inefficient. |
377
|
|
|
|
|
|
|
Note, as in other pack routines globs are handled as the equivalent |
378
|
|
|
|
|
|
|
1D array. |
379
|
|
|
|
|
|
|
|
380
|
|
|
|
|
|
|
e.g. [1,[2,2,[-4,-4]]],-1,0,1, 2,3,4] is packed as 1,2,2,-4,-4,-1,0,1,2,3,4 |
381
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
If arg is a reference to a scalar then assume scalar is prepacked binary data. |
383
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
Can be used in a typemap file (uses mortal scratch space). |
385
|
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
*/ |
387
|
|
|
|
|
|
|
|
388
|
0
|
|
|
|
|
|
void* packND ( SV* arg, char packtype ) { |
389
|
|
|
|
|
|
|
|
390
|
|
|
|
|
|
|
SV* work; |
391
|
|
|
|
|
|
|
STRLEN len; |
392
|
|
|
|
|
|
|
void pack_element(SV* work, SV** arg, char packtype); /* Called by packND */ |
393
|
|
|
|
|
|
|
|
394
|
0
|
0
|
|
|
|
|
if (is_scalar_ref(arg)) /* Scalar ref */ |
395
|
0
|
0
|
|
|
|
|
return (void*) SvPV(SvRV(arg), len); |
396
|
|
|
|
|
|
|
|
397
|
0
|
0
|
|
|
|
|
if (packtype!='f' && packtype!='i' && packtype!='d' |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
398
|
0
|
0
|
|
|
|
|
&& packtype!='s' && packtype!='u') |
|
|
0
|
|
|
|
|
|
399
|
0
|
|
|
|
|
|
croak("Programming error: invalid type conversion specified to packND"); |
400
|
|
|
|
|
|
|
|
401
|
|
|
|
|
|
|
/* |
402
|
|
|
|
|
|
|
Create a work char variable - be cunning and make it a mortal *SV |
403
|
|
|
|
|
|
|
which will go away automagically when we leave the current |
404
|
|
|
|
|
|
|
context, i.e. no need to malloc and worry about freeing - thus |
405
|
|
|
|
|
|
|
we can use packND in a typemap! |
406
|
|
|
|
|
|
|
*/ |
407
|
|
|
|
|
|
|
|
408
|
0
|
|
|
|
|
|
work = sv_2mortal(newSVpv("", 0)); |
409
|
|
|
|
|
|
|
|
410
|
0
|
|
|
|
|
|
pack_element(work, &arg, packtype); |
411
|
|
|
|
|
|
|
|
412
|
0
|
0
|
|
|
|
|
return (void *) SvPV(work, PL_na); |
413
|
|
|
|
|
|
|
|
414
|
|
|
|
|
|
|
} |
415
|
|
|
|
|
|
|
|
416
|
|
|
|
|
|
|
/* Internal function of packND - pack an element recursively */ |
417
|
|
|
|
|
|
|
|
418
|
0
|
|
|
|
|
|
void pack_element(SV* work, SV** arg, char packtype) { |
419
|
|
|
|
|
|
|
|
420
|
|
|
|
|
|
|
I32 i,n; |
421
|
|
|
|
|
|
|
AV* array; |
422
|
|
|
|
|
|
|
int iscalar; |
423
|
|
|
|
|
|
|
float scalar; |
424
|
|
|
|
|
|
|
short sscalar; |
425
|
|
|
|
|
|
|
unsigned char uscalar; |
426
|
|
|
|
|
|
|
double nval; |
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
/* Pack element arg onto work recursively */ |
429
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
/* Is arg a scalar? Pack and return */ |
431
|
|
|
|
|
|
|
|
432
|
0
|
0
|
|
|
|
|
if (arg==NULL || (!SvROK(*arg) && SvTYPE(*arg)!=SVt_PVGV)) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
433
|
|
|
|
|
|
|
|
434
|
0
|
0
|
|
|
|
|
if (arg==NULL) |
435
|
0
|
|
|
|
|
|
nval = 0.0; |
436
|
|
|
|
|
|
|
else |
437
|
0
|
0
|
|
|
|
|
nval = SvNV(*arg); |
438
|
|
|
|
|
|
|
|
439
|
0
|
0
|
|
|
|
|
if (packtype=='f') { |
440
|
0
|
|
|
|
|
|
scalar = (float) nval; /* Get the scalar value */ |
441
|
0
|
|
|
|
|
|
sv_catpvn(work, (char *) &scalar, sizeof(float)); /* Pack it in */ |
442
|
|
|
|
|
|
|
} |
443
|
0
|
0
|
|
|
|
|
if (packtype=='i') { |
444
|
0
|
|
|
|
|
|
iscalar = (int) nval; /* Get the scalar value */ |
445
|
0
|
|
|
|
|
|
sv_catpvn(work, (char *) &iscalar, sizeof(int)); /* Pack it in */ |
446
|
|
|
|
|
|
|
} |
447
|
0
|
0
|
|
|
|
|
if (packtype=='d') { |
448
|
0
|
|
|
|
|
|
sv_catpvn(work, (char *) &nval, sizeof(double)); /* Pack it in */ |
449
|
|
|
|
|
|
|
} |
450
|
0
|
0
|
|
|
|
|
if (packtype=='s') { |
451
|
0
|
|
|
|
|
|
sscalar = (short) nval; /* Get the scalar value */ |
452
|
0
|
|
|
|
|
|
sv_catpvn(work, (char *) &sscalar, sizeof(short)); /* Pack it in */ |
453
|
|
|
|
|
|
|
} |
454
|
0
|
0
|
|
|
|
|
if (packtype=='u') { |
455
|
0
|
|
|
|
|
|
uscalar = (unsigned char) nval; |
456
|
0
|
|
|
|
|
|
sv_catpvn(work, (char *) &uscalar, sizeof(char)); /* Pack it in */ |
457
|
|
|
|
|
|
|
} |
458
|
|
|
|
|
|
|
|
459
|
0
|
|
|
|
|
|
return; |
460
|
|
|
|
|
|
|
} |
461
|
|
|
|
|
|
|
|
462
|
|
|
|
|
|
|
/* Is it a glob or reference to an array? */ |
463
|
|
|
|
|
|
|
|
464
|
0
|
0
|
|
|
|
|
if (SvTYPE(*arg)==SVt_PVGV || (SvROK(*arg) && SvTYPE(SvRV(*arg))==SVt_PVAV)) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
465
|
|
|
|
|
|
|
|
466
|
|
|
|
|
|
|
/* Dereference */ |
467
|
|
|
|
|
|
|
|
468
|
0
|
0
|
|
|
|
|
if (SvTYPE(*arg)==SVt_PVGV) { |
469
|
0
|
0
|
|
|
|
|
array = GvAVn((GV*)*arg); /* glob */ |
470
|
|
|
|
|
|
|
}else{ |
471
|
0
|
|
|
|
|
|
array = (AV *) SvRV(*arg); /* reference */ |
472
|
|
|
|
|
|
|
} |
473
|
|
|
|
|
|
|
|
474
|
|
|
|
|
|
|
/* Pack each array element */ |
475
|
|
|
|
|
|
|
|
476
|
0
|
|
|
|
|
|
n = av_len(array); |
477
|
|
|
|
|
|
|
|
478
|
0
|
0
|
|
|
|
|
for (i=0; i<=n; i++) { |
479
|
|
|
|
|
|
|
|
480
|
|
|
|
|
|
|
/* To curse is human, to recurse divine */ |
481
|
|
|
|
|
|
|
|
482
|
0
|
|
|
|
|
|
pack_element(work, av_fetch(array, i, 0), packtype ); |
483
|
|
|
|
|
|
|
} |
484
|
0
|
|
|
|
|
|
return; |
485
|
|
|
|
|
|
|
} |
486
|
|
|
|
|
|
|
|
487
|
|
|
|
|
|
|
errexit: |
488
|
|
|
|
|
|
|
|
489
|
0
|
|
|
|
|
|
croak("Routine can only handle scalars or refs to N-D arrays of scalars"); |
490
|
|
|
|
|
|
|
|
491
|
|
|
|
|
|
|
} |
492
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
|
494
|
|
|
|
|
|
|
/* ################################################################################## |
495
|
|
|
|
|
|
|
|
496
|
|
|
|
|
|
|
unpack1D - take packed string (C array) and write back into perl 1D array. |
497
|
|
|
|
|
|
|
If 1st argument is a reference, unpack into this array. |
498
|
|
|
|
|
|
|
If 1st argument is a glob, unpack into the 1D array of the same name. |
499
|
|
|
|
|
|
|
|
500
|
|
|
|
|
|
|
Can only be used in a typemap if the size of the array is known |
501
|
|
|
|
|
|
|
in advance or is the size of a preexisting perl array (n=0). If it |
502
|
|
|
|
|
|
|
is determined by another variable you may have to put in in some |
503
|
|
|
|
|
|
|
direct CODE: lines in the XSUB file. |
504
|
|
|
|
|
|
|
|
505
|
|
|
|
|
|
|
*/ |
506
|
|
|
|
|
|
|
|
507
|
55
|
|
|
|
|
|
void unpack1D ( SV* arg, void * var, char packtype, int n ) { |
508
|
|
|
|
|
|
|
|
509
|
|
|
|
|
|
|
/* n is the size of array var[] (n=1 for 1 element, etc.) If n=0 take |
510
|
|
|
|
|
|
|
var[] as having the same dimension as array referenced by arg */ |
511
|
|
|
|
|
|
|
|
512
|
|
|
|
|
|
|
int* ivar; |
513
|
|
|
|
|
|
|
float* fvar; |
514
|
|
|
|
|
|
|
double* dvar; |
515
|
|
|
|
|
|
|
short* svar; |
516
|
|
|
|
|
|
|
unsigned char* uvar; |
517
|
|
|
|
|
|
|
/* SV* work; */ |
518
|
|
|
|
|
|
|
AV* array; |
519
|
|
|
|
|
|
|
I32 i,m; |
520
|
|
|
|
|
|
|
|
521
|
|
|
|
|
|
|
/* Note in ref to scalar case data is already changed */ |
522
|
|
|
|
|
|
|
|
523
|
55
|
50
|
|
|
|
|
if (is_scalar_ref(arg)) /* Do nothing */ |
524
|
0
|
|
|
|
|
|
return; |
525
|
|
|
|
|
|
|
|
526
|
55
|
50
|
|
|
|
|
if (packtype!='f' && packtype!='i' && packtype!= 'd' && |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
527
|
0
|
0
|
|
|
|
|
packtype!='u' && packtype!='s') |
528
|
0
|
|
|
|
|
|
croak("Programming error: invalid type conversion specified to unpack1D"); |
529
|
|
|
|
|
|
|
|
530
|
55
|
|
|
|
|
|
m=n; array = coerce1D( arg, m ); /* Get array ref and coerce */ |
531
|
|
|
|
|
|
|
|
532
|
55
|
50
|
|
|
|
|
if (m==0) |
533
|
55
|
|
|
|
|
|
m = av_len( array )+1; |
534
|
|
|
|
|
|
|
|
535
|
55
|
50
|
|
|
|
|
if (packtype=='i') /* Cast void array var[] to appropriate type */ |
536
|
0
|
|
|
|
|
|
ivar = (int *) var; |
537
|
55
|
50
|
|
|
|
|
if (packtype=='f') |
538
|
0
|
|
|
|
|
|
fvar = (float *) var; |
539
|
55
|
50
|
|
|
|
|
if (packtype=='d') |
540
|
55
|
|
|
|
|
|
dvar = (double *) var; |
541
|
55
|
50
|
|
|
|
|
if (packtype=='u') |
542
|
0
|
|
|
|
|
|
uvar = (unsigned char *) var; |
543
|
55
|
50
|
|
|
|
|
if (packtype=='s') |
544
|
0
|
|
|
|
|
|
svar = (short *) var; |
545
|
|
|
|
|
|
|
|
546
|
|
|
|
|
|
|
/* Unpack into the array */ |
547
|
|
|
|
|
|
|
|
548
|
524967
|
100
|
|
|
|
|
for(i=0; i
|
549
|
524912
|
50
|
|
|
|
|
if (packtype=='i') |
550
|
0
|
|
|
|
|
|
av_store( array, i, newSViv( (IV)ivar[i] ) ); |
551
|
524912
|
50
|
|
|
|
|
if (packtype=='f') |
552
|
0
|
|
|
|
|
|
av_store( array, i, newSVnv( (double)fvar[i] ) ); |
553
|
524912
|
50
|
|
|
|
|
if (packtype=='d') |
554
|
524912
|
|
|
|
|
|
av_store( array, i, newSVnv( (double)dvar[i] ) ); |
555
|
524912
|
50
|
|
|
|
|
if (packtype=='u') |
556
|
0
|
|
|
|
|
|
av_store( array, i, newSViv( (IV)uvar[i] ) ); |
557
|
524912
|
50
|
|
|
|
|
if (packtype=='s') |
558
|
0
|
|
|
|
|
|
av_store( array, i, newSViv( (IV)svar[i] ) ); |
559
|
|
|
|
|
|
|
} |
560
|
|
|
|
|
|
|
|
561
|
55
|
|
|
|
|
|
return; |
562
|
|
|
|
|
|
|
} |
563
|
|
|
|
|
|
|
|
564
|
|
|
|
|
|
|
|
565
|
|
|
|
|
|
|
/* ################################################################################# |
566
|
|
|
|
|
|
|
|
567
|
|
|
|
|
|
|
coerce1D - utility function. Make sure arg is a reference to a 1D array |
568
|
|
|
|
|
|
|
of size at least n, creating/extending as necessary. Fill with zeroes. |
569
|
|
|
|
|
|
|
Return reference to array. If n=0 just returns reference to array, |
570
|
|
|
|
|
|
|
creating as necessary. |
571
|
|
|
|
|
|
|
*/ |
572
|
|
|
|
|
|
|
|
573
|
92
|
|
|
|
|
|
AV* coerce1D ( SV* arg, int n ) { |
574
|
|
|
|
|
|
|
|
575
|
|
|
|
|
|
|
/* n is the size of array var[] (n=1 for 1 element, etc.) */ |
576
|
|
|
|
|
|
|
|
577
|
|
|
|
|
|
|
AV* array; |
578
|
|
|
|
|
|
|
I32 i,m; |
579
|
|
|
|
|
|
|
|
580
|
|
|
|
|
|
|
/* In ref to scalar case we can do nothing - we can only hope the |
581
|
|
|
|
|
|
|
caller made the scalar the right size in the first place */ |
582
|
|
|
|
|
|
|
|
583
|
92
|
50
|
|
|
|
|
if (is_scalar_ref(arg)) /* Do nothing */ |
584
|
0
|
|
|
|
|
|
return (AV*)NULL; |
585
|
|
|
|
|
|
|
|
586
|
|
|
|
|
|
|
/* Check what has been passed and create array reference whether it |
587
|
|
|
|
|
|
|
exists or not */ |
588
|
|
|
|
|
|
|
|
589
|
92
|
50
|
|
|
|
|
if (SvTYPE(arg)==SVt_PVGV) { |
590
|
0
|
0
|
|
|
|
|
array = GvAVn((GV*)arg); /* glob */ |
591
|
92
|
50
|
|
|
|
|
}else if (SvROK(arg) && SvTYPE(SvRV(arg))==SVt_PVAV) { |
|
|
50
|
|
|
|
|
|
592
|
92
|
|
|
|
|
|
array = (AV *) SvRV(arg); /* reference */ |
593
|
|
|
|
|
|
|
}else{ |
594
|
0
|
|
|
|
|
|
array = newAV(); /* Create */ |
595
|
0
|
|
|
|
|
|
sv_setsv(arg, newRV((SV*) array)); |
596
|
|
|
|
|
|
|
} |
597
|
|
|
|
|
|
|
|
598
|
92
|
|
|
|
|
|
m = av_len(array); |
599
|
|
|
|
|
|
|
|
600
|
66296
|
100
|
|
|
|
|
for (i=m+1; i
|
601
|
66204
|
|
|
|
|
|
av_store( array, i, newSViv( (IV) 0 ) ); |
602
|
|
|
|
|
|
|
} |
603
|
|
|
|
|
|
|
|
604
|
92
|
|
|
|
|
|
return array; |
605
|
|
|
|
|
|
|
} |
606
|
|
|
|
|
|
|
|
607
|
|
|
|
|
|
|
|
608
|
|
|
|
|
|
|
/* ################################################################################ |
609
|
|
|
|
|
|
|
|
610
|
|
|
|
|
|
|
get_mortalspace - utility to get temporary memory space. Uses |
611
|
|
|
|
|
|
|
a mortal *SV for this so it is automatically freed when the current |
612
|
|
|
|
|
|
|
context is terminated. Useful in typemap's for OUTPUT only arrays. |
613
|
|
|
|
|
|
|
|
614
|
|
|
|
|
|
|
*/ |
615
|
|
|
|
|
|
|
|
616
|
|
|
|
|
|
|
|
617
|
0
|
|
|
|
|
|
void* get_mortalspace( int n, char packtype ) { |
618
|
|
|
|
|
|
|
|
619
|
|
|
|
|
|
|
/* n is the number of elements of space required, packtype is 'f' or 'i' */ |
620
|
|
|
|
|
|
|
|
621
|
|
|
|
|
|
|
SV* work; |
622
|
|
|
|
|
|
|
|
623
|
0
|
0
|
|
|
|
|
if (packtype!='f' && packtype!='i' && packtype!='d' |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
624
|
0
|
0
|
|
|
|
|
&& packtype!='u' && packtype!='s') |
|
|
0
|
|
|
|
|
|
625
|
0
|
|
|
|
|
|
croak("Programming error: invalid type conversion specified to get_mortalspace"); |
626
|
|
|
|
|
|
|
|
627
|
0
|
|
|
|
|
|
work = sv_2mortal(newSVpv("", 0)); |
628
|
|
|
|
|
|
|
|
629
|
0
|
0
|
|
|
|
|
if (packtype=='f') |
630
|
0
|
0
|
|
|
|
|
SvGROW( work, sizeof(float)*n ); /* Pregrow for efficiency */ |
|
|
0
|
|
|
|
|
|
631
|
0
|
0
|
|
|
|
|
if (packtype=='i') |
632
|
0
|
0
|
|
|
|
|
SvGROW( work, sizeof(int)*n ); |
|
|
0
|
|
|
|
|
|
633
|
0
|
0
|
|
|
|
|
if (packtype=='d') |
634
|
0
|
0
|
|
|
|
|
SvGROW( work, sizeof(double)*n); |
|
|
0
|
|
|
|
|
|
635
|
0
|
0
|
|
|
|
|
if (packtype=='u') |
636
|
0
|
0
|
|
|
|
|
SvGROW( work, sizeof(char)*n); |
|
|
0
|
|
|
|
|
|
637
|
0
|
0
|
|
|
|
|
if (packtype=='s') |
638
|
0
|
0
|
|
|
|
|
SvGROW( work, sizeof(short)*n); |
|
|
0
|
|
|
|
|
|
639
|
|
|
|
|
|
|
|
640
|
0
|
0
|
|
|
|
|
return (void *) SvPV(work, PL_na); |
641
|
|
|
|
|
|
|
} |