portal-ruby 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/README ADDED
@@ -0,0 +1,34 @@
1
+ Portal-Ruby: Ruby bindings for Portal's Infranet
2
+ by Ray Capozzi
3
+
4
+
5
+ == DESCRIPTION:
6
+
7
+ portal-ruby enables Ruby programs to communicate with Portal's Infranet.
8
+
9
+ You can view http://portal-ruby.rubyforge.org for more information.
10
+
11
+
12
+ == SYNOPSIS:
13
+
14
+ require 'portal'
15
+
16
+ portal = Portal::Connection.new
17
+ portal.loopback
18
+ portal.xop(:PCM_OP_CUST_DELETE_ACCT,:PIN_FLD_POID => "0.0.0.1 /account 11")
19
+
20
+ This creates a connection to Portal using a pin.conf and deletes an account.
21
+
22
+
23
+ == REQUIREMENTS:
24
+
25
+ You need portal.[so|dll] to run.
26
+
27
+
28
+ == INSTALL
29
+
30
+ You need include files to build.
31
+ Under non-win32, the setup.rb should be enough. I'm still trying to understand
32
+ how one explains configuring VS. Perhaps I'll release win32 builds.
33
+
34
+
@@ -0,0 +1,115 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/clean'
4
+ require 'rake/gempackagetask'
5
+ require 'rake/rdoctask'
6
+ require 'fileutils'
7
+ require 'rubyforge'
8
+
9
+ include FileUtils
10
+
11
+ PKG_NAME = "portal-ruby"
12
+ SVN_HOME = "file:///c:/svn/local/portal-ruby"
13
+ RELEASE_DIR = "release"
14
+
15
+ def get_version
16
+ ENV['version'] or "0.0.1"
17
+ # ENV['version'] or abort "Must supply VERSION=x.y.z"
18
+ end
19
+
20
+ rdoc_template = ENV['template'] || "allison.rb"
21
+ #rdoc_template = "jamis.rb"
22
+
23
+ # Define the files to get doc-ed
24
+ Rake::RDocTask.new do |rdoc|
25
+ rdoc.template = rdoc_template
26
+ rdoc.rdoc_dir = "doc/rdoc"
27
+ rdoc.options << '--line-numbers' << "--tab-width=2" << "--quiet"
28
+ rdoc.options << "--inline-source" if rdoc_template =~ /allison/
29
+ rdoc.rdoc_files.add(['README', 'lib/**/*.rb', 'doc/**/*.rdoc', 'ext/portalext.c'])
30
+ end
31
+
32
+ task :package => [:clean,:compile,:test,:rerdoc]
33
+
34
+ desc "Create the static web pages"
35
+ task :webgen do
36
+ sh %{pushd doc/site; webgen; popd }
37
+ end
38
+
39
+ # Remote Site Section
40
+
41
+ desc "Push static files"
42
+ #task :site_webgen => [:webgen] do
43
+ task :site_webgen do
44
+ sh %{rsync -e 'ssh -1' -azv doc/site/output/* rubyforge.org:/var/www/gforge-projects/portal-ruby/}
45
+ end
46
+
47
+ task :site_rdoc do
48
+ sh %{ rsync -e 'ssh -1' -azv doc/rdoc/* rubyforge.org:/var/www/gforge-projects/portal-ruby/rdoc/ }
49
+ end
50
+
51
+ gem_spec = Gem::Specification.new do |spec|
52
+ test_files = Dir.glob("test/**/*.rb") - Dir.glob("test/**/*local*")
53
+
54
+ spec.name = PKG_NAME
55
+ spec.version = get_version
56
+ spec.summary = "Binding for Portal's Infranet and Oracle Telco Billing"
57
+ spec.description = spec.summary
58
+ spec.platform = Gem::Platform::RUBY
59
+ spec.has_rdoc = true
60
+ spec.extra_rdoc_files = [ "README" ]
61
+ spec.test_files = test_files
62
+
63
+ all_files = %w(README Rakefile) +
64
+ # Dir.glob("doc/rdoc/**/*") +
65
+ test_files +
66
+ Dir.glob("ext/**/*.{h,c,rb}") +
67
+ Dir.glob("{lib}/**/*.rb")
68
+ spec.files = all_files.to_a.delete_if {|f| f.include?('.svn')}
69
+
70
+ spec.require_path = "lib"
71
+ spec.extensions = FileList["ext/**/extconf.rb"].to_a
72
+
73
+ spec.required_ruby_version = '>= 1.8.5'
74
+
75
+ if RUBY_PLATFORM =~ /mswin/
76
+ # spec.files += ['Release/portalext.so']
77
+ spec.extensions.clear
78
+ spec.platform = Gem::Platform::WIN32
79
+ end
80
+
81
+ spec.author = "Raymond Capozzi"
82
+ spec.email = "rcapozzi+ruby@gmail.com"
83
+ spec.homepage = "portal-ruby.rubyforge.com"
84
+ spec.rubyforge_project = "portal-ruby"
85
+ end
86
+
87
+ Rake::GemPackageTask.new(gem_spec) do |pkg|
88
+ pkg.gem_spec = gem_spec
89
+ #pkg.need_tar = true if RUBY_PLATFORM !~ /mswin/
90
+ end
91
+
92
+ desc "Release from source control"
93
+ task :export do
94
+ rm_rf RELEASE_DIR
95
+ sh %{ svn export #{SVN_HOME} #{RELEASE_DIR} }
96
+ puts "Now cd #{RELEASE_DIR} && rake gem version=x.y.z"
97
+ end
98
+
99
+ desc "Release this turd to rubyforge"
100
+ task :release => [:gem] do |t|
101
+ rf = RubyForge.new
102
+ puts "Logging in"
103
+ rf.login
104
+
105
+ c = rf.userconfig
106
+ c["release_notes"] = description if description
107
+ c["release_changes"] = changes if changes
108
+ c["preformatted"] = true
109
+
110
+ files = ["#{pkg}.gem"].compact
111
+
112
+ puts "Releasing #{name} v. #{version}"
113
+ rf.add_release rubyforge_name, name, version, *files
114
+
115
+ end
@@ -0,0 +1,13 @@
1
+ require 'mkmf'
2
+
3
+ # Create a Makefile for building this extension
4
+ #
5
+ # export PINSDK=$CVSTOP/portal
6
+ # ruby ./extconf.rb --with-portal-lib=$PINSDK/lib --with-portal-include=$PINSDK/include
7
+
8
+ sdk = ENV["PINSDK"] || "/usr/local/portal"
9
+ dir_config("portal", sdk)
10
+ if have_header( "pcm.h" ) and
11
+ have_library( "portal", "pin_log_flist" )
12
+ create_makefile( "portalext" )
13
+ end
@@ -0,0 +1,1098 @@
1
+ /* -*- indent-tabs-mode: nil -*- */
2
+ /*
3
+ * portalext.c
4
+ *
5
+ * $Author: rcapozzi $
6
+ * $Date: $
7
+ *
8
+ * Copyright (C) 2006-2007 Raymond Capozzi
9
+ */
10
+
11
+ #if defined WINDOWS || defined _WIN32 || defined HAVE_WINDOWS_H
12
+ #define WIN32_LEAN_AND_MEAN
13
+ #include <windows.h>
14
+ #endif
15
+
16
+ #include <string.h>
17
+ #include "portalext.h"
18
+ #include "pbo_decimal.h"
19
+ #include "st.h"
20
+ #include "ruby.h"
21
+ #include "util.h"
22
+
23
+ /* Prototype */
24
+ static pin_flist_t * portal_hash_to_flist(VALUE hash);
25
+ static VALUE portal_to_flist_array_i(VALUE pair, VALUE data);
26
+ static int portal_to_flist_i(VALUE key, VALUE val, ConvertData *cd);
27
+
28
+ /* Class visible values */
29
+ VALUE mPortal, cContext, ePortalError;
30
+
31
+ /* Ids and constants */
32
+ static ID id_call;
33
+ static ID id_inspect;
34
+ static ID id_to_f;
35
+ static ID id_to_i;
36
+ static ID id_to_s;
37
+ static ID id_to_sym;
38
+ static ID id_xop;
39
+
40
+ /*
41
+ * Free the
42
+ * Called by ruby as part of the initialization.
43
+ */
44
+ void
45
+ pdata_free(pd)
46
+ PortalData *pd;
47
+ {
48
+ TRACE("Freeing");
49
+ PDataClearErr(pd);
50
+ if (pd->ctxp != NULL){
51
+ PCM_CONTEXT_CLOSE(pd->ctxp,0,&pd->ebuf);
52
+ }
53
+ PIN_FLIST_DESTROY_EX(&(pd->in_flistp), NULL);
54
+ PIN_FLIST_DESTROY_EX(&(pd->out_flistp), NULL);
55
+ }
56
+
57
+ void
58
+ cdata_free(cd)
59
+ ConvertData *cd;
60
+ {
61
+ PIN_FLIST_DESTROY_EX(&(cd->flistp), NULL);
62
+ }
63
+
64
+ /*
65
+ * call-seq:
66
+ * Connection.new -> a naked object
67
+ *
68
+ * Allocate the C data structure that follows this instance around.
69
+ * Called by ruby as part of the initialization.
70
+ * We return a brand new Ruby object.
71
+ */
72
+ static VALUE portal_alloc _((VALUE));
73
+ static VALUE
74
+ portal_alloc(klass)
75
+ VALUE klass;
76
+ {
77
+ VALUE obj;
78
+ PortalData *pd = NULL;
79
+ PDataWrap(klass,obj,pd);
80
+ TRACE_INSPECT("Allocated",obj);
81
+ return obj;
82
+ }
83
+
84
+ /*
85
+ * call-seq:
86
+ * inspectx -> String of debug info
87
+ *
88
+ * Connection.inspectx -> Dumps the associated C structs
89
+ */
90
+ static VALUE
91
+ portal_inspect(self)
92
+ VALUE self;
93
+ {
94
+ char *cname = rb_obj_classname(self);
95
+ size_t len;
96
+ VALUE str;
97
+ unsigned long id = rb_obj_id(self);
98
+ char *format = "#<%s:0X%lx owner_id=0x%lx>";
99
+
100
+ PortalData *pd;
101
+ PDataGet(self,pd);
102
+ TRACE("Inspecting");
103
+
104
+ len = strlen(cname)+6+16;
105
+ // len = strlen(format);
106
+ str = rb_str_new(0, len); /* 6:tags 16:addr */
107
+ snprintf(RSTRING(str)->ptr, len+1, "#<%s:0X%lx>", cname, self);
108
+ RSTRING(str)->len = strlen(RSTRING(str)->ptr);
109
+ if (OBJ_TAINTED(self)) OBJ_TAINT(str);
110
+
111
+ return str;
112
+
113
+ }
114
+
115
+ /*
116
+ * Cast something into a string.
117
+ */
118
+ #if defined WINDOWS || defined _WIN32 || defined HAVE_WINDOWS_H
119
+ static __inline VALUE
120
+ #else
121
+ static VALUE
122
+ #endif
123
+ portal_to_s(obj)
124
+ VALUE obj;
125
+ {
126
+ return rb_obj_as_string(obj);
127
+ return rb_funcall(obj, id_to_s, 0, 0);
128
+ }
129
+
130
+ /*
131
+ * Cast a String or Symbol into a char *.
132
+ */
133
+ #if defined WINDOWS || defined _WIN32 || defined HAVE_WINDOWS_H
134
+ static __inline char*
135
+ #else
136
+ static char*
137
+ #endif
138
+ portal_to_char(str)
139
+ VALUE str;
140
+ {
141
+ VALUE tmp;
142
+ if (TYPE(str) == T_STRING){
143
+ return StringValuePtr(str);
144
+ }
145
+ tmp = rb_funcall(str, id_to_s, 0, 0);
146
+ return StringValuePtr(tmp);
147
+ }
148
+
149
+ /*
150
+ * The Portal field number for a string.
151
+ */
152
+ static VALUE
153
+ portal_field_num(obj,str)
154
+ VALUE obj, str;
155
+ {
156
+ pin_fld_num_t fld_num = 0;
157
+ VALUE value;
158
+
159
+ if (TYPE(str) == T_STRING){
160
+ fld_num = PIN_FIELD_OF_NAME(StringValuePtr(str));
161
+ } else {
162
+ value = portal_to_s(str);
163
+ fld_num = PIN_FIELD_OF_NAME(portal_to_char(value));
164
+ }
165
+
166
+ if (!fld_num){
167
+ rb_raise(ePortalError, "Cannot find field number for %s", StringValuePtr(str));
168
+ }
169
+ return INT2FIX(PIN_GET_NUM_FROM_FLD(fld_num));
170
+ }
171
+
172
+ /*
173
+ * Returns the name for a given field number.
174
+ */
175
+ static VALUE
176
+ portal_field_name(self,num)
177
+ VALUE self, num;
178
+ {
179
+ VALUE tmp = Qundef;
180
+ VALUE name = Qundef;
181
+ const char *fld_name = NULL;
182
+
183
+ tmp = rb_funcall(num, id_to_i, 0, 0);
184
+
185
+ fld_name = pin_name_of_field(FIX2INT(tmp));
186
+ name = rb_str_new2(fld_name);
187
+ return name;
188
+ }
189
+
190
+ /*
191
+ * The Portal field type.
192
+ */
193
+ static VALUE
194
+ portal_field_type(obj, value)
195
+ VALUE obj, value;
196
+ {
197
+ int i = 0;
198
+ i = PIN_FIELD_OF_NAME(portal_to_char(value));
199
+ i = PIN_GET_TYPE_FROM_FLD(i);
200
+ if (!i){
201
+ rb_raise(ePortalError, "Cannot get type for %s",portal_to_char(value));
202
+ }
203
+ return INT2FIX(i);
204
+ }
205
+
206
+ /*
207
+ * TODO: Make robust enough to handle /account 1.
208
+ * Perhaps add: sscanf(portal_to_char(val),"0.0.0.%lld %s %lld",&poid_db,buf,&poid_id0);
209
+ */
210
+ static poid_t *
211
+ portal_poid_from_string(string,ebufp)
212
+ char * string;
213
+ pin_errbuf_t *ebufp;
214
+ {
215
+ // int64 poid_id0,poid_db;
216
+ // static char buf[64];
217
+ poid_t *pdp;
218
+ #if defined WINDOWS || defined _WIN32 || defined HAVE_WINDOWS_H
219
+ pdp = strlen(string) == 0 ? NULL : PIN_POID_FROM_STR(string,NULL,ebufp);
220
+ #else
221
+ pdp = strnlen(string,2) == 0 ? NULL : PIN_POID_FROM_STR(string,NULL,ebufp);
222
+ #endif
223
+ return pdp;
224
+ }
225
+
226
+ /*
227
+ * call-seq:
228
+ * portal_to_flist(hash) => Portal FList
229
+ * An error is kept in a local ebuf untill the end.
230
+ */
231
+ static int
232
+ portal_to_flist_i(VALUE key,VALUE val,ConvertData *cd)
233
+ {
234
+ pin_errbuf_t ebuf;
235
+ pin_fld_num_t fld_num = 0;
236
+ pin_flist_t *ary_flistp, *save_flistp;
237
+ int fld_type = 0;
238
+ int int_value = 0;
239
+ double big_value = 0.0;
240
+ char *fld_name = NULL, *tmp_str = NULL;
241
+ pin_decimal_t *pbo = NULL;
242
+ poid_t *pdp = NULL;
243
+
244
+ if (key == Qundef) {
245
+ return ST_CONTINUE;
246
+ }
247
+ PIN_ERR_CLEAR_ERR(&ebuf);
248
+
249
+ fld_name = portal_to_char(key);
250
+ fld_num = PIN_FIELD_OF_NAME(fld_name);
251
+ if (!fld_num) {
252
+ rb_raise(ePortalError, "Cannot find field number for %s", fld_name);
253
+ }
254
+
255
+ fld_type = PIN_GET_TYPE_FROM_FLD(fld_num);
256
+ if (!fld_type){
257
+ rb_raise(ePortalError, "Cannot get type for %s", fld_name);
258
+ }
259
+
260
+ #ifdef _DEBUG
261
+ tmp_str = TYPE(val) ? "Hash" : portal_to_char(val);
262
+ if (rb_gv_get("$DEBUG"))
263
+ fprintf(stderr," hash2flist name=%s num=%ld type=%ld val=%s\n", fld_name, fld_num, fld_type, tmp_str);
264
+ #endif
265
+
266
+ switch(fld_type){
267
+ case PIN_FLDT_STR:
268
+ PIN_FLIST_FLD_SET(cd->flistp, fld_num, (void *) portal_to_char(val), &ebuf);
269
+ break;
270
+
271
+ case PIN_FLDT_INT:
272
+ case PIN_FLDT_UINT:
273
+ case PIN_FLDT_ENUM:
274
+ case PIN_FLDT_TSTAMP:
275
+ int_value = TO_INT(val);
276
+ PIN_FLIST_FLD_SET(cd->flistp, fld_num, (void *)&int_value, &ebuf);
277
+ break;
278
+
279
+ case PIN_FLDT_NUM:
280
+ case PIN_FLDT_DECIMAL:
281
+ big_value = TO_BIG(val);
282
+ pbo = pbo_decimal_from_double(big_value,&ebuf);
283
+ PIN_FLIST_FLD_SET(cd->flistp, fld_num, (void *)pbo, &ebuf);
284
+
285
+ if (! pbo_decimal_is_null(pbo,&ebuf)) {
286
+ pbo_decimal_destroy(&pbo);
287
+ }
288
+ break;
289
+
290
+ case PIN_FLDT_POID:
291
+ /* Parse 0.0.0.1 /account 1234 1 */
292
+ pdp = portal_poid_from_string(portal_to_char(val), &ebuf);
293
+ PIN_FLIST_FLD_PUT(cd->flistp, fld_num, (void *)pdp, &ebuf);
294
+ break;
295
+
296
+ case PIN_FLDT_ARRAY:
297
+ case PIN_FLDT_SUBSTRUCT:
298
+ Check_Type(val,T_HASH);
299
+ cd->fld_num = fld_num;
300
+ save_flistp = cd->flistp;
301
+ rb_iterate(rb_each, val, portal_to_flist_array_i,(VALUE)cd);
302
+ (cd)->flistp = save_flistp;
303
+ (cd)->fld_num = fld_num;
304
+ ebuf = *cd->ebufp;
305
+ break;
306
+
307
+ case PIN_FLDT_OBJ:
308
+ case PIN_FLDT_BINSTR:
309
+ case PIN_FLDT_ERR:
310
+ default:
311
+ rb_raise(ePortalError, "Type %ld not supported for %s", fld_type, fld_name);
312
+ break;
313
+ } /* End switch */
314
+
315
+ if (PIN_ERR_IS_ERR(&ebuf)) {
316
+ PIN_ERR_LOG_EBUF(PIN_ERR_LEVEL_ERROR, "Hash to flist conversion error", &ebuf);
317
+ rb_raise(ePortalError, "Cannot convert %s", fld_name);
318
+ }
319
+
320
+ return ST_CONTINUE;
321
+ }
322
+
323
+ /*
324
+ * Interates through a nested Hash to create a nested flist.
325
+ * The hash keys must respond to to_i, as that value becomes the REC ID in the array.
326
+ *
327
+ * === Example:
328
+ *
329
+ * hash = {
330
+ * "PIN_FLD_NAME" => "Foo",
331
+ * :PIN_FLD_ARGS => {
332
+ * 1 => { :PIN_FLD_NAME => "Name 0" },
333
+ * 2 => {
334
+ * :PIN_FLD_NAME => "Name 1",
335
+ * :PIN_FLD_CREATED_T => 1,
336
+ * },
337
+ * 3 => {
338
+ * :PIN_FLD_NAME => "Value 2",
339
+ * :PIN_FLD_CREATED_T => 2,
340
+ * },
341
+ * },
342
+ * }
343
+ * PIN_ELEMID_ANY is denoted using a "*" as the key.
344
+ */
345
+ static VALUE
346
+ portal_to_flist_array_i(pair,data)
347
+ VALUE pair, data;
348
+ {
349
+ ConvertData *cd = (ConvertData *)data;
350
+ VALUE key, val;
351
+ pin_flist_t *ary_flistp, *save_flistp;
352
+ int rec_id = 0;
353
+ VALUE tmp_obj;
354
+ pin_fld_num_t fld_num;
355
+
356
+ //CDataGet(data,cd);
357
+ Check_Type(pair,T_ARRAY);
358
+ key = rb_ary_entry(pair, 0);
359
+ val = rb_ary_entry(pair, 1);
360
+ fld_num = cd->fld_num;
361
+
362
+ if (TYPE(key) == T_FIXNUM) {
363
+ rec_id = FIX2INT(key);
364
+ } else {
365
+ if (TYPE(key) == T_STRING && RSTRING(key)->ptr[0] == '*'){
366
+ rec_id = PIN_ELEMID_ANY;
367
+ } else {
368
+ tmp_obj = rb_funcall(key, id_to_i, 0, 0);
369
+ rec_id = FIX2INT(tmp_obj);
370
+ }
371
+ }
372
+
373
+ save_flistp = cd->flistp;
374
+ ary_flistp = PIN_FLIST_ELEM_ADD(cd->flistp, fld_num, rec_id, cd->ebufp);
375
+
376
+ cd->flistp = ary_flistp;
377
+ rb_hash_foreach(val, portal_to_flist_i,cd);
378
+ cd->flistp = save_flistp;
379
+ return ST_CONTINUE;
380
+ }
381
+
382
+ /*
383
+ * Convert a Ruby hash into a Portal flist
384
+ */
385
+ static pin_flist_t *
386
+ portal_hash_to_flist(hash)
387
+ VALUE hash;
388
+ {
389
+ pin_errbuf_t ebuf;
390
+ ConvertData cdata;
391
+
392
+ cdata.flistp = NULL;
393
+ cdata.ebufp = &ebuf;
394
+
395
+ // TODO: rb_thread_critical = Qtrue;
396
+ Check_Type(hash,T_HASH);
397
+ PIN_ERR_CLEAR_ERR(&ebuf);
398
+ cdata.flistp = PIN_FLIST_CREATE(&ebuf);
399
+
400
+ /* Iterate through the hash converting each key/val pair into
401
+ * their Portal equivilent.
402
+ * Not using rb_iterate(rb_each, hash, portal_to_flist_i, hash);
403
+ * because the receiver gets an array of [key,val] which you have to noodle.
404
+ *
405
+ * Using rb_hash_foreach(hash, inter_i, struct);
406
+ * Calls inter_i for each key/val pair in the hash.
407
+ * iter_i has prototype inter_i(key,val,struct).
408
+ * key and val are obvious. struct is some data structure
409
+ * that you use to maintain state between calls to the inter.
410
+ */
411
+ rb_hash_foreach(hash, portal_to_flist_i,&cdata);
412
+
413
+ PIN_ERR_CLEAR_ERR(&ebuf);
414
+ return cdata.flistp;
415
+ }
416
+
417
+ /*
418
+ * Converts Portal Poid to Ruby String. Returns a Ruby String.
419
+ */
420
+ static VALUE
421
+ portal_poid_to_val(pdp)
422
+ poid_t *pdp;
423
+ {
424
+ pin_errbuf_t ebuf;
425
+ int buf_size = PCM_MAX_POID_TYPE + 48;
426
+ char buf[PCM_MAX_POID_TYPE + 48];
427
+ char *bufp = NULL;
428
+ memset(buf,0,sizeof(buf));
429
+ bufp = buf;
430
+ PIN_ERR_CLEAR_ERR(&ebuf);
431
+ PIN_POID_TO_STR((poid_t *)pdp, &bufp, &buf_size, &ebuf);
432
+ return rb_str_new2(bufp);
433
+ }
434
+
435
+ /*
436
+ * Convert an Flist into a hash.
437
+ */
438
+ static VALUE
439
+ portal_flist_to_hash(flistp)
440
+ pin_flist_t *flistp;
441
+ {
442
+ pin_fld_num_t fld_num = 0;
443
+ int buf_size = PCM_MAX_POID_TYPE + 48;
444
+ char buf[PCM_MAX_POID_TYPE + 48];
445
+ char *bufp = NULL;
446
+ const char *fld_name = NULL;
447
+ void *field_val = NULL;
448
+ int rec_id = 0;
449
+ int fld_type = 0;
450
+ pin_cookie_t cookie = NULL;
451
+ pin_cookie_t ary_cookie = NULL;
452
+ double dbl = 0.00;
453
+ VALUE subhash = Qundef;
454
+ pin_errbuf_t ebuf;
455
+ ConvertData cdata;
456
+ VALUE hash = Qundef, key = Qundef, val = Qundef;
457
+
458
+ cdata.flistp = NULL;
459
+ cdata.ebufp = &ebuf;
460
+
461
+ PIN_ERR_CLEAR_ERR(&ebuf);
462
+ cdata.flistp = PIN_FLIST_CREATE(&ebuf);
463
+
464
+ memset(buf,0,sizeof(buf));
465
+ bufp = buf;
466
+ hash = rb_hash_new();
467
+
468
+ while ((field_val = pin_flist_any_get_next(flistp, &fld_num, &rec_id, NULL, &cookie, &ebuf)) != NULL) {
469
+ fld_name = pin_name_of_field(fld_num);
470
+ key = rb_str_new2(fld_name);
471
+ fld_type = PIN_GET_TYPE_FROM_FLD(fld_num);
472
+ switch(fld_type) {
473
+ case PIN_FLDT_STR:
474
+ val = rb_str_new2(field_val);
475
+ break;
476
+
477
+ case PIN_FLDT_INT:
478
+ case PIN_FLDT_UINT:
479
+ case PIN_FLDT_ENUM:
480
+ case PIN_FLDT_TSTAMP:
481
+ val = INT2NUM(*(int*)field_val);
482
+ break;
483
+
484
+ case PIN_FLDT_NUM:
485
+ case PIN_FLDT_DECIMAL:
486
+ dbl = pbo_decimal_to_double((pin_decimal_t *)field_val, &ebuf);
487
+ val = rb_float_new(dbl);
488
+ break;
489
+
490
+ case PIN_FLDT_POID:
491
+ buf_size = sizeof(buf); // b/c this changes it and memset(buf,0,sizeof(buf));
492
+ PIN_POID_TO_STR((poid_t *)field_val, &bufp, &buf_size, &ebuf);
493
+ val = rb_str_new2(bufp);
494
+ break;
495
+
496
+ case PIN_FLDT_ARRAY:
497
+ subhash = rb_hash_aref(hash, key);
498
+ if (TYPE(subhash) != T_HASH){
499
+ subhash = rb_hash_new();
500
+ rb_hash_aset(hash,key,subhash);
501
+ }
502
+
503
+ val = portal_flist_to_hash((pin_flist_t *) field_val);
504
+ rb_hash_aset(subhash,INT2FIX(rec_id),val);
505
+
506
+ goto SKIP_SET;
507
+ break;
508
+
509
+ case PIN_FLDT_SUBSTRUCT:
510
+ /*
511
+ val = portal_flist_to_hash((pin_flist_t *) field_val);
512
+ rb_hash_aset(hash,key,subhash);
513
+ goto SKIP_SET;
514
+ */
515
+ /* A copy/paste of the Array code. Lets see if it works. */
516
+ subhash = rb_hash_aref(hash, key);
517
+ if (TYPE(subhash) != T_HASH){
518
+ subhash = rb_hash_new();
519
+ rb_hash_aset(hash,key,subhash);
520
+ }
521
+
522
+ val = portal_flist_to_hash((pin_flist_t *) field_val);
523
+ rb_hash_aset(subhash,INT2FIX(rec_id),val);
524
+
525
+ goto SKIP_SET;
526
+ break;
527
+
528
+ case PIN_FLDT_BINSTR:
529
+ case PIN_FLDT_ERR:
530
+ case PIN_FLDT_OBJ:
531
+ default:
532
+ fprintf(stderr," flist2hash name=%s num=%ld type=%ld\n", portal_to_char(key), fld_num, fld_type);
533
+ break;
534
+ }
535
+
536
+ if (PIN_ERR_IS_ERR(&ebuf)){
537
+ PIN_ERR_LOG_EBUF(PIN_ERR_LEVEL_ERROR, "Flist to hash conversion error", &ebuf);
538
+ rb_raise(ePortalError, "Error converting flist to hash key=%s type=%ld", portal_to_char(key),fld_type);
539
+ }
540
+
541
+ if (val != Qundef){
542
+ rb_hash_aset(hash, key, val);
543
+ #ifdef _DEBUG
544
+ if (rb_gv_get("$DEBUG"))
545
+ fprintf(stderr," flist2hash name=%s num=%ld type=%ld val=%s\n", portal_to_char(key), fld_num, fld_type, portal_to_char(val));
546
+ #endif
547
+ val = Qundef;
548
+ }
549
+
550
+ SKIP_SET:
551
+ ;
552
+ }
553
+
554
+ PIN_ERR_CLEAR_ERR(&ebuf);
555
+
556
+ Check_Type(hash,T_HASH);
557
+ return hash;
558
+ }
559
+
560
+ /*
561
+ * Test function for the from flist to hash conversion.
562
+ */
563
+ #ifdef _DEBUG
564
+ static VALUE
565
+ portal_test_flist_to_hash(self,hash)
566
+ VALUE self, hash;
567
+ {
568
+ VALUE result;
569
+ pin_flist_t *flistp;
570
+ pin_errbuf_t ebuf;
571
+ //char *flist_str = NULL;
572
+ //int flist_len = NULL;
573
+
574
+ PIN_ERR_CLEAR_ERR(&ebuf);
575
+ PIN_ERR_LOG_MSG(PIN_ERR_LEVEL_DEBUG, "Converting hash to flist");
576
+ flistp = portal_hash_to_flist(hash);
577
+ PIN_ERR_LOG_FLIST(PIN_ERR_LEVEL_DEBUG, "portal_test_flist_to_hash flist", flistp);
578
+ result = portal_flist_to_hash(flistp);
579
+
580
+ //flist_str = NULL;
581
+ //PIN_FLIST_TO_STR(flistp, &flist_str, &flist_len, &ebuf);
582
+ PIN_FLIST_DESTROY_EX(&flistp,NULL);
583
+
584
+ return result;
585
+ }
586
+ #endif
587
+
588
+ /*
589
+ * Test function for the from flist to hash conversion.
590
+ */
591
+ static VALUE
592
+ portal_hash_to_flist_string(self,hash)
593
+ VALUE self, hash;
594
+ {
595
+ VALUE result;
596
+ pin_flist_t *flistp;
597
+ pin_errbuf_t ebuf;
598
+ #if defined WINDOWS || defined _WIN32 || defined HAVE_WINDOWS_H
599
+ /* For some reason, windows does like other people giving us heap. */
600
+ int flist_len = 1000000;
601
+ char *flist_str = malloc(flist_len);
602
+ #else
603
+ int flist_len = NULL;
604
+ char *flist_str = NULL;
605
+ #endif
606
+
607
+ PIN_ERR_CLEAR_ERR(&ebuf);
608
+ flistp = portal_hash_to_flist(hash);
609
+ PIN_ERR_LOG_FLIST(PIN_ERR_LEVEL_DEBUG, "portal_hash_to_flist_string return", flistp);
610
+ PIN_FLIST_TO_STR(flistp, &flist_str, &flist_len, &ebuf);
611
+ PIN_FLIST_DESTROY_EX(&flistp,NULL);
612
+ result = rb_str_new2(flist_str);
613
+ free(flist_str);
614
+ return result;
615
+ }
616
+
617
+ /*
618
+ * Document-method: set_program_name
619
+ *
620
+ * call-seq:
621
+ * Portal.set_program_name(name) -> true
622
+ *
623
+ * Set the program name for the Portal log file.
624
+ */
625
+ static VALUE
626
+ portal_set_program_name(self,name)
627
+ VALUE self, name;
628
+ {
629
+ PIN_ERR_SET_PROGRAM(portal_to_char(name));
630
+ return Qtrue;
631
+ }
632
+
633
+ /*
634
+ * Document-method: set_log_level
635
+ *
636
+ * call-seq:
637
+ * Portal.set_log_level(level) -> true
638
+ * example:
639
+ * Portal.set_log_level(:warn)
640
+ * Portal.set_log_level(2)
641
+ *
642
+ * Set the error level for the log file using symbols, strings, or ints.
643
+ */
644
+ static VALUE
645
+ portal_set_log_level(self,level)
646
+ VALUE self, level;
647
+ {
648
+ int lev = 0;
649
+ char *cp = NULL;
650
+
651
+ if (TYPE(level) == T_STRING || TYPE(level) == T_SYMBOL) {
652
+ cp = portal_to_char(level);
653
+ if (!strcmpi(cp,"error")){
654
+ lev = PIN_ERR_LEVEL_ERROR;
655
+ } else if (!strcmpi(cp,"warn")) {
656
+ lev = PIN_ERR_LEVEL_WARNING;
657
+ } else if (!strcmpi(cp,"debug")) {
658
+ lev = PIN_ERR_LEVEL_DEBUG;
659
+ } else {
660
+ rb_raise(ePortalError, "Error level %s not supported", cp);
661
+ }
662
+ } else {
663
+ lev = NUM2INT(level);
664
+ if (lev > PIN_ERR_LEVEL_DEBUG){
665
+ rb_raise(ePortalError, "Error level %s not supported", cp);
666
+ }
667
+ }
668
+ PIN_ERR_SET_LEVEL(lev);
669
+ return Qtrue;
670
+ }
671
+
672
+ #define PORTAL_CHECK_ERROR(level,msg,flistp,ebufp) \
673
+ if (PIN_ERR_IS_ERR(ebufp)){ \
674
+ PIN_ERR_LOG_FLIST(level,msg,flistp); \
675
+ rb_raise(ePortalError, "Ebuf error: %s", msg); \
676
+ }
677
+
678
+ /*
679
+ * call-seq:
680
+ * xop(opcode,request) -> Hash
681
+ * xop(opcode,request,args) -> Hash
682
+ *
683
+ * Perform a Portal opcode by converting a hash into a flist.
684
+ *
685
+ * === Options:
686
+ * The options hash takes the following keys:
687
+ * :return | :flist_string | Converts the results flist into an flist_to_str like testnap
688
+ * :flags
689
+ *
690
+ * === Example:
691
+ * ph.xop(:PCM_OP_READ_OBJ,{:PIN_FLD_POID=>"0.0.0.1 /account 1"},:return => :flist_string)
692
+ */
693
+ static VALUE
694
+ portal_xop(argc, argv, self)
695
+ int argc;
696
+ VALUE *argv;
697
+ VALUE self;
698
+ {
699
+ VALUE sym_flist_string = Qundef, sym_return = Qundef, sym_response = Qundef;
700
+
701
+ VALUE response, tmp;
702
+ VALUE opcode, request, args;
703
+
704
+ pin_errbuf_t ebuf;
705
+ pin_flist_t *in_flistp = NULL;
706
+ pin_flist_t *out_flistp = NULL;
707
+ pin_opcode_t op;
708
+ PortalData *pd;
709
+ #if defined WINDOWS || defined _WIN32 || defined HAVE_WINDOWS_H
710
+ /* For some reason, windows does like other people giving us heap. */
711
+ int flist_len = 1000000;
712
+ char *flist_str = malloc(flist_len);
713
+ #else
714
+ int flist_len = NULL;
715
+ char *flist_str = NULL;
716
+ #endif
717
+ int return_string = 0;
718
+
719
+ rb_scan_args(argc, argv, "21", &opcode, &request, &args);
720
+
721
+ TRACE_INSPECT("opcode:",opcode);
722
+ TRACE_INSPECT("Request",request);
723
+ TRACE_INSPECT("Args",args);
724
+
725
+ if (TYPE(sym_flist_string) == T_UNDEF){
726
+ sym_flist_string = ID2SYM(rb_intern("flist_string"));
727
+ sym_return = ID2SYM(rb_intern("return"));
728
+ sym_response = ID2SYM(rb_intern("response"));
729
+ }
730
+
731
+ if (TYPE(args) == T_HASH){
732
+ tmp = rb_hash_aref(args, sym_return);
733
+ if (TYPE(tmp) == T_SYMBOL && tmp == sym_flist_string){
734
+ return_string = 1;
735
+ }
736
+ }
737
+
738
+ switch (TYPE(opcode)) {
739
+ case T_FIXNUM:
740
+ case T_BIGNUM:
741
+ op = NUM2INT(opcode);
742
+ break;
743
+ case T_STRING:
744
+ op = pcm_opname_to_opcode(portal_to_char(opcode));
745
+ default:
746
+ rb_raise(ePortalError, "Invalid opcode");
747
+ break;
748
+ } /* End switch */
749
+
750
+ TRACE_FUNC("xop","Opcode",pcm_opcode_to_opname(op));
751
+ in_flistp = portal_hash_to_flist(request);
752
+ PDataGet(self,pd);
753
+ PIN_ERR_CLEAR_ERR(&ebuf);
754
+ PCM_OP(pd->ctxp, op, 0, in_flistp, &out_flistp, &ebuf);
755
+ pd->ops++;
756
+ /*
757
+ * cm_proxy returns PIN_ERR_STREAM_EOF when not allowed.
758
+ */
759
+ // PORTAL_CHECK_ERROR(PIN_ERR_LEVEL_ERROR,"Bad operation",out_flistp,&ebuf);
760
+ if(PIN_ERR_IS_ERR(&ebuf)){
761
+ pd->errors++;
762
+ TRACE("Ebuf has error");
763
+ PIN_ERR_LOG_EBUF(PIN_ERR_LEVEL_ERROR, "xop error", &ebuf);
764
+ PIN_ERR_LOG_FLIST(PIN_ERR_LEVEL_ERROR, "input flist", in_flistp);
765
+ PIN_ERR_LOG_FLIST(PIN_ERR_LEVEL_ERROR, "return flist", out_flistp);
766
+ rb_raise(ePortalError, "Ebuf Error");
767
+ } else if (rb_gv_get("$DEBUG")) {
768
+ PIN_ERR_LOG_MSG(PIN_ERR_LEVEL_DEBUG, "xop input/output");
769
+ PIN_ERR_LOG_FLIST(PIN_ERR_LEVEL_DEBUG, "input flist", in_flistp);
770
+ PIN_ERR_LOG_FLIST(PIN_ERR_LEVEL_DEBUG, "return flist", out_flistp);
771
+ } else {
772
+ TRACE("xop success");
773
+ }
774
+
775
+ if (return_string){
776
+ PIN_FLIST_TO_STR(out_flistp, &flist_str, &flist_len, &ebuf);
777
+ //rb_str_new(flist_str,flist_len);
778
+ response = rb_hash_new();
779
+ rb_hash_aset(response,sym_flist_string,rb_str_new(flist_str,flist_len));
780
+ rb_hash_aset(response,sym_response,portal_flist_to_hash(out_flistp));
781
+ free(flist_str);
782
+ } else {
783
+ response = portal_flist_to_hash(out_flistp);
784
+ }
785
+ TRACE_INSPECT("Response",response);
786
+ PIN_FLIST_DESTROY_EX(&in_flistp, NULL);
787
+ PIN_FLIST_DESTROY_EX(&out_flistp, NULL);
788
+ TRACE("xop returning");
789
+ return response;
790
+ }
791
+
792
+ /*
793
+ * call-seq:
794
+ * loopback -> Hash
795
+ *
796
+ * Calls PCM_OP_TEST_LOOPBACK to probe the CM connection.
797
+ * A bad test will raise an exception.
798
+ * portal.loopback
799
+ */
800
+ static VALUE
801
+ portal_loopback(self)
802
+ VALUE self;
803
+ {
804
+ static VALUE poid_obj = NULL;
805
+ VALUE hash;
806
+ TRACE("Running loopback");
807
+ if (poid_obj == NULL){
808
+ poid_obj = rb_str_new2("0.0.0.1 /account 1 0")
809
+ }
810
+ hash = rb_hash_new();
811
+ rb_hash_aset(hash,rb_str_new2("PIN_FLD_POID"),poid_obj);
812
+ return rb_funcall(self, id_xop, 3, rb_str_new2("PCM_OP_TEST_LOOPBACK"), hash, Qnil);
813
+ }
814
+
815
+ /*
816
+ * call-seq:
817
+ * session -> String
818
+ *
819
+ * Returns the session associated to the current context.
820
+ * Returns nil if not connected.
821
+ */
822
+ static VALUE
823
+ portal_get_session(self)
824
+ {
825
+ PortalData *pd;
826
+ PDataGet(self,pd);
827
+ if (pd->ctxp == NULL)
828
+ return Qnil;
829
+ return portal_poid_to_val(pcm_get_session(pd->ctxp));
830
+ }
831
+
832
+ /*
833
+ * call-seq:
834
+ * userid -> String
835
+ *
836
+ * Returns the user poid associated to the current context.
837
+ * Returns nil if not connected.
838
+ */
839
+ static VALUE
840
+ portal_get_userid(self)
841
+ {
842
+ PortalData *pd;
843
+ TRACE("start");
844
+ PDataGet(self,pd);
845
+ if (pd->ctxp == NULL)
846
+ return Qnil;
847
+ return portal_poid_to_val(pcm_get_userid(pd->ctxp));
848
+ }
849
+
850
+ /*
851
+ * call-seq:
852
+ * robj(opcode,poid) -> Hash
853
+ * robj(opcode,poid,args) -> Hash
854
+ *
855
+ * Read an object. Returns the entire object.
856
+ *
857
+ * === Examples
858
+ *
859
+ * portal.robj :PIN_FLD_POID => "0.0.0.1 /account 1"
860
+ * portal.robj "0.0.0.1 /account 1"
861
+ * portal.robj "0.0.0.1 /account 1", :return => :flist_string
862
+ */
863
+ static VALUE
864
+ portal_robj(argc, argv, obj)
865
+ int argc;
866
+ VALUE *argv;
867
+ VALUE obj;
868
+ {
869
+ VALUE read_obj = NULL;
870
+ VALUE request, args, hash;
871
+ rb_scan_args(argc, argv, "11", &request, &args);
872
+
873
+ if (TYPE(request) == T_HASH) {
874
+ hash = request;
875
+ } else if (TYPE(request) == T_STRING) {
876
+ hash = rb_hash_new();
877
+ rb_hash_aset(hash,rb_str_new2("PIN_FLD_POID"),request);
878
+ } else {
879
+ rb_raise(ePortalError, "Expected Hash or String.");
880
+ }
881
+
882
+ if (read_obj == NULL){
883
+ read_obj = rb_str_new2("PCM_OP_READ_OBJ");
884
+ }
885
+
886
+ return rb_funcall(obj, id_xop, 3, read_obj, hash, args);
887
+ }
888
+
889
+ /*
890
+ * call-seq:
891
+ * connect()
892
+ * connect(hash)
893
+ * connect(string)
894
+ *
895
+ * Create a connection to Portal in one of several ways based on the arg.
896
+ * If nil, then the pin.conf in the current directory is used.
897
+ * If hash, use those details.
898
+ * If string, then that is the location for our pin.conf
899
+ *
900
+ * Connect using a pin.conf
901
+ * Portal::Connection.new.connect("/usr/local/portal/sys/test")
902
+ *
903
+ * You can supply the connection information in the request.
904
+ * This method avoids the need for a pin.conf.
905
+ * Note that this is a cm_proxy login type, so the password is not needed.
906
+ * request = {
907
+ * :PIN_FLD_POID => "0.0.0.1 /service/pcm_client 1",
908
+ * :PIN_FLD_TYPE => 0,
909
+ * :PIN_FLD_CM_PTR => {
910
+ * 0 => { :PIN_FLD_CM_PTR => "ip portal01.prod.example.com 11960"}
911
+ * 1 => { :PIN_FLD_CM_PTR => "ip portal02.prod.example.com 11960"}
912
+ * }
913
+ * Portal::Connection.new.connect(request)
914
+ */
915
+ static VALUE
916
+ portal_connect(self,obj)
917
+ VALUE self, obj;
918
+ {
919
+ PortalData *pd;
920
+ pcm_context_t *ctxp = NULL;
921
+ int64 database;// = 0;
922
+ static char * cwd = NULL;
923
+ pin_flist_t *in_flistp = NULL;
924
+
925
+ TRACE("Connecting");
926
+ PDataGet(self,pd);
927
+ PDataClearErr(pd);
928
+
929
+ if (TYPE(obj) == T_NIL ) {
930
+ PCM_CONNECT(&ctxp,&database,&pd->ebuf);
931
+ } else if (TYPE(obj) == T_HASH ) {
932
+ TRACE_INSPECT("Hash of args",obj);
933
+ in_flistp = portal_hash_to_flist(obj);
934
+ PCM_CONTEXT_OPEN(&ctxp,in_flistp,&pd->ebuf);
935
+ PIN_FLIST_DESTROY_EX(&in_flistp, NULL);
936
+ } else if (TYPE(obj) == T_STRING ) {
937
+
938
+ // Only do this once. getwd is not thread smart.
939
+ if (cwd == NULL ) {
940
+ cwd = ruby_getcwd();
941
+ if (cwd == NULL) {
942
+ rb_raise(ePortalError, "getcwd failed.");
943
+ }
944
+ }
945
+
946
+ /* Move to that directory */
947
+ if (chdir(portal_to_char(obj)) < 0) {
948
+ rb_raise(ePortalError, "Cannot cd to %s",portal_to_char(obj));
949
+ }
950
+
951
+ PCM_CONNECT(&ctxp,&database,&pd->ebuf);
952
+
953
+ /* Return to the original directory */
954
+ if (chdir(cwd) < 0) {
955
+ rb_raise(ePortalError, "Cannot cd to original dir %s",cwd);
956
+ }
957
+
958
+ } else {
959
+ rb_raise(ePortalError, "Unable to connect with supplied args.");
960
+ }
961
+
962
+ if (PIN_ERR_IS_ERR(&pd->ebuf)) {
963
+ TRACE("Bad Connect");
964
+ pd->ctxp = NULL;
965
+ if (pd->ebuf.pin_err == PIN_ERR_BAD_LOGIN_RESULT){
966
+ rb_raise(ePortalError, "Bad login result.");
967
+ }
968
+ rb_raise(ePortalError, "Cannot connect.");
969
+ }
970
+ TRACE("Connected");
971
+ pd->ctxp = ctxp;
972
+ return self;
973
+ }
974
+
975
+ /*
976
+ * call-seq:
977
+ * connected? -> true or false
978
+ *
979
+ * Returns true is we are connected to Portal. This does not probe the connection.
980
+ * Use +loopback+ to ping the CM.
981
+ * ph.connect unless ph.connected?
982
+ */
983
+ static VALUE
984
+ portal_connected(self)
985
+ VALUE self;
986
+ {
987
+ VALUE result = Qundef;
988
+ PortalData *pd;
989
+ PDataGet(self,pd);
990
+ result = pd->ctxp == NULL ? Qfalse : Qtrue;
991
+ return result;
992
+ }
993
+
994
+ /*
995
+ * call-seq:
996
+ * disconnect
997
+ *
998
+ * Disconnect from Portal. This is important to avoid mem leaks.
999
+ * ph.disconnect() rescue nil
1000
+ */
1001
+ static VALUE
1002
+ portal_disconnect(self)
1003
+ VALUE self;
1004
+ {
1005
+ PortalData *pd;
1006
+ PDataGet(self,pd);
1007
+ TRACE("Disconnecting");
1008
+ PCM_CONTEXT_CLOSE(pd->ctxp,0,&pd->ebuf);
1009
+ pd->ctxp = NULL;
1010
+ TRACE("Disconnected");
1011
+ return self;
1012
+ }
1013
+
1014
+ static VALUE
1015
+ portal_initialize(VALUE self)
1016
+ {
1017
+ if (rb_gv_get("$DEBUG")){
1018
+ PIN_ERR_SET_LEVEL(PIN_ERR_LEVEL_DEBUG);
1019
+ fprintf(stderr,"Portal logging set to debug\n");
1020
+ }
1021
+
1022
+ return self;
1023
+ }
1024
+
1025
+ /*
1026
+ * Document-class: Portal::Connection
1027
+ *
1028
+ * A single connection to Portal. Create a connection to execute opcodes.
1029
+ * Send Hash that mimics the input FList. The response is a Hash.
1030
+ * Errors usually result in an exception getting raised.
1031
+ *
1032
+ * The connection has the following attributes:
1033
+ *
1034
+ * ctxp:: The Portal context for this current connection.
1035
+ * program_name:: The program name. By default, it is the same name as the Ruby script.
1036
+ * log_level:: The logging done through the Portal logging interface.
1037
+ *
1038
+ */
1039
+
1040
+ /*
1041
+ * Document-class: Portal::Error
1042
+ *
1043
+ * In general, this exception is raise when the ebuf contains errors.
1044
+ */
1045
+
1046
+ /*
1047
+ * Document-module: Portal
1048
+ *
1049
+ * Helper functions for manipulating and converting data between Ruby and Flist.
1050
+ */
1051
+ void
1052
+ Init_portalext(void)
1053
+ {
1054
+ /* Initialize global IDs */
1055
+ id_call = rb_intern("call");
1056
+ id_inspect = rb_intern("inspect");
1057
+ id_to_f = rb_intern("to_f");
1058
+ id_to_i = rb_intern("to_i");
1059
+ id_to_s = rb_intern("to_s");
1060
+ id_xop = rb_intern("xop");
1061
+
1062
+ mPortal = rb_define_module ("Portal");
1063
+
1064
+ ePortalError = rb_define_class_under(mPortal, "Error", rb_eStandardError);
1065
+
1066
+ PIN_ERR_SET_PROGRAM(portal_to_char(rb_gv_get("$PROGRAM_NAME")));
1067
+
1068
+ /*
1069
+ * Module Portal
1070
+ */
1071
+ rb_define_module_function(mPortal,"field_num", portal_field_num,1);
1072
+ rb_define_module_function(mPortal,"field_type", portal_field_type,1);
1073
+ rb_define_module_function(mPortal,"field_name", portal_field_name,1);
1074
+ rb_define_module_function(mPortal,"set_program_name", portal_set_program_name,1);
1075
+ rb_define_module_function(mPortal,"set_log_level", portal_set_log_level,1);
1076
+ rb_define_module_function(mPortal,"hash_to_flist_string", portal_hash_to_flist_string,1);
1077
+
1078
+ #ifdef _DEBUG
1079
+ rb_define_module_function(mPortal,"test_flist_to_hash", portal_test_flist_to_hash,1);
1080
+ #endif
1081
+
1082
+ /*
1083
+ * Portal::Connection
1084
+ */
1085
+ cContext = rb_define_class_under(mPortal,"Connection", rb_cObject);
1086
+ rb_define_alloc_func(cContext, portal_alloc);
1087
+ rb_define_method(cContext, "initialize", portal_initialize, 0);
1088
+ rb_define_method(cContext, "connect", portal_connect, 1);
1089
+ rb_define_method(cContext, "connected?", portal_connected, 0);
1090
+ rb_define_method(cContext, "disconnect", portal_disconnect, 1);
1091
+ rb_define_method(cContext, "loopback", portal_loopback, 0);
1092
+ rb_define_method(cContext, "session", portal_get_session, 0);
1093
+ rb_define_method(cContext, "userid", portal_get_userid, 0);
1094
+ rb_define_method(cContext, "inspectx", portal_inspect, 0);
1095
+ rb_define_method(cContext, "robj", portal_robj, -1);
1096
+ rb_define_method(cContext, "xop", portal_xop, -1);
1097
+
1098
+ }