sys-proctable 0.9.9-universal-hpux

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile ADDED
@@ -0,0 +1,218 @@
1
+ require 'rake'
2
+ require 'rake/clean'
3
+ require 'rake/testtask'
4
+ require 'rbconfig'
5
+ include RbConfig
6
+
7
+ CLEAN.include(
8
+ '**/*.core', # Core dump files
9
+ '**/*.gem', # Gem files
10
+ '**/*.rbc', # Rubinius
11
+ '**/*.rbx', # Rubinius
12
+ '**/*.o', # C object file
13
+ '**/*.log', # Ruby extension build log
14
+ '**/Makefile', # C Makefile
15
+ '**/conftest.dSYM', # OS X build directory
16
+ "**/*.#{CONFIG['DLEXT']}" # C shared object
17
+ )
18
+
19
+ desc 'Build the sys-proctable library for C versions of sys-proctable'
20
+ task :build => [:clean] do
21
+ if RUBY_PLATFORM == 'java'
22
+ if ENV['JRUBY_OPTS']
23
+ ENV['JRUBY_OPTS'] += ' -Xcext.enabled=true'
24
+ else
25
+ ENV['JRUBY_OPTS'] = '-Xcext.enabled=true'
26
+ end
27
+ end
28
+
29
+ case CONFIG['host_os']
30
+ when /darwin/i
31
+ dir = 'ext/darwin'
32
+ ext = '.bundle'
33
+ when /hpux/i
34
+ dir = 'ext/hpux'
35
+ ext = '.sl'
36
+ end
37
+
38
+ if CONFIG['host_os'] =~ /darwin|hpux/i
39
+ Dir.chdir(dir) do
40
+ ruby 'extconf.rb'
41
+ sh 'make'
42
+ cp 'proctable' + ext, 'sys'
43
+ end
44
+ end
45
+ end
46
+
47
+ desc 'Install the sys-proctable library'
48
+ task :install => [:build] do
49
+ file = nil
50
+ dir = File.join(CONFIG['sitelibdir'], 'sys')
51
+
52
+ Dir.mkdir(dir) unless File.exists?(dir)
53
+
54
+ case CONFIG['host_os']
55
+ when /mswin|win32|msdos|cygwin|mingw|windows/i
56
+ file = 'lib/windows/sys/proctable.rb'
57
+ when /linux/i
58
+ file = 'lib/linux/sys/proctable.rb'
59
+ when /sunos|solaris/i
60
+ file = 'lib/sunos/sys/proctable.rb'
61
+ when /aix/i
62
+ file = 'lib/aix/sys/proctable.rb'
63
+ when /freebsd/i
64
+ file = 'lib/freebsd/sys/proctable.rb'
65
+ when /darwin/i
66
+ Dir.chdir('ext/darwin'){ sh 'make install' }
67
+ when /hpux/i
68
+ Dir.chdir('ext/hpux'){ sh 'make install' }
69
+ end
70
+
71
+ cp(file, dir, :verbose => true) if file
72
+ end
73
+
74
+ desc 'Uninstall the sys-proctable library'
75
+ task :uninstall do
76
+ case CONFIG['host_os']
77
+ when /darwin|hpux/i
78
+ dir = File.join(CONFIG['sitearchdir'], 'sys')
79
+ file = File.join(dir, 'proctable.' + CONFIG['DLEXT'])
80
+ else
81
+ dir = File.join(CONFIG['sitelibdir'], 'sys')
82
+ file = File.join(dir, 'proctable.rb')
83
+ end
84
+
85
+ rm(file)
86
+ end
87
+
88
+ desc 'Run the benchmark suite'
89
+ task :bench => [:build] do
90
+ sh "ruby -Ilib benchmarks/bench_ps.rb"
91
+ end
92
+
93
+ desc 'Run the example program'
94
+ task :example => [:build] do
95
+ sh 'ruby -Ilib -Iext examples/example_ps.rb'
96
+ end
97
+
98
+ desc 'Run the test suite'
99
+ Rake::TestTask.new do |t|
100
+ task :test => :build
101
+ t.libs << 'test' << '.'
102
+
103
+ case CONFIG['host_os']
104
+ when /mswin|msdos|cygwin|mingw|windows/i
105
+ t.test_files = FileList['test/test_sys_proctable_windows.rb']
106
+ t.libs << 'lib/windows'
107
+ when /linux/i
108
+ t.test_files = FileList['test/test_sys_proctable_linux.rb']
109
+ t.libs << 'lib/linux'
110
+ when /sunos|solaris/i
111
+ t.test_files = FileList['test/test_sys_proctable_sunos.rb']
112
+ t.libs << 'lib/sunos'
113
+ when /aix/i
114
+ t.test_files = FileList['test/test_sys_proctable_aix.rb']
115
+ t.libs << 'lib/aix'
116
+ when /freebsd/i
117
+ t.test_files = FileList['test/test_sys_proctable_freebsd.rb']
118
+ t.libs << 'lib/freebsd'
119
+ when /darwin/i
120
+ t.libs << 'ext/darwin'
121
+ t.test_files = FileList['test/test_sys_proctable_darwin.rb']
122
+ when /hpux/i
123
+ t.libs << 'ext/hpux'
124
+ t.test_files = FileList['test/test_sys_proctable_hpux.rb']
125
+ end
126
+ end
127
+
128
+ namespace :gem do
129
+ desc 'Create a gem for the specified OS, or your current OS by default'
130
+ task :create, [:os] => [:clean] do |_task, args|
131
+ require 'rubygems/package'
132
+
133
+ if args.is_a?(String)
134
+ os = args
135
+ else
136
+ args.with_defaults(:os => CONFIG['host_os'])
137
+ os = args[:os]
138
+ end
139
+
140
+ spec = eval(IO.read('sys-proctable.gemspec'))
141
+ spec.files += ['lib/sys-proctable.rb']
142
+
143
+ # I've had to manually futz with the spec here in some cases
144
+ # in order to get the universal platform settings I want because
145
+ # of some bugginess in Rubygems' platform.rb.
146
+ #
147
+ case os
148
+ when /freebsd/i
149
+ spec.platform = Gem::Platform.new(['universal', 'freebsd'])
150
+ spec.require_paths = ['lib', 'lib/freebsd']
151
+ spec.files += ['lib/freebsd/sys/proctable.rb']
152
+ spec.test_files << 'test/test_sys_proctable_freebsd.rb'
153
+ spec.add_dependency('ffi')
154
+ when /darwin/i
155
+ spec.platform = Gem::Platform.new(['universal', 'darwin'])
156
+ spec.files << 'ext/darwin/sys/proctable.c'
157
+ spec.extra_rdoc_files << 'ext/darwin/sys/proctable.c'
158
+ spec.test_files << 'test/test_sys_proctable_darwin.rb'
159
+ spec.extensions = ['ext/darwin/extconf.rb']
160
+ when /hpux/i
161
+ spec.platform = Gem::Platform.new(['universal', 'hpux'])
162
+ spec.files << 'ext/hpux/sys/proctable.c'
163
+ spec.extra_rdoc_files << 'ext/hpux/sys/proctable.c'
164
+ spec.test_files << 'test/test_sys_proctable_hpux.rb'
165
+ spec.extensions = ['ext/hpux/extconf.rb']
166
+ when /linux/i
167
+ spec.platform = Gem::Platform.new(['universal', 'linux'])
168
+ spec.require_paths = ['lib', 'lib/linux']
169
+ spec.files += ['lib/linux/sys/proctable.rb', 'lib/linux/sys/proctable/cgroup_entry.rb']
170
+ spec.test_files << 'test/test_sys_proctable_linux.rb'
171
+ when /sunos|solaris/i
172
+ spec.platform = Gem::Platform.new(['universal', 'solaris'])
173
+ spec.require_paths = ['lib', 'lib/sunos']
174
+ spec.files += ['lib/sunos/sys/proctable.rb']
175
+ spec.test_files << 'test/test_sys_proctable_sunos.rb'
176
+ when /aix/i
177
+ spec.platform = Gem::Platform.new(['universal', 'aix5'])
178
+ spec.require_paths = ['lib', 'lib/aix']
179
+ spec.files += ['lib/aix/sys/proctable.rb']
180
+ spec.test_files << 'test/test_sys_proctable_aix.rb'
181
+ when /mswin|win32|dos|cygwin|mingw|windows/i
182
+ spec.platform = Gem::Platform.new(['universal', 'mingw32'])
183
+ spec.require_paths = ['lib', 'lib/windows']
184
+ spec.files += ['lib/windows/sys/proctable.rb']
185
+ spec.test_files << 'test/test_sys_proctable_windows.rb'
186
+ else
187
+ raise "Unsupported platform: #{os}"
188
+ end
189
+
190
+ spec.test_files << 'test/test_sys_top.rb'
191
+
192
+ # https://github.com/rubygems/rubygems/issues/147
193
+ spec.original_platform = spec.platform
194
+
195
+ spec.signing_key = File.join(Dir.home, '.ssh', 'gem-private_key.pem')
196
+
197
+ Gem::Package.build(spec, true)
198
+ end
199
+
200
+ desc 'Create a gem for each supported OS'
201
+ task :create_all => [:clean] do
202
+ platforms = %w[aix darwin freebsd hpux linux solaris windows]
203
+ Rake::Task["clean"].execute
204
+ platforms.each{ |os|
205
+ FileUtils.mkdir_p("pkg/#{os}")
206
+ Rake::Task["gem:create"].execute(os)
207
+ Dir.glob("*.gem").each{ |gem| FileUtils.mv(gem, "pkg/#{os}") }
208
+ }
209
+ end
210
+
211
+ desc 'Install the sys-proctable library as a gem'
212
+ task :install => [:create] do
213
+ gem_name = Dir['*.gem'].first
214
+ sh "gem install -l #{gem_name}"
215
+ end
216
+ end
217
+
218
+ task :default => :test
@@ -0,0 +1,21 @@
1
+ ########################################################################
2
+ # bench_ps.rb
3
+ #
4
+ # Benchmark program to show overall speed and compare the block form
5
+ # versus the non-block form. You should run this benchmark via the
6
+ # 'rake bench' Rake task.
7
+ ########################################################################
8
+ require 'benchmark'
9
+ require 'sys/proctable'
10
+
11
+ MAX = 10
12
+
13
+ Benchmark.bm do |bench|
14
+ bench.report("Block form"){
15
+ MAX.times{ Sys::ProcTable.ps{} }
16
+ }
17
+
18
+ bench.report("Non-block form"){
19
+ MAX.times{ Sys::ProcTable.ps }
20
+ }
21
+ end
data/doc/top.txt ADDED
@@ -0,0 +1,47 @@
1
+ = Description
2
+ A simple 'top' interface for Ruby
3
+
4
+ = Prerequisites
5
+ Requires the "sys/proctable" package (which should be installed along
6
+ with this package).
7
+
8
+ = Synopsis
9
+ require "sys/top"
10
+
11
+ Sys::Top.top(5).each{ |ps|
12
+ p ps
13
+ }
14
+
15
+ = Constants
16
+ VERSION
17
+ Returns the version number of this package as a String.
18
+
19
+ = Class Methods
20
+ Sys::Top.top(number=10, field="pctcpu")
21
+ Returns an array of ProcTableStruct's. The size of the array (i.e. the
22
+ number of processes) that it returns is based on +number+, and sorted by
23
+ +pctcpu+. By default, the size and field values are 10 and "pctcpu",
24
+ respectively.
25
+
26
+ = Notes
27
+ Not all fields are available on all platforms. Please check your
28
+ platform specific documentation for which fields are available.
29
+
30
+ = Bugs
31
+ None that I'm aware of. Please log bug reports on the project page at
32
+ http://www.rubyforge.org/projects/sysutils
33
+
34
+ = License
35
+ Artistic 2.0
36
+
37
+ = Copyright
38
+ (C) 2004-2009 Daniel J. Berger
39
+ All Rights Reserved.
40
+
41
+ = Warranty
42
+ This package is provided "as is" and without any express or
43
+ implied warranties, including, without limitation, the implied
44
+ warranties of merchantability and fitness for a particular purpose.
45
+
46
+ = Author
47
+ Daniel J. Berger
@@ -0,0 +1,20 @@
1
+ #######################################################################
2
+ # example_ps.rb
3
+ #
4
+ # Generic test program that demonstrates the use of ProcTable.ps. You
5
+ # can run this via the 'rake example' task.
6
+ #
7
+ # Modify as you see fit
8
+ #######################################################################
9
+ require 'sys/proctable'
10
+ include Sys
11
+
12
+ puts "VERSION: " + ProcTable::VERSION
13
+ sleep 2
14
+
15
+ ProcTable.ps{ |s|
16
+ ProcTable.fields.each{ |field|
17
+ puts "#{field}: " + s.send(field).to_s
18
+ }
19
+ puts '=' * 30
20
+ }
@@ -0,0 +1,4 @@
1
+ require 'mkmf'
2
+
3
+ have_type('rb_pid_t', 'ruby.h')
4
+ create_makefile('sys/proctable', 'sys')
@@ -0,0 +1,325 @@
1
+ /**********************************************************************
2
+ * proctable.c
3
+ *
4
+ * HP-UX specific code for the Ruby ps extension. Some code has been
5
+ * copied directly from Dan Urist's Proc::ProcessTable Perl module.
6
+ *
7
+ * Author: Daniel Berger
8
+ **********************************************************************/
9
+ #include "ruby.h"
10
+
11
+ #define _PSTAT64
12
+
13
+ #ifdef __cplusplus
14
+ extern "C"
15
+ {
16
+ #endif
17
+
18
+ #include <sys/param.h>
19
+ #include <sys/pstat.h>
20
+ #include <devnm.h>
21
+
22
+ #define BURST 30 /* pstat structs to get per syscall */
23
+
24
+ /* Process state strings */
25
+ #define SLEEP "sleep"
26
+ #define RUN "run"
27
+ #define STOP "stop"
28
+ #define ZOMBIE "zombie"
29
+ #define IDLE "idle"
30
+ #define OTHER "other"
31
+
32
+ VALUE sProcStruct, cProcError;
33
+
34
+ /*****************************************************************************
35
+ * This array's only purpose is for the 'fields()' class method. If there's
36
+ * a way to report fields out of our defined struct (sProc), please tell me
37
+ * how!
38
+ *****************************************************************************/
39
+ char *fields[] = {
40
+ "comm",
41
+ "uid",
42
+ "pid",
43
+ "ppid",
44
+ "dsize",
45
+ "tsize",
46
+ "ssize",
47
+ "nice",
48
+ "ttydev",
49
+ "pgrp",
50
+ "pri",
51
+ "addr",
52
+ "cpu",
53
+ "utime",
54
+ "stime",
55
+ "start",
56
+ "flag",
57
+ "stat",
58
+ "wchan",
59
+ "procnum",
60
+ "cmd",
61
+ "cmdline",
62
+ "time",
63
+ "cpticks",
64
+ "cptickstotal",
65
+ "fss",
66
+ "pctcpu",
67
+ "rssize",
68
+ "suid",
69
+ "shmsize",
70
+ "mmsize",
71
+ "usize",
72
+ "iosize",
73
+ "vtsize",
74
+ "vdsize",
75
+ "vssize",
76
+ "vshmsize",
77
+ "vmmsize",
78
+ "vusize",
79
+ "viosize",
80
+ "minorfaults",
81
+ "majorfaults",
82
+ "nswap",
83
+ "nsignals",
84
+ "msgrcv",
85
+ "msgsnd",
86
+ "maxrss",
87
+ "sid",
88
+ "schedpolicy",
89
+ "ticksleft",
90
+ "euid",
91
+ "egid",
92
+ "gid",
93
+ "sgid"
94
+ };
95
+
96
+
97
+ /*
98
+ * Private method that converts a psinfo struct into a Ruby struct.
99
+ */
100
+ static VALUE proctable_getprocstruct(struct pst_status *p)
101
+ {
102
+ char state[10];
103
+ char flag[12];
104
+ char ttydev[MAXPATHLEN+1];
105
+ VALUE v_tty, v_struct;
106
+
107
+ switch( p->pst_stat )
108
+ {
109
+ case PS_SLEEP:
110
+ strcpy(state,SLEEP);
111
+ break;
112
+ case PS_RUN:
113
+ strcpy(state,RUN);
114
+ break;
115
+ case PS_STOP:
116
+ strcpy(state,STOP);
117
+ break;
118
+ case PS_ZOMBIE:
119
+ strcpy(state,ZOMBIE);
120
+ break;
121
+ case PS_IDLE:
122
+ strcpy(state,IDLE);
123
+ break;
124
+ case PS_OTHER:
125
+ strcpy(state,OTHER);
126
+ break;
127
+ default:
128
+ strcpy(state,"unknown");
129
+ }
130
+
131
+ /* If the major number is -1, there is no associated tty */
132
+ if(p->pst_term.psd_major != -1){
133
+ devnm(
134
+ S_IFCHR,
135
+ (dev_t)((p->pst_term.psd_major << 24) | p->pst_term.psd_minor),
136
+ ttydev,
137
+ sizeof(ttydev),
138
+ 1
139
+ );
140
+ v_tty = rb_str_new2(ttydev);
141
+ }
142
+ else{
143
+ v_tty = rb_str_new2("");
144
+ }
145
+
146
+ v_struct = rb_struct_new(sProcStruct,
147
+ rb_str_new2(p->pst_ucomm),
148
+ INT2NUM(p->pst_uid),
149
+ INT2NUM(p->pst_pid),
150
+ INT2NUM(p->pst_ppid),
151
+ INT2NUM(p->pst_dsize),
152
+ INT2NUM(p->pst_tsize),
153
+ INT2NUM(p->pst_ssize),
154
+ INT2NUM(p->pst_nice),
155
+ v_tty,
156
+ INT2NUM(p->pst_pgrp),
157
+ INT2NUM(p->pst_pri),
158
+ INT2NUM(p->pst_addr),
159
+ INT2NUM(p->pst_cpu),
160
+ INT2NUM(p->pst_utime),
161
+ INT2NUM(p->pst_stime),
162
+ rb_time_new(p->pst_start,0),
163
+ INT2NUM(p->pst_flag),
164
+ rb_str_new2(state),
165
+ INT2NUM(p->pst_wchan),
166
+ INT2NUM(p->pst_procnum),
167
+ rb_str_new2(p->pst_cmd),
168
+ rb_str_new2(p->pst_cmd),
169
+ INT2NUM(p->pst_time),
170
+ INT2NUM(p->pst_cpticks),
171
+ INT2NUM(p->pst_cptickstotal),
172
+ INT2NUM(p->pst_fss),
173
+ rb_float_new(p->pst_pctcpu),
174
+ INT2NUM(p->pst_rssize),
175
+ INT2NUM(p->pst_suid),
176
+ INT2NUM(p->pst_shmsize),
177
+ INT2NUM(p->pst_mmsize),
178
+ INT2NUM(p->pst_usize),
179
+ INT2NUM(p->pst_iosize),
180
+ INT2NUM(p->pst_vtsize),
181
+ INT2NUM(p->pst_vdsize),
182
+ INT2NUM(p->pst_vssize),
183
+ INT2NUM(p->pst_vshmsize),
184
+ INT2NUM(p->pst_vmmsize),
185
+ INT2NUM(p->pst_vusize),
186
+ INT2NUM(p->pst_viosize),
187
+ UINT2NUM(p->pst_minorfaults),
188
+ UINT2NUM(p->pst_majorfaults),
189
+ UINT2NUM(p->pst_nswap),
190
+ UINT2NUM(p->pst_nsignals),
191
+ UINT2NUM(p->pst_msgrcv),
192
+ UINT2NUM(p->pst_msgsnd),
193
+ INT2NUM(p->pst_maxrss),
194
+ INT2NUM(p->pst_sid),
195
+ INT2NUM(p->pst_schedpolicy),
196
+ INT2NUM(p->pst_ticksleft),
197
+ INT2NUM(p->pst_euid),
198
+ INT2NUM(p->pst_egid),
199
+ INT2NUM(p->pst_gid),
200
+ INT2NUM(p->pst_sgid)
201
+ );
202
+
203
+ OBJ_FREEZE(v_struct);
204
+
205
+ return v_struct;
206
+ }
207
+
208
+ /*
209
+ * call-seq:
210
+ * ProcTable.ps(pid=nil)
211
+ * ProcTable.ps(pid=nil){ |ps| ... }
212
+ *
213
+ * In block form, yields a ProcTableStruct for each process entry that you
214
+ * have rights to. This method returns an array of ProcTableStruct's in
215
+ * non-block form.
216
+ *
217
+ * If a +pid+ is provided, then only a single ProcTableStruct is yielded or
218
+ * returned, or nil if no process information is found for that +pid+.
219
+ */
220
+ static VALUE proctable_ps(int argc, VALUE *argv)
221
+ {
222
+ struct pst_status pst[BURST];
223
+ int i, count;
224
+ int idx = 0;
225
+ int found = 0;
226
+ VALUE v_pid = Qnil;
227
+ VALUE v_arr = rb_ary_new();
228
+
229
+ rb_scan_args(argc, argv, "01", &v_pid);
230
+
231
+ if(v_pid != Qnil){
232
+ struct pst_status pst_single;
233
+ int n = NUM2INT(v_pid);
234
+ if(pstat_getproc(&pst_single, sizeof(pst_single), 0, n) > 0){
235
+ if(rb_block_given_p()){
236
+ rb_yield(proctable_getprocstruct(&pst_single));
237
+ return Qnil;
238
+ }
239
+ else{
240
+ return(proctable_getprocstruct(&pst_single));
241
+ }
242
+ }
243
+ else{
244
+ return Qnil; /* not found */
245
+ }
246
+ }
247
+
248
+ while ((count = pstat_getproc(pst, sizeof(pst[0]), BURST, idx)) > 0){
249
+ for (i = 0; i < count; i++){
250
+ if( rb_block_given_p() )
251
+ rb_yield(proctable_getprocstruct(&pst[i]));
252
+ else
253
+ rb_ary_push(v_arr, proctable_getprocstruct(&pst[i]) );
254
+ }
255
+ idx = pst[count-1].pst_idx + 1;
256
+ }
257
+
258
+ if(rb_block_given_p())
259
+ return Qnil;
260
+
261
+ return v_arr;
262
+ }
263
+
264
+ /*
265
+ * call-seq:
266
+ * ProcTable.fields
267
+ *
268
+ * Returns an array of fields that each ProcTableStruct will contain. This
269
+ * may be useful if you want to know in advance what fields are available
270
+ * without having to perform at least one read of the /proc table.
271
+ */
272
+ static VALUE proctable_fields()
273
+ {
274
+ int i;
275
+ VALUE v_farray = rb_ary_new();
276
+
277
+ for(i = 0; i < (sizeof(fields) / sizeof(fields[0])); i++)
278
+ rb_ary_push(v_farray,rb_str_new2(fields[i]));
279
+
280
+ return v_farray;
281
+ }
282
+
283
+ /*
284
+ * A Ruby interface for gathering process table information.
285
+ */
286
+ void Init_proctable()
287
+ {
288
+ VALUE mSys, cProcTable;
289
+
290
+ /* The Sys module serves as a namespace only */
291
+ mSys = rb_define_module("Sys");
292
+
293
+ /* The ProcTable class encapsulates process table information */
294
+ cProcTable = rb_define_class_under(mSys, "ProcTable", rb_cObject);
295
+
296
+ /* The error typically raised if any of the ProcTable methods fail */
297
+ cProcError = rb_define_class_under(cProcTable, "Error", rb_eStandardError);
298
+
299
+ /* Singleton methods */
300
+
301
+ rb_define_singleton_method(cProcTable, "fields", proctable_fields, 0);
302
+ rb_define_singleton_method(cProcTable, "ps", proctable_ps, -1);
303
+
304
+ /* There is no constructor */
305
+ rb_funcall(cProcTable, rb_intern("private_class_method"), 1, ID2SYM(rb_intern("new")));
306
+
307
+ /* 0.9.9: The version of the sys-proctable library. */
308
+ rb_define_const(cProcTable, "VERSION", rb_str_new2("0.9.9"));
309
+
310
+ /* Structs */
311
+
312
+ sProcStruct = rb_struct_define("ProcTableStruct",
313
+ "comm","uid","pid","ppid","dsize","tsize","ssize","nice","ttydev","pgrp",
314
+ "pri","addr","cpu","utime","stime","start","flag","stat","wchan",
315
+ "procnum","cmd","cmdline","time","cpticks","cptickstotal","fss","pctcpu",
316
+ "rssize","suid","shmsize","mmsize", "usize","iosize","vtsize","vdsize",
317
+ "vssize","vshmsize","vmmsize","vusize","viosize","minorfaults",
318
+ "majorfaults","nswap","nsignals","msgrcv","msgsnd","maxrss","sid",
319
+ "schedpolicy","ticksleft","euid","egid","gid","sgid",NULL
320
+ );
321
+ }
322
+
323
+ #ifdef __cplusplus
324
+ }
325
+ #endif