portal-ruby 0.0.2

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.
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
+ }