rubywmq 1.0.0 → 1.1.1
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 +1 -1
- data/examples/put1_a.rb +25 -25
- data/examples/q_to_files.rb +48 -48
- data/ext/build.sh +0 -0
- data/ext/decode_rfh.c +348 -348
- data/ext/decode_rfh.h +45 -45
- data/ext/extconf.rb +44 -44
- data/ext/generate/generate_structs.rb +97 -97
- data/ext/generate/wmq_structs.erb +1 -18
- data/ext/wmq.c +93 -93
- data/ext/wmq.h +367 -350
- data/ext/wmq_message.c +671 -682
- data/ext/wmq_mq_load.c +217 -217
- data/ext/wmq_queue.c +1411 -1411
- data/ext/wmq_queue_manager.c +1570 -1581
- data/tests/test.rb +328 -300
- metadata +46 -47
data/ext/decode_rfh.c
CHANGED
@@ -1,348 +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
|
-
}
|
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
|
+
}
|