nwrfc 0.0.5 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +15 -0
- data/README.rdoc +124 -120
- data/Rakefile +8 -8
- data/lib/nwrfc.rb +390 -389
- data/lib/nwrfc/datacontainer.rb +337 -337
- data/lib/nwrfc/nwerror.rb +39 -24
- data/lib/nwrfc/nwrfclib.rb +436 -436
- data/lib/nwrfc/server.rb +45 -45
- metadata +37 -59
data/lib/nwrfc/datacontainer.rb
CHANGED
@@ -1,338 +1,338 @@
|
|
1
|
-
module NWRFC
|
2
|
-
|
3
|
-
# Representation of a data container (function, structure or table)
|
4
|
-
# Implements common functions for data containers, such as setting and getting values, tables, structures and
|
5
|
-
# takes care of type conversion and calling correct SDK functions to set or get values
|
6
|
-
#
|
7
|
-
# == Type Conversions
|
8
|
-
# To ensure that data is passed correctly to the NW RFC SDK functions, certain conversions are applied to values
|
9
|
-
# passed, depending on the type of the field. ABAP supports a number of elementary types, which are listed in the
|
10
|
-
#
|
11
|
-
# DECFLOAT16 and DECFLOAT34 types are not yet supported.
|
12
|
-
#
|
13
|
-
# === Inbound
|
14
|
-
# For character and string
|
15
|
-
class DataContainer
|
16
|
-
attr_reader :handle, :desc
|
17
|
-
|
18
|
-
def initialize(handle)
|
19
|
-
@error = NWRFCLib::RFCError.new
|
20
|
-
@handle = handle
|
21
|
-
@desc = NWRFCLib.describe_type(@handle, @error)
|
22
|
-
@member_metadata = {} #Cache of metadata for members
|
23
|
-
NWRFC.check_error(@error)
|
24
|
-
end
|
25
|
-
|
26
|
-
#--
|
27
|
-
# VALUE RETRIEVAL
|
28
|
-
#++
|
29
|
-
|
30
|
-
# Get value from a data container (structure, function instance or table)
|
31
|
-
def [](element)
|
32
|
-
member = element.to_s.upcase
|
33
|
-
metadata = member_metadata(element)
|
34
|
-
case metadata[:type]
|
35
|
-
|
36
|
-
when :RFCTYPE_CHAR
|
37
|
-
# TODO: Try use :string parameter in get_chars
|
38
|
-
return read_chars(metadata)
|
39
|
-
|
40
|
-
when :RFCTYPE_DATE
|
41
|
-
return Date.parse(read_chars(metadata))
|
42
|
-
#return Date.new(date[0..3].to_i, date[4..5].to_i, date[6..7].to_i)
|
43
|
-
|
44
|
-
when :RFCTYPE_BCD
|
45
|
-
size = metadata[:nucLength] + (metadata[:decimals] || 0)
|
46
|
-
buf = FFI::MemoryPointer.new(:uchar, size*2)
|
47
|
-
rc = NWRFCLib.get_chars(@handle, metadata[:name].cU, buf, size, @error.to_ptr)
|
48
|
-
NWRFC.check_error(@error) if rc > 0
|
49
|
-
return buf.get_bytes(0, size*2).uC.to_f
|
50
|
-
#size = metadata[:ucLength]
|
51
|
-
#cb = FFI::MemoryPointer.new :char, size * 2
|
52
|
-
#rc = NWRFCLib.get_chars(@handle, metadata[:name].cU, cb, size * 2, @error.to_ptr)
|
53
|
-
#NWRFC.check_error(@error) if rc > 0
|
54
|
-
#cb.read_string(size).uC
|
55
|
-
|
56
|
-
when :RFCTYPE_TIME
|
57
|
-
# TODO: See whether we can optimize this
|
58
|
-
timec = read_chars(metadata)
|
59
|
-
return Time.parse("#{timec[0..1]}:#{timec[2..3]}:#{timec[4..5]}")
|
60
|
-
|
61
|
-
when :RFCTYPE_BYTE
|
62
|
-
size = metadata[:ucLength]
|
63
|
-
buf = FFI::MemoryPointer.new(:uchar, size)
|
64
|
-
rc = NWRFCLib.get_bytes(@handle, metadata[:name].cU, buf, size, @error.to_ptr)
|
65
|
-
NWRFC.check_error(@error) if rc > 0
|
66
|
-
return buf.get_bytes(0, size)
|
67
|
-
|
68
|
-
when :RFCTYPE_TABLE
|
69
|
-
# TODO Cache instances of table members and return those where available
|
70
|
-
new_handle = NWRFCLib::RFCDataContainer.new
|
71
|
-
rc = NWRFCLib.get_table(@handle, member.cU, new_handle.to_ptr, @error.to_ptr)
|
72
|
-
NWRFC.check_error(@error) if rc > 0
|
73
|
-
# CAVEAT: Other calls using the handle require "handle" field
|
74
|
-
# of the RFC_DATA_CONTAINER struct for some reason.
|
75
|
-
new_handle = new_handle[:handle]
|
76
|
-
return Table.new(new_handle)
|
77
|
-
|
78
|
-
when :RFCTYPE_NUM
|
79
|
-
return read_chars(metadata)
|
80
|
-
|
81
|
-
when :RFCTYPE_FLOAT
|
82
|
-
double = FFI::MemoryPointer.new :double
|
83
|
-
rc = NWRFCLib.get_float(@handle, member.cU, double, @error)
|
84
|
-
NWRFC.check_error(@error) if rc > 0
|
85
|
-
return double.get_double(0)
|
86
|
-
|
87
|
-
when :RFCTYPE_INT
|
88
|
-
int = FFI::MemoryPointer.new :int
|
89
|
-
rc = NWRFCLib.get_int(@handle, member.cU, int, @error)
|
90
|
-
NWRFC.check_error(@error) if rc > 0
|
91
|
-
return int.get_int(0)
|
92
|
-
|
93
|
-
when :RFCTYPE_INT2
|
94
|
-
short = FFI::MemoryPointer.new :short
|
95
|
-
rc = NWRFCLib.get_int2(@handle, member.cU, short, @error)
|
96
|
-
NWRFC.check_error(@error) if rc > 0
|
97
|
-
return short.get_short(0)
|
98
|
-
|
99
|
-
when :RFCTYPE_INT1
|
100
|
-
int1 = FFI::MemoryPointer.new :uint8
|
101
|
-
rc = NWRFCLib.get_int1(@handle, member.cU, int1, @error)
|
102
|
-
NWRFC.check_error(@error) if rc > 0
|
103
|
-
return int1.get_uint8(0)
|
104
|
-
|
105
|
-
when :RFCTYPE_NULL
|
106
|
-
raise "Unsupported type RFCTYPE_NULL" #You should never run into this
|
107
|
-
|
108
|
-
when :RFCTYPE_STRUCTURE
|
109
|
-
# TODO Cache instances of structure members and return those where available
|
110
|
-
new_handle = NWRFCLib::RFCDataContainer.new
|
111
|
-
rc = NWRFCLib.get_structure(@handle, member.cU, new_handle.to_ptr, @error.to_ptr)
|
112
|
-
NWRFC.check_error(@error) if rc > 0
|
113
|
-
new_handle = new_handle[:handle]
|
114
|
-
return Structure.new(new_handle)
|
115
|
-
|
116
|
-
when :RFCTYPE_DECF16
|
117
|
-
double = FFI::MemoryPointer.new :double
|
118
|
-
rc = NWRFCLib.get_dec_f16(@handle, member.cU, double, @error)
|
119
|
-
NWRFC.check_error(@error) if rc > 0
|
120
|
-
return double.get_double(0)
|
121
|
-
|
122
|
-
when :RFCTYPE_DECF34
|
123
|
-
double = FFI::MemoryPointer.new :double, 2
|
124
|
-
rc = NWRFCLib.get_dec_f34(@handle, member.cU, double, @error)
|
125
|
-
NWRFC.check_error(@error) if rc > 0
|
126
|
-
return double.get_double(0)
|
127
|
-
|
128
|
-
when :RFCTYPE_XMLDATA
|
129
|
-
raise "Unsupported type RFCTYPE_XMLDATA (no longer used)" #You should never run into this
|
130
|
-
|
131
|
-
when :RFCTYPE_STRING
|
132
|
-
return read_string(metadata)
|
133
|
-
|
134
|
-
when :RFCTYPE_XSTRING
|
135
|
-
size = FFI::MemoryPointer.new(:uint)
|
136
|
-
rc = NWRFCLib.get_string_length(@handle, metadata[:name].cU, size, @error)
|
137
|
-
NWRFC.check_error(@error) if rc > 0
|
138
|
-
buf_len = size.read_uint
|
139
|
-
sbuf = FFI::MemoryPointer.new :uchar, buf_len
|
140
|
-
rc = NWRFCLib.get_x_string(@handle, metadata[:name].cU, sbuf, buf_len, size, @error)
|
141
|
-
NWRFC.check_error(@error) if rc > 0
|
142
|
-
return sbuf.read_string(sbuf.size)
|
143
|
-
|
144
|
-
else
|
145
|
-
raise "Illegal member type #{metadata[:type]}"
|
146
|
-
end
|
147
|
-
|
148
|
-
end
|
149
|
-
|
150
|
-
#--
|
151
|
-
# VALUE STORAGE
|
152
|
-
#++
|
153
|
-
|
154
|
-
# Set value on a data container (structure, function instance or table)
|
155
|
-
def []=(element, value)
|
156
|
-
member = element.to_s.upcase
|
157
|
-
metadata = member_metadata(element)
|
158
|
-
case metadata[:type]
|
159
|
-
|
160
|
-
when :RFCTYPE_CHAR
|
161
|
-
value = value.to_s
|
162
|
-
NWRFCLib.set_chars(@handle, member.cU, value.cU, value.length, @error.to_ptr)
|
163
|
-
|
164
|
-
when :RFCTYPE_DATE
|
165
|
-
value = value_to_date(value)
|
166
|
-
NWRFCLib.set_date(@handle, member.cU, value.cU, @error.to_ptr)
|
167
|
-
|
168
|
-
when :RFCTYPE_BCD
|
169
|
-
stval = value.to_s.cU
|
170
|
-
m = FFI::MemoryPointer.from_string stval
|
171
|
-
NWRFCLib.set_string(@handle, member.cU, m, value.to_s.size, @error)
|
172
|
-
|
173
|
-
when :RFCTYPE_TIME
|
174
|
-
value = value_to_time(value)
|
175
|
-
NWRFCLib.set_time(@handle, member.cU, value.cU, @error.to_ptr)
|
176
|
-
|
177
|
-
when :RFCTYPE_BYTE
|
178
|
-
m = FFI::MemoryPointer.from_string value.to_s
|
179
|
-
NWRFCLib.set_bytes(@handle, member.cU, m, value.to_s.size, @error.to_ptr)
|
180
|
-
|
181
|
-
when :RFCTYPE_TABLE
|
182
|
-
raise "Value must be of type table" unless value.class == NWRFC::Table
|
183
|
-
NWRFCLib.set_table(@handle, member.cU, value.handle, @error)
|
184
|
-
|
185
|
-
when :RFCTYPE_NUM
|
186
|
-
value = value.to_s
|
187
|
-
NWRFCLib.set_num(@handle, member.cU, value.cU, value.length, @error.to_ptr)
|
188
|
-
|
189
|
-
when :RFCTYPE_FLOAT
|
190
|
-
NWRFCLib.set_float(@handle, member.cU, value.to_f, @error.to_ptr)
|
191
|
-
|
192
|
-
when :RFCTYPE_INT
|
193
|
-
NWRFCLib.set_int(@handle, member.cU, value.to_i, @error.to_ptr)
|
194
|
-
|
195
|
-
when :RFCTYPE_INT2
|
196
|
-
NWRFCLib.set_int2(@handle, member.cU, value.to_i, @error.to_ptr)
|
197
|
-
|
198
|
-
when :RFCTYPE_INT1
|
199
|
-
NWRFCLib.set_int1(@handle, member.cU, value.to_i, @error.to_ptr)
|
200
|
-
|
201
|
-
when :RFCTYPE_NULL
|
202
|
-
raise "Unsupported type RFCTYPE_NULL" #You should never run into this
|
203
|
-
|
204
|
-
when :RFCTYPE_STRUCTURE
|
205
|
-
raise "Value must be of type table" unless value.class == NWRFC::Structure
|
206
|
-
NWRFCLib.set_structure(@handle, member.cU, value.handle, @error)
|
207
|
-
|
208
|
-
when :RFCTYPE_DECF16
|
209
|
-
raise "#{@members[:type]}: decfloat16 not supported yet"
|
210
|
-
double = NWRFCLib::RFC_DECF16.new #FFI::MemoryPointer.new :double
|
211
|
-
double[:align] = value.to_f
|
212
|
-
#double.put_double(0, value.to_f)
|
213
|
-
#double = FFI::Pointer.new 4
|
214
|
-
NWRFCLib.set_dec_f16(@handle, member.cU, double.pointer, @error)
|
215
|
-
|
216
|
-
when :RFCTYPE_DECF34
|
217
|
-
raise "#{@members[:type]}: decfloat34 not supported yet"
|
218
|
-
# double = FFI::MemoryPointer.new :double, 2
|
219
|
-
# double.put_double(0, value.to_f)
|
220
|
-
double = NWRFCLib::RFC_DECF34.new #FFI::MemoryPointer.new :double
|
221
|
-
double[:align] = value.to_f
|
222
|
-
NWRFCLib.set_dec_f34(@handle, member.cU, double, @error)
|
223
|
-
|
224
|
-
when :RFCTYPE_XMLDATA
|
225
|
-
raise "Unsupported type RFCTYPE_XMLDATA (no longer used)" #You should never run into this
|
226
|
-
|
227
|
-
when :RFCTYPE_STRING
|
228
|
-
stval = value.cU
|
229
|
-
m = FFI::MemoryPointer.from_string stval
|
230
|
-
NWRFCLib.set_string(@handle, member.cU, m, value.size, @error)
|
231
|
-
|
232
|
-
when :RFCTYPE_XSTRING
|
233
|
-
m = FFI::MemoryPointer.new value.size
|
234
|
-
m.put_bytes 0, value
|
235
|
-
NWRFCLib.set_x_string(@handle, member.cU, m, value.size, @error)
|
236
|
-
|
237
|
-
else
|
238
|
-
raise "Illegal member type #{@members[:type]}"
|
239
|
-
end
|
240
|
-
NWRFC.check_error(@error)
|
241
|
-
end
|
242
|
-
|
243
|
-
# Return value as a SAP-formatted date ("YYYYMMDD"). Force value to fit into 8 chars by
|
244
|
-
# truncating or padding with spaces
|
245
|
-
def value_to_date(value)
|
246
|
-
return value.strftime(NW_DATE_FORMAT) if value.respond_to? :strftime
|
247
|
-
# Force the resulting string into 8 characters otherwise
|
248
|
-
value = value.to_s
|
249
|
-
value << ' ' until value.size == 8 if value.size < 8
|
250
|
-
value = value[0..7] if value.size > 8
|
251
|
-
value
|
252
|
-
end
|
253
|
-
|
254
|
-
# Return value as a SAP-formatted time ("HHMMSS"). Force value to fit into 6 chars by
|
255
|
-
# truncating or padding with spaces
|
256
|
-
def value_to_time(value)
|
257
|
-
return value.strftime(NW_TIME_FORMAT) if value.respond_to? :strftime
|
258
|
-
# Force the resulting string into 6 characters otherwise
|
259
|
-
value = value.to_s
|
260
|
-
value << ' ' until value.size == 6 if value.size < 6
|
261
|
-
value = value[0..6] if value.size > 6
|
262
|
-
value
|
263
|
-
end
|
264
|
-
|
265
|
-
# Return a list (array) of symbols representing the names of the fields (or parameters, in the case of a function)
|
266
|
-
# of this data container
|
267
|
-
def fields
|
268
|
-
fc = FFI::MemoryPointer.new(:uint)
|
269
|
-
rc = NWRFCLib.get_field_count(@desc, fc, @error)
|
270
|
-
NWRFC.check_error(@error) if rc > 0
|
271
|
-
fc = fc.read_uint
|
272
|
-
fd = NWRFCLib::RFCFieldDesc.new
|
273
|
-
# Make a list of field names
|
274
|
-
fc.times.inject([]) {|array, index|
|
275
|
-
rc = NWRFCLib.get_field_desc_by_index(@desc, index, fd.to_ptr, @error.to_ptr)
|
276
|
-
NWRFC.check_error(@error) if rc > 0
|
277
|
-
#@todo WARNING! our get_str method did not handle getting the name of the RESPTEXT parameter in STFC_DEEP_TABLE correctly
|
278
|
-
# As a workaround, we use our read_string_dn method; do we need to use this elsewhere?
|
279
|
-
#array << fd[:name].get_str.to_sym #<-The code with good intentions
|
280
|
-
array << fd[:name].to_ptr.read_string_dn.uC.to_sym #<- Workaround; the way of the future?
|
281
|
-
}
|
282
|
-
end
|
283
|
-
|
284
|
-
# Get the metadata of a member (function, structure or table)
|
285
|
-
def member_metadata(member_name)
|
286
|
-
# TODO: Cache metadata definitions; will it be quicker than making a hash of metadata for a given member each time?
|
287
|
-
member = member_name.to_s.upcase
|
288
|
-
if self.class == NWRFC::FunctionCall
|
289
|
-
fpar = NWRFCLib::RFCFuncParam.new
|
290
|
-
rc = NWRFCLib.get_parameter_desc_by_name(@desc, member.cU, fpar.to_ptr, @error.to_ptr)
|
291
|
-
NWRFC.check_error(@error) if rc > 0
|
292
|
-
member_to_hash(fpar)
|
293
|
-
elsif self.class == NWRFC::Table || self.class == NWRFC::Structure
|
294
|
-
fd = NWRFCLib::RFCFieldDesc.new
|
295
|
-
rc = NWRFCLib.get_field_desc_by_name(@desc, member.cU, fd.to_ptr, @error.to_ptr)
|
296
|
-
NWRFC.check_error(@error) if rc > 0
|
297
|
-
member_to_hash(fd)
|
298
|
-
end
|
299
|
-
end
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
private
|
304
|
-
# Returns the subset of metadata values common to both a function parameter
|
305
|
-
# and a type field
|
306
|
-
def member_to_hash(member)
|
307
|
-
{
|
308
|
-
:name => member[:name].get_str,
|
309
|
-
:type => NWRFCLib::RFC_TYPE[member[:type]],
|
310
|
-
:nucLength => member[:nucLength],
|
311
|
-
:ucLength => member[:ucLength],
|
312
|
-
:decimals => member[:decimals],
|
313
|
-
:typeDescHandle => member[:typeDescHandle]
|
314
|
-
}
|
315
|
-
end
|
316
|
-
|
317
|
-
def read_chars(metadata)
|
318
|
-
size = metadata[:ucLength]
|
319
|
-
cb = FFI::MemoryPointer.new :char, size
|
320
|
-
rc = NWRFCLib.get_chars(@handle, metadata[:name].cU, cb, metadata[:nucLength], @error.to_ptr)
|
321
|
-
NWRFC.check_error(@error) if rc > 0
|
322
|
-
cb.read_string(size).uC
|
323
|
-
end
|
324
|
-
|
325
|
-
def read_string(metadata)
|
326
|
-
size = FFI::MemoryPointer.new(:uint)
|
327
|
-
rc = NWRFCLib.get_string_length(@handle, metadata[:name].cU, size, @error)
|
328
|
-
NWRFC.check_error(@error) if rc > 0
|
329
|
-
buf_len = size.read_uint + 1
|
330
|
-
sbuf = FFI::MemoryPointer.new :char, buf_len * NWRFCLib::B_SIZE
|
331
|
-
rc = NWRFCLib.get_string(@handle, metadata[:name].cU, sbuf, buf_len, size, @error)
|
332
|
-
NWRFC.check_error(@error) if rc > 0
|
333
|
-
sbuf.read_string(sbuf.size).uC
|
334
|
-
end
|
335
|
-
|
336
|
-
end
|
337
|
-
|
1
|
+
module NWRFC
|
2
|
+
|
3
|
+
# Representation of a data container (function, structure or table)
|
4
|
+
# Implements common functions for data containers, such as setting and getting values, tables, structures and
|
5
|
+
# takes care of type conversion and calling correct SDK functions to set or get values
|
6
|
+
#
|
7
|
+
# == Type Conversions
|
8
|
+
# To ensure that data is passed correctly to the NW RFC SDK functions, certain conversions are applied to values
|
9
|
+
# passed, depending on the type of the field. ABAP supports a number of elementary types, which are listed in the
|
10
|
+
#
|
11
|
+
# DECFLOAT16 and DECFLOAT34 types are not yet supported.
|
12
|
+
#
|
13
|
+
# === Inbound
|
14
|
+
# For character and string
|
15
|
+
class DataContainer
|
16
|
+
attr_reader :handle, :desc
|
17
|
+
|
18
|
+
def initialize(handle)
|
19
|
+
@error = NWRFCLib::RFCError.new
|
20
|
+
@handle = handle
|
21
|
+
@desc = NWRFCLib.describe_type(@handle, @error)
|
22
|
+
@member_metadata = {} #Cache of metadata for members
|
23
|
+
NWRFC.check_error(@error)
|
24
|
+
end
|
25
|
+
|
26
|
+
#--
|
27
|
+
# VALUE RETRIEVAL
|
28
|
+
#++
|
29
|
+
|
30
|
+
# Get value from a data container (structure, function instance or table)
|
31
|
+
def [](element)
|
32
|
+
member = element.to_s.upcase
|
33
|
+
metadata = member_metadata(element)
|
34
|
+
case metadata[:type]
|
35
|
+
|
36
|
+
when :RFCTYPE_CHAR
|
37
|
+
# TODO: Try use :string parameter in get_chars
|
38
|
+
return read_chars(metadata)
|
39
|
+
|
40
|
+
when :RFCTYPE_DATE
|
41
|
+
return Date.parse(read_chars(metadata))
|
42
|
+
#return Date.new(date[0..3].to_i, date[4..5].to_i, date[6..7].to_i)
|
43
|
+
|
44
|
+
when :RFCTYPE_BCD
|
45
|
+
size = metadata[:nucLength] + (metadata[:decimals] || 0)
|
46
|
+
buf = FFI::MemoryPointer.new(:uchar, size*2)
|
47
|
+
rc = NWRFCLib.get_chars(@handle, metadata[:name].cU, buf, size, @error.to_ptr)
|
48
|
+
NWRFC.check_error(@error) if rc > 0
|
49
|
+
return buf.get_bytes(0, size*2).uC.to_f
|
50
|
+
#size = metadata[:ucLength]
|
51
|
+
#cb = FFI::MemoryPointer.new :char, size * 2
|
52
|
+
#rc = NWRFCLib.get_chars(@handle, metadata[:name].cU, cb, size * 2, @error.to_ptr)
|
53
|
+
#NWRFC.check_error(@error) if rc > 0
|
54
|
+
#cb.read_string(size).uC
|
55
|
+
|
56
|
+
when :RFCTYPE_TIME
|
57
|
+
# TODO: See whether we can optimize this
|
58
|
+
timec = read_chars(metadata)
|
59
|
+
return Time.parse("#{timec[0..1]}:#{timec[2..3]}:#{timec[4..5]}")
|
60
|
+
|
61
|
+
when :RFCTYPE_BYTE
|
62
|
+
size = metadata[:ucLength]
|
63
|
+
buf = FFI::MemoryPointer.new(:uchar, size)
|
64
|
+
rc = NWRFCLib.get_bytes(@handle, metadata[:name].cU, buf, size, @error.to_ptr)
|
65
|
+
NWRFC.check_error(@error) if rc > 0
|
66
|
+
return buf.get_bytes(0, size)
|
67
|
+
|
68
|
+
when :RFCTYPE_TABLE
|
69
|
+
# TODO Cache instances of table members and return those where available
|
70
|
+
new_handle = NWRFCLib::RFCDataContainer.new
|
71
|
+
rc = NWRFCLib.get_table(@handle, member.cU, new_handle.to_ptr, @error.to_ptr)
|
72
|
+
NWRFC.check_error(@error) if rc > 0
|
73
|
+
# CAVEAT: Other calls using the handle require "handle" field
|
74
|
+
# of the RFC_DATA_CONTAINER struct for some reason.
|
75
|
+
new_handle = new_handle[:handle]
|
76
|
+
return Table.new(new_handle)
|
77
|
+
|
78
|
+
when :RFCTYPE_NUM
|
79
|
+
return read_chars(metadata)
|
80
|
+
|
81
|
+
when :RFCTYPE_FLOAT
|
82
|
+
double = FFI::MemoryPointer.new :double
|
83
|
+
rc = NWRFCLib.get_float(@handle, member.cU, double, @error)
|
84
|
+
NWRFC.check_error(@error) if rc > 0
|
85
|
+
return double.get_double(0)
|
86
|
+
|
87
|
+
when :RFCTYPE_INT
|
88
|
+
int = FFI::MemoryPointer.new :int
|
89
|
+
rc = NWRFCLib.get_int(@handle, member.cU, int, @error)
|
90
|
+
NWRFC.check_error(@error) if rc > 0
|
91
|
+
return int.get_int(0)
|
92
|
+
|
93
|
+
when :RFCTYPE_INT2
|
94
|
+
short = FFI::MemoryPointer.new :short
|
95
|
+
rc = NWRFCLib.get_int2(@handle, member.cU, short, @error)
|
96
|
+
NWRFC.check_error(@error) if rc > 0
|
97
|
+
return short.get_short(0)
|
98
|
+
|
99
|
+
when :RFCTYPE_INT1
|
100
|
+
int1 = FFI::MemoryPointer.new :uint8
|
101
|
+
rc = NWRFCLib.get_int1(@handle, member.cU, int1, @error)
|
102
|
+
NWRFC.check_error(@error) if rc > 0
|
103
|
+
return int1.get_uint8(0)
|
104
|
+
|
105
|
+
when :RFCTYPE_NULL
|
106
|
+
raise "Unsupported type RFCTYPE_NULL" #You should never run into this
|
107
|
+
|
108
|
+
when :RFCTYPE_STRUCTURE
|
109
|
+
# TODO Cache instances of structure members and return those where available
|
110
|
+
new_handle = NWRFCLib::RFCDataContainer.new
|
111
|
+
rc = NWRFCLib.get_structure(@handle, member.cU, new_handle.to_ptr, @error.to_ptr)
|
112
|
+
NWRFC.check_error(@error) if rc > 0
|
113
|
+
new_handle = new_handle[:handle]
|
114
|
+
return Structure.new(new_handle)
|
115
|
+
|
116
|
+
when :RFCTYPE_DECF16
|
117
|
+
double = FFI::MemoryPointer.new :double
|
118
|
+
rc = NWRFCLib.get_dec_f16(@handle, member.cU, double, @error)
|
119
|
+
NWRFC.check_error(@error) if rc > 0
|
120
|
+
return double.get_double(0)
|
121
|
+
|
122
|
+
when :RFCTYPE_DECF34
|
123
|
+
double = FFI::MemoryPointer.new :double, 2
|
124
|
+
rc = NWRFCLib.get_dec_f34(@handle, member.cU, double, @error)
|
125
|
+
NWRFC.check_error(@error) if rc > 0
|
126
|
+
return double.get_double(0)
|
127
|
+
|
128
|
+
when :RFCTYPE_XMLDATA
|
129
|
+
raise "Unsupported type RFCTYPE_XMLDATA (no longer used)" #You should never run into this
|
130
|
+
|
131
|
+
when :RFCTYPE_STRING
|
132
|
+
return read_string(metadata)
|
133
|
+
|
134
|
+
when :RFCTYPE_XSTRING
|
135
|
+
size = FFI::MemoryPointer.new(:uint)
|
136
|
+
rc = NWRFCLib.get_string_length(@handle, metadata[:name].cU, size, @error)
|
137
|
+
NWRFC.check_error(@error) if rc > 0
|
138
|
+
buf_len = size.read_uint
|
139
|
+
sbuf = FFI::MemoryPointer.new :uchar, buf_len
|
140
|
+
rc = NWRFCLib.get_x_string(@handle, metadata[:name].cU, sbuf, buf_len, size, @error)
|
141
|
+
NWRFC.check_error(@error) if rc > 0
|
142
|
+
return sbuf.read_string(sbuf.size)
|
143
|
+
|
144
|
+
else
|
145
|
+
raise "Illegal member type #{metadata[:type]}"
|
146
|
+
end
|
147
|
+
|
148
|
+
end
|
149
|
+
|
150
|
+
#--
|
151
|
+
# VALUE STORAGE
|
152
|
+
#++
|
153
|
+
|
154
|
+
# Set value on a data container (structure, function instance or table)
|
155
|
+
def []=(element, value)
|
156
|
+
member = element.to_s.upcase
|
157
|
+
metadata = member_metadata(element)
|
158
|
+
case metadata[:type]
|
159
|
+
|
160
|
+
when :RFCTYPE_CHAR
|
161
|
+
value = value.to_s
|
162
|
+
NWRFCLib.set_chars(@handle, member.cU, value.cU, value.length, @error.to_ptr)
|
163
|
+
|
164
|
+
when :RFCTYPE_DATE
|
165
|
+
value = value_to_date(value)
|
166
|
+
NWRFCLib.set_date(@handle, member.cU, value.cU, @error.to_ptr)
|
167
|
+
|
168
|
+
when :RFCTYPE_BCD
|
169
|
+
stval = value.to_s.cU
|
170
|
+
m = FFI::MemoryPointer.from_string stval
|
171
|
+
NWRFCLib.set_string(@handle, member.cU, m, value.to_s.size, @error)
|
172
|
+
|
173
|
+
when :RFCTYPE_TIME
|
174
|
+
value = value_to_time(value)
|
175
|
+
NWRFCLib.set_time(@handle, member.cU, value.cU, @error.to_ptr)
|
176
|
+
|
177
|
+
when :RFCTYPE_BYTE
|
178
|
+
m = FFI::MemoryPointer.from_string value.to_s
|
179
|
+
NWRFCLib.set_bytes(@handle, member.cU, m, value.to_s.size, @error.to_ptr)
|
180
|
+
|
181
|
+
when :RFCTYPE_TABLE
|
182
|
+
raise "Value must be of type table" unless value.class == NWRFC::Table
|
183
|
+
NWRFCLib.set_table(@handle, member.cU, value.handle, @error)
|
184
|
+
|
185
|
+
when :RFCTYPE_NUM
|
186
|
+
value = value.to_s
|
187
|
+
NWRFCLib.set_num(@handle, member.cU, value.cU, value.length, @error.to_ptr)
|
188
|
+
|
189
|
+
when :RFCTYPE_FLOAT
|
190
|
+
NWRFCLib.set_float(@handle, member.cU, value.to_f, @error.to_ptr)
|
191
|
+
|
192
|
+
when :RFCTYPE_INT
|
193
|
+
NWRFCLib.set_int(@handle, member.cU, value.to_i, @error.to_ptr)
|
194
|
+
|
195
|
+
when :RFCTYPE_INT2
|
196
|
+
NWRFCLib.set_int2(@handle, member.cU, value.to_i, @error.to_ptr)
|
197
|
+
|
198
|
+
when :RFCTYPE_INT1
|
199
|
+
NWRFCLib.set_int1(@handle, member.cU, value.to_i, @error.to_ptr)
|
200
|
+
|
201
|
+
when :RFCTYPE_NULL
|
202
|
+
raise "Unsupported type RFCTYPE_NULL" #You should never run into this
|
203
|
+
|
204
|
+
when :RFCTYPE_STRUCTURE
|
205
|
+
raise "Value must be of type table" unless value.class == NWRFC::Structure
|
206
|
+
NWRFCLib.set_structure(@handle, member.cU, value.handle, @error)
|
207
|
+
|
208
|
+
when :RFCTYPE_DECF16
|
209
|
+
raise "#{@members[:type]}: decfloat16 not supported yet"
|
210
|
+
double = NWRFCLib::RFC_DECF16.new #FFI::MemoryPointer.new :double
|
211
|
+
double[:align] = value.to_f
|
212
|
+
#double.put_double(0, value.to_f)
|
213
|
+
#double = FFI::Pointer.new 4
|
214
|
+
NWRFCLib.set_dec_f16(@handle, member.cU, double.pointer, @error)
|
215
|
+
|
216
|
+
when :RFCTYPE_DECF34
|
217
|
+
raise "#{@members[:type]}: decfloat34 not supported yet"
|
218
|
+
# double = FFI::MemoryPointer.new :double, 2
|
219
|
+
# double.put_double(0, value.to_f)
|
220
|
+
double = NWRFCLib::RFC_DECF34.new #FFI::MemoryPointer.new :double
|
221
|
+
double[:align] = value.to_f
|
222
|
+
NWRFCLib.set_dec_f34(@handle, member.cU, double, @error)
|
223
|
+
|
224
|
+
when :RFCTYPE_XMLDATA
|
225
|
+
raise "Unsupported type RFCTYPE_XMLDATA (no longer used)" #You should never run into this
|
226
|
+
|
227
|
+
when :RFCTYPE_STRING
|
228
|
+
stval = value.cU
|
229
|
+
m = FFI::MemoryPointer.from_string stval
|
230
|
+
NWRFCLib.set_string(@handle, member.cU, m, value.size, @error)
|
231
|
+
|
232
|
+
when :RFCTYPE_XSTRING
|
233
|
+
m = FFI::MemoryPointer.new value.size
|
234
|
+
m.put_bytes 0, value
|
235
|
+
NWRFCLib.set_x_string(@handle, member.cU, m, value.size, @error)
|
236
|
+
|
237
|
+
else
|
238
|
+
raise "Illegal member type #{@members[:type]}"
|
239
|
+
end
|
240
|
+
NWRFC.check_error(@error)
|
241
|
+
end
|
242
|
+
|
243
|
+
# Return value as a SAP-formatted date ("YYYYMMDD"). Force value to fit into 8 chars by
|
244
|
+
# truncating or padding with spaces
|
245
|
+
def value_to_date(value)
|
246
|
+
return value.strftime(NW_DATE_FORMAT) if value.respond_to? :strftime
|
247
|
+
# Force the resulting string into 8 characters otherwise
|
248
|
+
value = value.to_s
|
249
|
+
value << ' ' until value.size == 8 if value.size < 8
|
250
|
+
value = value[0..7] if value.size > 8
|
251
|
+
value
|
252
|
+
end
|
253
|
+
|
254
|
+
# Return value as a SAP-formatted time ("HHMMSS"). Force value to fit into 6 chars by
|
255
|
+
# truncating or padding with spaces
|
256
|
+
def value_to_time(value)
|
257
|
+
return value.strftime(NW_TIME_FORMAT) if value.respond_to? :strftime
|
258
|
+
# Force the resulting string into 6 characters otherwise
|
259
|
+
value = value.to_s
|
260
|
+
value << ' ' until value.size == 6 if value.size < 6
|
261
|
+
value = value[0..6] if value.size > 6
|
262
|
+
value
|
263
|
+
end
|
264
|
+
|
265
|
+
# Return a list (array) of symbols representing the names of the fields (or parameters, in the case of a function)
|
266
|
+
# of this data container
|
267
|
+
def fields
|
268
|
+
fc = FFI::MemoryPointer.new(:uint)
|
269
|
+
rc = NWRFCLib.get_field_count(@desc, fc, @error)
|
270
|
+
NWRFC.check_error(@error) if rc > 0
|
271
|
+
fc = fc.read_uint
|
272
|
+
fd = NWRFCLib::RFCFieldDesc.new
|
273
|
+
# Make a list of field names
|
274
|
+
fc.times.inject([]) {|array, index|
|
275
|
+
rc = NWRFCLib.get_field_desc_by_index(@desc, index, fd.to_ptr, @error.to_ptr)
|
276
|
+
NWRFC.check_error(@error) if rc > 0
|
277
|
+
#@todo WARNING! our get_str method did not handle getting the name of the RESPTEXT parameter in STFC_DEEP_TABLE correctly
|
278
|
+
# As a workaround, we use our read_string_dn method; do we need to use this elsewhere?
|
279
|
+
#array << fd[:name].get_str.to_sym #<-The code with good intentions
|
280
|
+
array << fd[:name].to_ptr.read_string_dn.uC.to_sym #<- Workaround; the way of the future?
|
281
|
+
}
|
282
|
+
end
|
283
|
+
|
284
|
+
# Get the metadata of a member (function, structure or table)
|
285
|
+
def member_metadata(member_name)
|
286
|
+
# TODO: Cache metadata definitions; will it be quicker than making a hash of metadata for a given member each time?
|
287
|
+
member = member_name.to_s.upcase
|
288
|
+
if self.class == NWRFC::FunctionCall
|
289
|
+
fpar = NWRFCLib::RFCFuncParam.new
|
290
|
+
rc = NWRFCLib.get_parameter_desc_by_name(@desc, member.cU, fpar.to_ptr, @error.to_ptr)
|
291
|
+
NWRFC.check_error(@error) if rc > 0
|
292
|
+
member_to_hash(fpar)
|
293
|
+
elsif self.class == NWRFC::Table || self.class == NWRFC::Structure
|
294
|
+
fd = NWRFCLib::RFCFieldDesc.new
|
295
|
+
rc = NWRFCLib.get_field_desc_by_name(@desc, member.cU, fd.to_ptr, @error.to_ptr)
|
296
|
+
NWRFC.check_error(@error) if rc > 0
|
297
|
+
member_to_hash(fd)
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
301
|
+
|
302
|
+
|
303
|
+
private
|
304
|
+
# Returns the subset of metadata values common to both a function parameter
|
305
|
+
# and a type field
|
306
|
+
def member_to_hash(member)
|
307
|
+
{
|
308
|
+
:name => member[:name].get_str,
|
309
|
+
:type => NWRFCLib::RFC_TYPE[member[:type]],
|
310
|
+
:nucLength => member[:nucLength],
|
311
|
+
:ucLength => member[:ucLength],
|
312
|
+
:decimals => member[:decimals],
|
313
|
+
:typeDescHandle => member[:typeDescHandle]
|
314
|
+
}
|
315
|
+
end
|
316
|
+
|
317
|
+
def read_chars(metadata)
|
318
|
+
size = metadata[:ucLength]
|
319
|
+
cb = FFI::MemoryPointer.new :char, size
|
320
|
+
rc = NWRFCLib.get_chars(@handle, metadata[:name].cU, cb, metadata[:nucLength], @error.to_ptr)
|
321
|
+
NWRFC.check_error(@error) if rc > 0
|
322
|
+
cb.read_string(size).uC
|
323
|
+
end
|
324
|
+
|
325
|
+
def read_string(metadata)
|
326
|
+
size = FFI::MemoryPointer.new(:uint)
|
327
|
+
rc = NWRFCLib.get_string_length(@handle, metadata[:name].cU, size, @error)
|
328
|
+
NWRFC.check_error(@error) if rc > 0
|
329
|
+
buf_len = size.read_uint + 1
|
330
|
+
sbuf = FFI::MemoryPointer.new :char, buf_len * NWRFCLib::B_SIZE
|
331
|
+
rc = NWRFCLib.get_string(@handle, metadata[:name].cU, sbuf, buf_len, size, @error)
|
332
|
+
NWRFC.check_error(@error) if rc > 0
|
333
|
+
sbuf.read_string(sbuf.size).uC
|
334
|
+
end
|
335
|
+
|
336
|
+
end
|
337
|
+
|
338
338
|
end
|