ekaranto-rubywmq 2.0.0
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/.document +4 -0
- data/LICENSE.txt +201 -0
- data/README.md +408 -0
- data/Rakefile +87 -0
- data/examples/each_a.rb +16 -0
- data/examples/each_b.rb +25 -0
- data/examples/each_header.rb +22 -0
- data/examples/files_to_q.cfg +24 -0
- data/examples/files_to_q.rb +31 -0
- data/examples/get_a.rb +19 -0
- data/examples/get_client.rb +35 -0
- data/examples/put1_a.rb +9 -0
- data/examples/put1_b.rb +17 -0
- data/examples/put1_c.rb +16 -0
- data/examples/put_a.rb +19 -0
- data/examples/put_b.rb +27 -0
- data/examples/put_dlh.rb +25 -0
- data/examples/put_dynamic_q.rb +22 -0
- data/examples/put_group_a.rb +35 -0
- data/examples/put_group_b.rb +37 -0
- data/examples/put_rfh.rb +51 -0
- data/examples/put_rfh2_a.rb +27 -0
- data/examples/put_rfh2_b.rb +27 -0
- data/examples/put_xmit_q.rb +17 -0
- data/examples/q_to_files.cfg +17 -0
- data/examples/q_to_files.rb +32 -0
- data/examples/request.rb +44 -0
- data/examples/server.rb +81 -0
- data/ext/decode_rfh.c +348 -0
- data/ext/decode_rfh.h +45 -0
- data/ext/extconf.rb +30 -0
- data/ext/extconf_client.rb +24 -0
- data/ext/generate/generate_const.rb +140 -0
- data/ext/generate/generate_reason.rb +233 -0
- data/ext/generate/generate_structs.rb +82 -0
- data/ext/generate/wmq_structs.erb +341 -0
- data/ext/wmq.c +90 -0
- data/ext/wmq.h +371 -0
- data/ext/wmq_message.c +671 -0
- data/ext/wmq_mq_load.c +217 -0
- data/ext/wmq_queue.c +1411 -0
- data/ext/wmq_queue_manager.c +1570 -0
- data/lib/rubywmq.rb +1 -0
- data/lib/wmq/message.rb +70 -0
- data/lib/wmq/queue_manager.rb +110 -0
- data/lib/wmq/version.rb +3 -0
- data/lib/wmq.rb +16 -0
- data/nbproject/project.properties +11 -0
- data/nbproject/project.xml +17 -0
- data/tests/test.rb +318 -0
- metadata +115 -0
data/examples/request.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
#
|
2
|
+
# Sample : request.rb
|
3
|
+
#
|
4
|
+
# Sample program that demonstrates how to send a request message
|
5
|
+
# and then block until the response is received from the server.
|
6
|
+
#
|
7
|
+
# A temporary Dynamic Reply To Queue is used with non-persistent messaging
|
8
|
+
#
|
9
|
+
require 'rubygems'
|
10
|
+
require 'wmq'
|
11
|
+
|
12
|
+
wait_seconds = 30
|
13
|
+
|
14
|
+
WMQ::QueueManager.connect(:q_mgr_name=>'REID') do |qmgr|
|
15
|
+
qmgr.open_queue(:q_name => 'SYSTEM.DEFAULT.MODEL.QUEUE',
|
16
|
+
:dynamic_q_name=> 'REQUEST.*',
|
17
|
+
:mode => :input
|
18
|
+
) do |reply_queue|
|
19
|
+
|
20
|
+
message = WMQ::Message.new()
|
21
|
+
message.descriptor = { :msg_type => WMQ::MQMT_REQUEST,
|
22
|
+
:reply_to_q => reply_queue.name,
|
23
|
+
:reply_to_q_mgr=> qmgr.name,
|
24
|
+
:format => WMQ::MQFMT_STRING,
|
25
|
+
:expiry => wait_seconds*10} # Measured in tenths of a second
|
26
|
+
message.data = 'Hello World'
|
27
|
+
|
28
|
+
# Send request message
|
29
|
+
qmgr.put(:q_name=>'TEST.QUEUE', :message=>message)
|
30
|
+
|
31
|
+
# Copy outgoing Message id to correlation id
|
32
|
+
message.descriptor[:correl_id]=message.descriptor[:msg_id]
|
33
|
+
|
34
|
+
# Wait for reply
|
35
|
+
# Only get the message that matches the correlation id set above
|
36
|
+
if reply_queue.get(:wait=>wait_seconds*1000, :message=>message, :match=>WMQ::MQMO_MATCH_CORREL_ID)
|
37
|
+
puts "Received:"
|
38
|
+
puts message.data
|
39
|
+
else
|
40
|
+
# get returns false when no message received. Also: message.data = nil
|
41
|
+
puts "Timed Out waiting for a reply from the server"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/examples/server.rb
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
#
|
2
|
+
# Sample : Sample program to show how to write a server side application
|
3
|
+
#
|
4
|
+
# This server times out after 60 seconds, but could be modified to
|
5
|
+
# run forever. Example:
|
6
|
+
# queue.each(:wait=>-1) do |message|
|
7
|
+
#
|
8
|
+
# Note: - All calls are being performed under synchpoint control to
|
9
|
+
# prevent messages being if the program terminates unexpectedly
|
10
|
+
# or an error occurrs.
|
11
|
+
# Uses: :sync=>true
|
12
|
+
# - Queue#each will backout any message changes if an excecption is raised
|
13
|
+
# but not handled within the each block
|
14
|
+
#
|
15
|
+
# A "well-behaved" WebSphere MQ application should adhere to the following rules:
|
16
|
+
# - Perform puts and gets under synchpoint where applicable
|
17
|
+
# - Only send replies to Request messages. No reply for Datagrams
|
18
|
+
# - Set the message type to Reply when replying to a request message
|
19
|
+
# - Reply with:
|
20
|
+
# - Remaining Expiry (Ideally deduct any processing time since get)
|
21
|
+
# - Same priority as received message
|
22
|
+
# - Same persistence as received message
|
23
|
+
# - Adhere to the Report options supplied for message and correlation id's
|
24
|
+
# in reply message
|
25
|
+
# - All headers must be returned on reply messages
|
26
|
+
# - This allows the calling application to store state information
|
27
|
+
# in these headers
|
28
|
+
# - Unless of course if the relevant header is input only and used
|
29
|
+
# for completing the request
|
30
|
+
# - In this case any remaining headers should be returned
|
31
|
+
# to the caller
|
32
|
+
# - If an error occurs trying to process the message, an error message
|
33
|
+
# must be sent back to the requesting application
|
34
|
+
# - If the reply fails, it must be put to the dead letter queue
|
35
|
+
# with the relevant dead letter header and reason
|
36
|
+
#
|
37
|
+
# Note: - It is not recommended to run server side MQ applications over a client
|
38
|
+
# connection.
|
39
|
+
# - Client connections require substantially more error handling.
|
40
|
+
# - E.g. Connection to queue manager can be lost due to netowk issues
|
41
|
+
# - Need to go into some sort of retry state attempting
|
42
|
+
# to reconnect to the queue manager
|
43
|
+
# - What about any work that was in progress?
|
44
|
+
# - Need to re-open any queues
|
45
|
+
# - Do any changes to other resources need to be undone first?
|
46
|
+
# - E.g. Database, File etc..
|
47
|
+
# - etc....
|
48
|
+
#
|
49
|
+
require 'rubygems'
|
50
|
+
require 'wmq'
|
51
|
+
|
52
|
+
WMQ::QueueManager.connect(:q_mgr_name=>'REID') do |qmgr|
|
53
|
+
qmgr.open_queue(:q_name=>'TEST.QUEUE', :mode=>:input) do |queue|
|
54
|
+
queue.each(:wait=>60000, :sync=>true, :convert=>true) do |request|
|
55
|
+
puts "Data Received:"
|
56
|
+
puts request.data
|
57
|
+
|
58
|
+
begin
|
59
|
+
reply = WMQ::Message.new
|
60
|
+
reply.data = 'Echo back:'+request.data
|
61
|
+
|
62
|
+
qmgr.put_to_reply_q(:message=>reply,
|
63
|
+
:request_message=>request, # Only replies if message type is request
|
64
|
+
:sync=>true)
|
65
|
+
|
66
|
+
rescue WMQ::WMQException => exc
|
67
|
+
# Failed to send reply, put message to the Dead Letter Queue and add a dead letter header
|
68
|
+
p exc
|
69
|
+
puts "Failed to reply to sender, Put to dead letter queue"
|
70
|
+
qmgr.put_to_dead_letter_q(:message=>request,
|
71
|
+
:reason=>WMQ::MQRC_UNKNOWN_REMOTE_Q_MGR,
|
72
|
+
:q_name=>queue.name,
|
73
|
+
:sync=>true)
|
74
|
+
# If it fails to put to the dead letter queue, this program will terminate and
|
75
|
+
# the changes will be "backed out". E.g. Queue Full, ...
|
76
|
+
end
|
77
|
+
qmgr.commit
|
78
|
+
end
|
79
|
+
end
|
80
|
+
puts 'No more messages found after 60 second wait interval'
|
81
|
+
end
|
data/ext/decode_rfh.c
ADDED
@@ -0,0 +1,348 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright 2007 Edwin M. Fine, Fine Computer Consultants, Inc.
|
3
|
+
*
|
4
|
+
* Licensed under the Apache License, Version 2.0
|
5
|
+
* (the "License"); you may not use this file except
|
6
|
+
* in compliance with the License. You may obtain a copy
|
7
|
+
* of the License at http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
* Unless required by applicable law or agreed to in writing,
|
9
|
+
* software distributed under the License is distributed on an
|
10
|
+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
11
|
+
* either express or implied. See the License for the specific
|
12
|
+
* language governing permissions and limitations under the License.
|
13
|
+
*/
|
14
|
+
|
15
|
+
/*
|
16
|
+
* This function decodes an RFH NameValueString into separate
|
17
|
+
* name/value strings and invokes a callback function for each
|
18
|
+
* name/value pair. The callback function prototype is
|
19
|
+
*
|
20
|
+
* void cbfunc(const char *name, const char *value);
|
21
|
+
*
|
22
|
+
* Strings are expected to be null-terminated and not contain any
|
23
|
+
* null characters.
|
24
|
+
*
|
25
|
+
* This is the specification for NameValueString:
|
26
|
+
*
|
27
|
+
* NameValueString (MQCHARn)
|
28
|
+
*
|
29
|
+
* String containing name/value pairs.
|
30
|
+
*
|
31
|
+
* This is a variable-length character string containing name/value
|
32
|
+
* pairs in the form:
|
33
|
+
*
|
34
|
+
* name1 value1 name2 value2 name3 value3 ...
|
35
|
+
*
|
36
|
+
* Each name or value must be separated from the adjacent name
|
37
|
+
* or value by one or more blank characters; these blanks are
|
38
|
+
* not significant. A name or value can contain significant
|
39
|
+
* blanks by prefixing and suffixing the name or value with the
|
40
|
+
* double-quote character; all characters between the open
|
41
|
+
* double-quote and the matching close double-quote are treated
|
42
|
+
* as significant. In the following example, the name is
|
43
|
+
* FAMOUS_WORDS, and the value is Hello World:
|
44
|
+
*
|
45
|
+
* FAMOUS_WORDS "Hello World"
|
46
|
+
*
|
47
|
+
* A name or value can contain any characters other than the
|
48
|
+
* null character (which acts as a delimiter for
|
49
|
+
* NameValueString). However, to assist interoperability, an
|
50
|
+
* application might prefer to restrict names to the following
|
51
|
+
* characters:
|
52
|
+
*
|
53
|
+
* * First character: upper case or lower case alphabetic (A
|
54
|
+
* through Z, or a through z), or underscore.
|
55
|
+
*
|
56
|
+
* * Second character: upper case or lower case alphabetic,
|
57
|
+
* decimal digit (0 through 9), underscore, hyphen, or
|
58
|
+
* dot.
|
59
|
+
*
|
60
|
+
* If a name or value contains one or more double-quote
|
61
|
+
* characters, the name or value must be enclosed in double
|
62
|
+
* quotes, and each double quote within the string must be
|
63
|
+
* doubled, for example:
|
64
|
+
*
|
65
|
+
* Famous_Words "The program displayed ""Hello World"""
|
66
|
+
*
|
67
|
+
* Names and values are case sensitive, that is, lowercase
|
68
|
+
* letters are not considered to be the same as uppercase
|
69
|
+
* letters. For example, FAMOUS_WORDS and Famous_Words are two
|
70
|
+
* different names. / The length in bytes of NameValueString is
|
71
|
+
* equal to StrucLength minus MQRFH_STRUC_LENGTH_FIXED. To avoid
|
72
|
+
* problems with data conversion of the user data in some
|
73
|
+
* environments, make sure that this length is a multiple of
|
74
|
+
* four. NameValueString must be padded with blanks to this
|
75
|
+
* length, or terminated earlier by placing a null character
|
76
|
+
* following the last value in the string. The null and bytes
|
77
|
+
* following it, up to the specified length of NameValueString,
|
78
|
+
* are ignored.
|
79
|
+
*/
|
80
|
+
|
81
|
+
#include "decode_rfh.h"
|
82
|
+
#include <stdio.h>
|
83
|
+
|
84
|
+
#define MAX_TOK_LEN 1024 /* This is pretty generous */
|
85
|
+
#define EOS -1 /* End of input string */
|
86
|
+
#define QUOTE '"'
|
87
|
+
|
88
|
+
#define IS_SEPARATOR(ch) ((ch) == ' ' || (ch) == '\0')
|
89
|
+
#define IS_VALID_ID_CHAR(ch) (!IS_SEPARATOR(ch))
|
90
|
+
#define IS_UNQUOTED_ID_CHAR(ch) (!IS_SEPARATOR(ch) && ch != QUOTE)
|
91
|
+
#define GETCHAR(charp, endp) ((charp) < (endp) ? (int)*charp++ : EOS)
|
92
|
+
#define LOOKAHEAD(charp, endp) (charp < endp - 1 ? (int)*charp : EOS)
|
93
|
+
#define PUSHBACK(ch, charp) (*--charp = (char)ch)
|
94
|
+
|
95
|
+
#define SKIP_SEPARATORS(charp, endp) \
|
96
|
+
while (charp < endp && IS_SEPARATOR(*charp)) ++charp
|
97
|
+
|
98
|
+
typedef enum {
|
99
|
+
ST_INITIAL,
|
100
|
+
ST_IN_QUOTED_ID,
|
101
|
+
ST_IN_UNQUOTED_ID,
|
102
|
+
ST_END,
|
103
|
+
} state_t;
|
104
|
+
|
105
|
+
static int debug_mode = 0;
|
106
|
+
|
107
|
+
int rfh_in_debug_mode(void)
|
108
|
+
{
|
109
|
+
return debug_mode;
|
110
|
+
}
|
111
|
+
|
112
|
+
void rfh_set_debug_mode(int on_if_true)
|
113
|
+
{
|
114
|
+
debug_mode = on_if_true;
|
115
|
+
}
|
116
|
+
|
117
|
+
#define ENUM_TUPLE(enum_val) { enum_val, #enum_val }
|
118
|
+
#define NUM_ELEMS(arr) (sizeof(arr) / sizeof(*arr))
|
119
|
+
|
120
|
+
static const char *rfh_state_to_s(state_t state)
|
121
|
+
{
|
122
|
+
static struct
|
123
|
+
{
|
124
|
+
state_t state;
|
125
|
+
const char *str;
|
126
|
+
} state_map[] =
|
127
|
+
{
|
128
|
+
ENUM_TUPLE(ST_INITIAL),
|
129
|
+
ENUM_TUPLE(ST_IN_QUOTED_ID),
|
130
|
+
ENUM_TUPLE(ST_IN_UNQUOTED_ID),
|
131
|
+
ENUM_TUPLE(ST_END),
|
132
|
+
};
|
133
|
+
|
134
|
+
size_t i;
|
135
|
+
|
136
|
+
for (i = 0; i < NUM_ELEMS(state_map); ++i)
|
137
|
+
if (state_map[i].state == state)
|
138
|
+
return state_map[i].str;
|
139
|
+
|
140
|
+
return "";
|
141
|
+
}
|
142
|
+
|
143
|
+
const char *rfh_toktype_to_s(rfh_toktype_t toktype)
|
144
|
+
{
|
145
|
+
static struct
|
146
|
+
{
|
147
|
+
rfh_toktype_t toktype;
|
148
|
+
const char *str;
|
149
|
+
} toktype_map[] =
|
150
|
+
{
|
151
|
+
ENUM_TUPLE(TT_TOKEN),
|
152
|
+
ENUM_TUPLE(TT_UNESCAPED_QUOTE),
|
153
|
+
ENUM_TUPLE(TT_ILLEGAL_QUOTE),
|
154
|
+
ENUM_TUPLE(TT_UNEXPECTED_EOS),
|
155
|
+
ENUM_TUPLE(TT_TOKEN_TRUNCATED),
|
156
|
+
ENUM_TUPLE(TT_INTERNAL_ERROR),
|
157
|
+
ENUM_TUPLE(TT_ALLOC_FAILURE),
|
158
|
+
ENUM_TUPLE(TT_END),
|
159
|
+
};
|
160
|
+
|
161
|
+
size_t i;
|
162
|
+
|
163
|
+
for (i = 0; i < NUM_ELEMS(toktype_map); ++i)
|
164
|
+
if (toktype_map[i].toktype == toktype)
|
165
|
+
return toktype_map[i].str;
|
166
|
+
|
167
|
+
return "";
|
168
|
+
}
|
169
|
+
|
170
|
+
static rfh_toktype_t get_token(const char **charpp, const char *endp, char *token, char *end_token)
|
171
|
+
{
|
172
|
+
const char *charp = *charpp;
|
173
|
+
char *tokp = token;
|
174
|
+
int ch;
|
175
|
+
state_t state = ST_INITIAL;
|
176
|
+
rfh_toktype_t toktype = TT_TOKEN;
|
177
|
+
|
178
|
+
SKIP_SEPARATORS(charp, endp);
|
179
|
+
|
180
|
+
while (state != ST_END && tokp < end_token)
|
181
|
+
{
|
182
|
+
ch = GETCHAR(charp, endp);
|
183
|
+
|
184
|
+
if (debug_mode)
|
185
|
+
fprintf(stderr, "state = %s, char = %c [%d]\n", rfh_state_to_s(state), (char)ch, ch);
|
186
|
+
|
187
|
+
switch (state)
|
188
|
+
{
|
189
|
+
case ST_INITIAL:
|
190
|
+
if (ch == EOS)
|
191
|
+
{
|
192
|
+
*tokp = '\0';
|
193
|
+
toktype = TT_END;
|
194
|
+
state = ST_END;
|
195
|
+
if (debug_mode)
|
196
|
+
fprintf(stderr, "new state = %s, toktype = %s\n",
|
197
|
+
rfh_state_to_s(state), rfh_toktype_to_s(toktype));
|
198
|
+
}
|
199
|
+
else if (IS_UNQUOTED_ID_CHAR(ch))
|
200
|
+
{
|
201
|
+
*tokp++ = (char)ch;
|
202
|
+
state = ST_IN_UNQUOTED_ID;
|
203
|
+
if (debug_mode)
|
204
|
+
fprintf(stderr, "new state = %s\n", rfh_state_to_s(state));
|
205
|
+
}
|
206
|
+
else if (ch == QUOTE)
|
207
|
+
{
|
208
|
+
state = ST_IN_QUOTED_ID;
|
209
|
+
if (debug_mode)
|
210
|
+
fprintf(stderr, "new state = %s\n", rfh_state_to_s(state));
|
211
|
+
}
|
212
|
+
break;
|
213
|
+
|
214
|
+
case ST_IN_UNQUOTED_ID:
|
215
|
+
if (IS_SEPARATOR(ch) || ch == EOS)
|
216
|
+
{
|
217
|
+
*tokp = '\0';
|
218
|
+
state = ST_END;
|
219
|
+
if (debug_mode)
|
220
|
+
fprintf(stderr, "new state = %s\n", rfh_state_to_s(state));
|
221
|
+
}
|
222
|
+
else if (ch == QUOTE) /* Not allowed in unquoted string */
|
223
|
+
{
|
224
|
+
toktype = TT_ILLEGAL_QUOTE;
|
225
|
+
state = ST_END;
|
226
|
+
if (debug_mode)
|
227
|
+
fprintf(stderr, "new state = %s, toktype = %s\n",
|
228
|
+
rfh_state_to_s(state), rfh_toktype_to_s(toktype));
|
229
|
+
}
|
230
|
+
else
|
231
|
+
*tokp++ = (char)ch;
|
232
|
+
break;
|
233
|
+
|
234
|
+
case ST_IN_QUOTED_ID:
|
235
|
+
if (ch == QUOTE) /* Could be end of token, or first char of "" */
|
236
|
+
{
|
237
|
+
int lookahead_ch = LOOKAHEAD(charp, endp);
|
238
|
+
if (lookahead_ch == QUOTE) /* Found escaped quote */
|
239
|
+
{
|
240
|
+
*tokp++ = QUOTE;
|
241
|
+
++charp; /* Skip second quote */
|
242
|
+
}
|
243
|
+
else if (IS_SEPARATOR(lookahead_ch) || lookahead_ch == EOS) /* End of token */
|
244
|
+
{
|
245
|
+
*tokp = '\0';
|
246
|
+
state = ST_END;
|
247
|
+
if (debug_mode)
|
248
|
+
fprintf(stderr, "new state = %s\n", rfh_state_to_s(state));
|
249
|
+
}
|
250
|
+
else /* Error: Unescaped quote */
|
251
|
+
{
|
252
|
+
toktype = TT_UNESCAPED_QUOTE;
|
253
|
+
state = ST_END;
|
254
|
+
if (debug_mode)
|
255
|
+
fprintf(stderr, "new state = %s, toktype = %s\n",
|
256
|
+
rfh_state_to_s(state), rfh_toktype_to_s(toktype));
|
257
|
+
}
|
258
|
+
}
|
259
|
+
else if (ch == EOS) /* Error */
|
260
|
+
{
|
261
|
+
toktype = TT_UNEXPECTED_EOS;
|
262
|
+
state = ST_END;
|
263
|
+
if (debug_mode)
|
264
|
+
fprintf(stderr, "new state = %s, toktype = %s\n",
|
265
|
+
rfh_state_to_s(state), rfh_toktype_to_s(toktype));
|
266
|
+
}
|
267
|
+
else
|
268
|
+
*tokp++ = (char)ch;
|
269
|
+
break;
|
270
|
+
|
271
|
+
default:
|
272
|
+
toktype = TT_INTERNAL_ERROR;
|
273
|
+
state = ST_END;
|
274
|
+
if (debug_mode)
|
275
|
+
fprintf(stderr, "new state = %s, toktype = %s\n",
|
276
|
+
rfh_state_to_s(state), rfh_toktype_to_s(toktype));
|
277
|
+
break;
|
278
|
+
} /* switch */
|
279
|
+
} /* while */
|
280
|
+
|
281
|
+
/* If state is not ST_END, an error may have occurred */
|
282
|
+
if (state != ST_END && toktype == TT_TOKEN)
|
283
|
+
{
|
284
|
+
if (tokp >= end_token)
|
285
|
+
toktype = TT_TOKEN_TRUNCATED;
|
286
|
+
else
|
287
|
+
toktype = TT_UNEXPECTED_EOS;
|
288
|
+
|
289
|
+
if (debug_mode)
|
290
|
+
fprintf(stderr, "end state = %s, toktype = %s\n",
|
291
|
+
rfh_state_to_s(state), rfh_toktype_to_s(toktype));
|
292
|
+
}
|
293
|
+
|
294
|
+
*charpp = charp;
|
295
|
+
|
296
|
+
if (debug_mode)
|
297
|
+
fprintf(stderr, "-- leaving; end state = %s, returned toktype = %s, returned token = [%s]\n",
|
298
|
+
rfh_state_to_s(state), rfh_toktype_to_s(toktype), token);
|
299
|
+
|
300
|
+
return toktype;
|
301
|
+
}
|
302
|
+
|
303
|
+
rfh_toktype_t rfh_decode_name_val_str(const char *nvstr, size_t len, CALLBACK_FN callback, void *user_data)
|
304
|
+
{
|
305
|
+
#if defined(USE_FIXED_BUFFERS)
|
306
|
+
char name[MAX_TOK_LEN + 1];
|
307
|
+
char value[MAX_TOK_LEN + 1];
|
308
|
+
size_t name_len = sizeof(name);
|
309
|
+
size_t value_len = sizeof(value);
|
310
|
+
#else
|
311
|
+
size_t name_len = len + 1;
|
312
|
+
size_t value_len = len + 1;
|
313
|
+
char *buf = (char *)malloc(len * 2 * sizeof(char) + 2);
|
314
|
+
char *name = buf;
|
315
|
+
char *value = buf + len + 1;
|
316
|
+
#endif
|
317
|
+
|
318
|
+
const char *charp = nvstr, *endp = nvstr + len;
|
319
|
+
rfh_toktype_t toktype;
|
320
|
+
|
321
|
+
#if !defined(USE_FIXED_BUFFERS)
|
322
|
+
if (buf == NULL) /* Out of mem */
|
323
|
+
return TT_ALLOC_FAILURE;
|
324
|
+
#endif
|
325
|
+
|
326
|
+
for (;;)
|
327
|
+
{
|
328
|
+
if ((toktype = get_token(&charp, endp, name, name + name_len)) != TT_TOKEN)
|
329
|
+
{
|
330
|
+
break;
|
331
|
+
}
|
332
|
+
|
333
|
+
if ((toktype = get_token(&charp, endp, value, value + value_len)) != TT_TOKEN)
|
334
|
+
{
|
335
|
+
if (toktype == TT_END) /* Expected a value! */
|
336
|
+
toktype = TT_UNEXPECTED_EOS;
|
337
|
+
break;
|
338
|
+
}
|
339
|
+
|
340
|
+
callback(name, value, user_data);
|
341
|
+
}
|
342
|
+
|
343
|
+
#if !defined(USE_FIXED_BUFFERS)
|
344
|
+
free(buf);
|
345
|
+
#endif
|
346
|
+
|
347
|
+
return toktype;
|
348
|
+
}
|
data/ext/decode_rfh.h
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright 2007 Edwin M. Fine, Fine Computer Consultants, Inc.
|
3
|
+
*
|
4
|
+
* Licensed under the Apache License, Version 2.0
|
5
|
+
* (the "License"); you may not use this file except
|
6
|
+
* in compliance with the License. You may obtain a copy
|
7
|
+
* of the License at http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
* Unless required by applicable law or agreed to in writing,
|
9
|
+
* software distributed under the License is distributed on an
|
10
|
+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
11
|
+
* either express or implied. See the License for the specific
|
12
|
+
* language governing permissions and limitations under the License.
|
13
|
+
*/
|
14
|
+
#if !defined(DECODE_RFH_INCLUDED)
|
15
|
+
#define DECODE_RFH_INCLUDED
|
16
|
+
|
17
|
+
#include <stdlib.h> /* For size_t */
|
18
|
+
|
19
|
+
typedef void (*CALLBACK_FN)(const char *name, const char *value, void *user_data);
|
20
|
+
|
21
|
+
typedef enum {
|
22
|
+
TT_TOKEN,
|
23
|
+
TT_UNESCAPED_QUOTE, /* '"' not followed by '"' in quoted string */
|
24
|
+
TT_ILLEGAL_QUOTE, /* '"' in unquoted string */
|
25
|
+
TT_UNEXPECTED_EOS,
|
26
|
+
TT_TOKEN_TRUNCATED, /* Token buffer too short to receive full token */
|
27
|
+
TT_INTERNAL_ERROR,
|
28
|
+
TT_ALLOC_FAILURE,
|
29
|
+
TT_END
|
30
|
+
} rfh_toktype_t;
|
31
|
+
|
32
|
+
/* Returns TT_END on success, other on error */
|
33
|
+
rfh_toktype_t
|
34
|
+
rfh_decode_name_val_str(const char *nvstr,
|
35
|
+
size_t len,
|
36
|
+
CALLBACK_FN callback,
|
37
|
+
void *user_data);
|
38
|
+
|
39
|
+
/* Translates toktype_t to string */
|
40
|
+
const char *rfh_toktype_to_s(rfh_toktype_t toktype);
|
41
|
+
|
42
|
+
int rfh_in_debug_mode(void);
|
43
|
+
void rfh_set_debug_mode(int on_if_true);
|
44
|
+
|
45
|
+
#endif
|
data/ext/extconf.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'mkmf'
|
2
|
+
generate_sources_path = File.join(File.dirname(__FILE__), 'generate')
|
3
|
+
$LOAD_PATH.unshift generate_sources_path
|
4
|
+
require 'generate_reason'
|
5
|
+
require 'generate_const'
|
6
|
+
require 'generate_structs'
|
7
|
+
|
8
|
+
include_path = ''
|
9
|
+
if RUBY_PLATFORM =~ /win|mingw/i
|
10
|
+
include_path = 'C:\Program Files\IBM\WebSphere MQ\tools\c\include'
|
11
|
+
dir_config('mqm', include_path, '.')
|
12
|
+
else
|
13
|
+
include_path = '/opt/mqm/inc'
|
14
|
+
dir_config('mqm', include_path, '/opt/mqm/lib64')
|
15
|
+
end
|
16
|
+
|
17
|
+
have_header('cmqc.h')
|
18
|
+
|
19
|
+
# Check for WebSphere MQ Server library
|
20
|
+
unless (RUBY_PLATFORM =~ /win/i) || (RUBY_PLATFORM =~ /solaris/i) || (RUBY_PLATFORM =~ /linux/i)
|
21
|
+
have_library('mqm')
|
22
|
+
end
|
23
|
+
|
24
|
+
# Generate Source Files
|
25
|
+
GenerateReason.generate(include_path+'/')
|
26
|
+
GenerateConst.generate(include_path+'/', File.dirname(__FILE__) + '/../lib/wmq')
|
27
|
+
GenerateStructs.new(include_path+'/', generate_sources_path).generate
|
28
|
+
|
29
|
+
# Generate Makefile
|
30
|
+
create_makefile('wmq/wmq')
|
@@ -0,0 +1,24 @@
|
|
1
|
+
#
|
2
|
+
# NOTE: Do NOT use this file unless the platform being used is not supported
|
3
|
+
# directly by Ruby WMQ. Ruby WMQ already supports automatic dynamic loading on
|
4
|
+
# Windows, Solaris and Linux
|
5
|
+
#
|
6
|
+
require 'mkmf'
|
7
|
+
require '../../generate/generate_reason'
|
8
|
+
require '../../generate/generate_const'
|
9
|
+
require '../../generate/generate_structs'
|
10
|
+
|
11
|
+
include_path = ''
|
12
|
+
unless (RUBY_PLATFORM =~ /win/i) || (RUBY_PLATFORM =~ /solaris/i) || (RUBY_PLATFORM =~ /linux/i)
|
13
|
+
include_path = '/opt/mqm/inc'
|
14
|
+
dir_config('mqm', include_path, '/opt/mqm/lib')
|
15
|
+
have_library('mqic')
|
16
|
+
|
17
|
+
# Generate Source Files # Could check if not already present
|
18
|
+
GenerateReason.generate(include_path+'/')
|
19
|
+
GenerateConst.generate(include_path+'/', '../../lib/wmq')
|
20
|
+
GenerateStructs.new(include_path+'/', '../../generate').generate
|
21
|
+
|
22
|
+
have_header('cmqc.h')
|
23
|
+
create_makefile('wmq_client')
|
24
|
+
end
|