genx4r 0.04
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/CHANGES +31 -0
- data/LICENSE +22 -0
- data/README +31 -0
- data/TODO +6 -0
- data/ext/genx4r/MANIFEST +5 -0
- data/ext/genx4r/charProps.c +378 -0
- data/ext/genx4r/extconf.rb +5 -0
- data/ext/genx4r/genx.c +1940 -0
- data/ext/genx4r/genx.h +287 -0
- data/ext/genx4r/genx4r.c +584 -0
- data/genx4r.gemspec +29 -0
- data/setup.rb +1346 -0
- data/test/basics.rb +93 -0
- data/test/declare.rb +59 -0
- data/test/non-io.rb +41 -0
- metadata +55 -0
data/ext/genx4r/genx.h
ADDED
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
|
|
2
|
+
/*
|
|
3
|
+
* genx - C-callable library for generating XML documents
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/*
|
|
7
|
+
* Copyright (c) 2004 by Tim Bray and Sun Microsystems. For copying
|
|
8
|
+
* permission, see http://www.tbray.org/ongoing/genx/COPYING
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
#include <stdio.h>
|
|
12
|
+
|
|
13
|
+
#ifdef __cplusplus
|
|
14
|
+
extern "C" {
|
|
15
|
+
#endif
|
|
16
|
+
|
|
17
|
+
/*
|
|
18
|
+
* Note on error handling: genx routines mostly return
|
|
19
|
+
* GENX_SUCCESS (guaranteed to be zero) in normal circumstances, one of
|
|
20
|
+
* these other GENX_ values on a memory allocation or I/O failure or if the
|
|
21
|
+
* call would result in non-well-formed output.
|
|
22
|
+
* You can associate an error message with one of these codes explicitly
|
|
23
|
+
* or with the most recent error using genxGetErrorMessage() and
|
|
24
|
+
* genxLastErrorMessage(); see below.
|
|
25
|
+
*/
|
|
26
|
+
typedef enum
|
|
27
|
+
{
|
|
28
|
+
GENX_SUCCESS = 0,
|
|
29
|
+
GENX_BAD_UTF8,
|
|
30
|
+
GENX_NON_XML_CHARACTER,
|
|
31
|
+
GENX_BAD_NAME,
|
|
32
|
+
GENX_ALLOC_FAILED,
|
|
33
|
+
GENX_BAD_NAMESPACE_NAME,
|
|
34
|
+
GENX_INTERNAL_ERROR,
|
|
35
|
+
GENX_DUPLICATE_PREFIX,
|
|
36
|
+
GENX_SEQUENCE_ERROR,
|
|
37
|
+
GENX_NO_START_TAG,
|
|
38
|
+
GENX_IO_ERROR,
|
|
39
|
+
GENX_MISSING_VALUE,
|
|
40
|
+
GENX_MALFORMED_COMMENT,
|
|
41
|
+
GENX_XML_PI_TARGET,
|
|
42
|
+
GENX_MALFORMED_PI,
|
|
43
|
+
GENX_DUPLICATE_ATTRIBUTE,
|
|
44
|
+
GENX_ATTRIBUTE_IN_DEFAULT_NAMESPACE,
|
|
45
|
+
GENX_DUPLICATE_NAMESPACE,
|
|
46
|
+
GENX_BAD_DEFAULT_DECLARATION
|
|
47
|
+
} genxStatus;
|
|
48
|
+
|
|
49
|
+
/* character types */
|
|
50
|
+
#define GENX_XML_CHAR 1
|
|
51
|
+
#define GENX_LETTER 2
|
|
52
|
+
#define GENX_NAMECHAR 4
|
|
53
|
+
|
|
54
|
+
/* a UTF-8 string */
|
|
55
|
+
typedef unsigned char * utf8;
|
|
56
|
+
typedef const unsigned char * constUtf8;
|
|
57
|
+
|
|
58
|
+
/*
|
|
59
|
+
* genx's own types
|
|
60
|
+
*/
|
|
61
|
+
typedef struct genxWriter_rec * genxWriter;
|
|
62
|
+
typedef struct genxNamespace_rec * genxNamespace;
|
|
63
|
+
typedef struct genxElement_rec * genxElement;
|
|
64
|
+
typedef struct genxAttribute_rec * genxAttribute;
|
|
65
|
+
|
|
66
|
+
/*
|
|
67
|
+
* Constructors, set/get
|
|
68
|
+
*/
|
|
69
|
+
|
|
70
|
+
/*
|
|
71
|
+
* Create a new writer. For generating multiple XML documents, it's most
|
|
72
|
+
* efficient to re-use the same genx object. However, you can only write
|
|
73
|
+
* one document at a time with a writer.
|
|
74
|
+
* Returns NULL if it fails, which can only be due to an allocation failure.
|
|
75
|
+
*/
|
|
76
|
+
genxWriter genxNew(void * (*alloc)(void * userData, int bytes),
|
|
77
|
+
void (* dealloc)(void * userData, void * data),
|
|
78
|
+
void * userData);
|
|
79
|
+
|
|
80
|
+
/*
|
|
81
|
+
* Dispose of a writer, freeing all associated memory
|
|
82
|
+
*/
|
|
83
|
+
void genxDispose(genxWriter w);
|
|
84
|
+
|
|
85
|
+
/*
|
|
86
|
+
* Set/get
|
|
87
|
+
*/
|
|
88
|
+
|
|
89
|
+
/*
|
|
90
|
+
* The userdata pointer will be passed to memory-allocation
|
|
91
|
+
* and I/O callbacks. If not set, genx will pass NULL
|
|
92
|
+
*/
|
|
93
|
+
void genxSetUserData(genxWriter w, void * userData);
|
|
94
|
+
void * genxGetUserData(genxWriter w);
|
|
95
|
+
|
|
96
|
+
/*
|
|
97
|
+
* User-provided memory allocator, if desired. For example, if you were
|
|
98
|
+
* in an Apache module, you could arrange for genx to use ap_palloc by
|
|
99
|
+
* making the pool accessible via the userData call.
|
|
100
|
+
* The "dealloc" is to be used to free memory allocated with "alloc". If
|
|
101
|
+
* alloc is provided but dealloc is NULL, genx will not attempt to free
|
|
102
|
+
* the memory; this would be appropriate in an Apache context.
|
|
103
|
+
* If "alloc" is not provided, genx routines use malloc() to allocate memory
|
|
104
|
+
*/
|
|
105
|
+
void genxSetAlloc(genxWriter w,
|
|
106
|
+
void * (* alloc)(void * userData, int bytes));
|
|
107
|
+
void genxSetDealloc(genxWriter w,
|
|
108
|
+
void (* dealloc)(void * userData, void * data));
|
|
109
|
+
void * (* genxGetAlloc(genxWriter w))(void * userData, int bytes);
|
|
110
|
+
void (* genxGetDealloc(genxWriter w))(void * userData, void * data);
|
|
111
|
+
|
|
112
|
+
/*
|
|
113
|
+
* Get the prefix associated with a namespace
|
|
114
|
+
*/
|
|
115
|
+
utf8 genxGetNamespacePrefix(genxNamespace ns);
|
|
116
|
+
|
|
117
|
+
/*
|
|
118
|
+
* Declaration functions
|
|
119
|
+
*/
|
|
120
|
+
|
|
121
|
+
/*
|
|
122
|
+
* Declare a namespace. The provided prefix is the default but can be
|
|
123
|
+
* overridden by genxAddNamespace. If no default prefiix is provided,
|
|
124
|
+
* genx will generate one of the form g-%d.
|
|
125
|
+
* On error, returns NULL and signals via statusp
|
|
126
|
+
*/
|
|
127
|
+
genxNamespace genxDeclareNamespace(genxWriter w,
|
|
128
|
+
constUtf8 uri, constUtf8 prefix,
|
|
129
|
+
genxStatus * statusP);
|
|
130
|
+
|
|
131
|
+
/*
|
|
132
|
+
* Declare an element
|
|
133
|
+
* If something failed, returns NULL and sets the status code via statusP
|
|
134
|
+
*/
|
|
135
|
+
genxElement genxDeclareElement(genxWriter w,
|
|
136
|
+
genxNamespace ns, constUtf8 type,
|
|
137
|
+
genxStatus * statusP);
|
|
138
|
+
|
|
139
|
+
/*
|
|
140
|
+
* Declare an attribute
|
|
141
|
+
*/
|
|
142
|
+
genxAttribute genxDeclareAttribute(genxWriter w,
|
|
143
|
+
genxNamespace ns,
|
|
144
|
+
constUtf8 name, genxStatus * statusP);
|
|
145
|
+
|
|
146
|
+
/*
|
|
147
|
+
* Writing XML
|
|
148
|
+
*/
|
|
149
|
+
|
|
150
|
+
/*
|
|
151
|
+
* Start a new document.
|
|
152
|
+
*/
|
|
153
|
+
genxStatus genxStartDocFile(genxWriter w, FILE * file);
|
|
154
|
+
|
|
155
|
+
/*
|
|
156
|
+
* Caller-provided I/O package.
|
|
157
|
+
* First form is for a null-terminated string.
|
|
158
|
+
* for second, if you have s="abcdef" and want to send "abc", you'd call
|
|
159
|
+
* sendBounded(userData, s, s + 3)
|
|
160
|
+
*/
|
|
161
|
+
typedef struct
|
|
162
|
+
{
|
|
163
|
+
genxStatus (* send)(void * userData, constUtf8 s);
|
|
164
|
+
genxStatus (* sendBounded)(void * userData, constUtf8 start, constUtf8 end);
|
|
165
|
+
genxStatus (* flush)(void * userData);
|
|
166
|
+
} genxSender;
|
|
167
|
+
|
|
168
|
+
genxStatus genxStartDocSender(genxWriter w, genxSender * sender);
|
|
169
|
+
|
|
170
|
+
/*
|
|
171
|
+
* End a document. Calls "flush"
|
|
172
|
+
*/
|
|
173
|
+
genxStatus genxEndDocument(genxWriter w);
|
|
174
|
+
|
|
175
|
+
/*
|
|
176
|
+
* Write a comment
|
|
177
|
+
*/
|
|
178
|
+
genxStatus genxComment(genxWriter w, constUtf8 text);
|
|
179
|
+
|
|
180
|
+
/*
|
|
181
|
+
* Write a PI
|
|
182
|
+
*/
|
|
183
|
+
genxStatus genxPI(genxWriter w, constUtf8 target, constUtf8 text);
|
|
184
|
+
|
|
185
|
+
/*
|
|
186
|
+
* Start an element
|
|
187
|
+
*/
|
|
188
|
+
genxStatus genxStartElementLiteral(genxWriter w,
|
|
189
|
+
constUtf8 xmlns, constUtf8 type);
|
|
190
|
+
|
|
191
|
+
/*
|
|
192
|
+
* Start a predeclared element
|
|
193
|
+
* - element must have been declared
|
|
194
|
+
*/
|
|
195
|
+
genxStatus genxStartElement(genxElement e);
|
|
196
|
+
|
|
197
|
+
/*
|
|
198
|
+
* Write an attribute
|
|
199
|
+
*/
|
|
200
|
+
genxStatus genxAddAttributeLiteral(genxWriter w, constUtf8 xmlns,
|
|
201
|
+
constUtf8 name, constUtf8 value);
|
|
202
|
+
|
|
203
|
+
/*
|
|
204
|
+
* Write a predeclared attribute
|
|
205
|
+
*/
|
|
206
|
+
genxStatus genxAddAttribute(genxAttribute a, constUtf8 value);
|
|
207
|
+
|
|
208
|
+
/*
|
|
209
|
+
* add a namespace declaration
|
|
210
|
+
*/
|
|
211
|
+
genxStatus genxAddNamespace(genxNamespace ns, utf8 prefix);
|
|
212
|
+
|
|
213
|
+
/*
|
|
214
|
+
* Clear default namespace declaration
|
|
215
|
+
*/
|
|
216
|
+
genxStatus genxUnsetDefaultNamespace(genxWriter w);
|
|
217
|
+
|
|
218
|
+
/*
|
|
219
|
+
* Write an end tag
|
|
220
|
+
*/
|
|
221
|
+
genxStatus genxEndElement(genxWriter w);
|
|
222
|
+
|
|
223
|
+
/*
|
|
224
|
+
* Write some text
|
|
225
|
+
* You can't write any text outside the root element, except with
|
|
226
|
+
* genxComment and genxPI
|
|
227
|
+
*/
|
|
228
|
+
genxStatus genxAddText(genxWriter w, constUtf8 start);
|
|
229
|
+
genxStatus genxAddCountedText(genxWriter w, constUtf8 start, int byteCount);
|
|
230
|
+
genxStatus genxAddBoundedText(genxWriter w, constUtf8 start, constUtf8 end);
|
|
231
|
+
|
|
232
|
+
/*
|
|
233
|
+
* Write one character. The integer value is the Unicode character
|
|
234
|
+
* value, as usually expressed in U+XXXX notation.
|
|
235
|
+
*/
|
|
236
|
+
genxStatus genxAddCharacter(genxWriter w, int c);
|
|
237
|
+
|
|
238
|
+
/*
|
|
239
|
+
* Utility routines
|
|
240
|
+
*/
|
|
241
|
+
|
|
242
|
+
/*
|
|
243
|
+
* Return the Unicode character encoded by the UTF-8 pointed-to by the
|
|
244
|
+
* argument, and advance the argument past the encoding of the character.
|
|
245
|
+
* Returns -1 if the UTF-8 is malformed, in which case advances the
|
|
246
|
+
* argument to point at the first byte past the point past the malformed
|
|
247
|
+
* ones.
|
|
248
|
+
*/
|
|
249
|
+
int genxNextUnicodeChar(constUtf8 * sp);
|
|
250
|
+
|
|
251
|
+
/*
|
|
252
|
+
* Scan a buffer allegedly full of UTF-8 encoded XML characters; return
|
|
253
|
+
* one of GENX_SUCCESS, GENX_BAD_UTF8, or GENX_NON_XML_CHARACTER
|
|
254
|
+
*/
|
|
255
|
+
genxStatus genxCheckText(genxWriter w, constUtf8 s);
|
|
256
|
+
|
|
257
|
+
/*
|
|
258
|
+
* return character status, the OR of GENX_XML_CHAR,
|
|
259
|
+
* GENX_LETTER, and GENX_NAMECHAR
|
|
260
|
+
*/
|
|
261
|
+
int genxCharClass(genxWriter w, int c);
|
|
262
|
+
|
|
263
|
+
/*
|
|
264
|
+
* Silently wipe any non-XML characters out of a chunk of text.
|
|
265
|
+
* If you call this on a string before you pass it addText or
|
|
266
|
+
* addAttribute, you will never get an error from genx unless
|
|
267
|
+
* (a) there's a bug in your software, e.g. a malformed element name, or
|
|
268
|
+
* (b) there's a memory allocation or I/O error
|
|
269
|
+
* The output can never be longer than the input.
|
|
270
|
+
* Returns true if any changes were made.
|
|
271
|
+
*/
|
|
272
|
+
int genxScrubText(genxWriter w, constUtf8 in, utf8 out);
|
|
273
|
+
|
|
274
|
+
/*
|
|
275
|
+
* return error messages
|
|
276
|
+
*/
|
|
277
|
+
char * genxGetErrorMessage(genxWriter w, genxStatus status);
|
|
278
|
+
char * genxLastErrorMessage(genxWriter w);
|
|
279
|
+
|
|
280
|
+
/*
|
|
281
|
+
* return version
|
|
282
|
+
*/
|
|
283
|
+
char * genxGetVersion();
|
|
284
|
+
|
|
285
|
+
#ifdef __cplusplus
|
|
286
|
+
}
|
|
287
|
+
#endif
|
data/ext/genx4r/genx4r.c
ADDED
|
@@ -0,0 +1,584 @@
|
|
|
1
|
+
/* Copyright (c) 2004 Garrett Rooney
|
|
2
|
+
*
|
|
3
|
+
* Permission is hereby granted, free of charge, to any person obtaining
|
|
4
|
+
* a copy of this software and associated documentation files (the
|
|
5
|
+
* "Software"), to deal in the Software without restriction, including
|
|
6
|
+
* without limitation the rights to use, copy, modify, merge, publish,
|
|
7
|
+
* distribute, sublicense, and/or sell copies of the Software, and to
|
|
8
|
+
* permit persons to whom the Software is furnished to do so, subject to
|
|
9
|
+
* the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included
|
|
12
|
+
* in all copies or substantial portions of the Software.
|
|
13
|
+
*
|
|
14
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
|
15
|
+
* KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
|
16
|
+
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
|
+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
|
+
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
19
|
+
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
20
|
+
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
|
21
|
+
|
|
22
|
+
/* $Id: genx4r.c 278 2004-07-26 13:09:20Z rooneg $ */
|
|
23
|
+
|
|
24
|
+
#include "ruby.h"
|
|
25
|
+
|
|
26
|
+
#include "genx.h"
|
|
27
|
+
|
|
28
|
+
static VALUE rb_mGenX;
|
|
29
|
+
static VALUE rb_cGenXWriter;
|
|
30
|
+
|
|
31
|
+
static VALUE rb_cGenXNamespace;
|
|
32
|
+
static VALUE rb_cGenXAttribute;
|
|
33
|
+
static VALUE rb_cGenXElement;
|
|
34
|
+
|
|
35
|
+
static VALUE rb_cGenXException;
|
|
36
|
+
|
|
37
|
+
static void
|
|
38
|
+
writer_mark (genxWriter w)
|
|
39
|
+
{}
|
|
40
|
+
|
|
41
|
+
static void
|
|
42
|
+
writer_free (genxWriter w)
|
|
43
|
+
{
|
|
44
|
+
genxDispose (w);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
#define GENX4R_ERR(expr, w) \
|
|
48
|
+
do { \
|
|
49
|
+
genxStatus genx4r__status = (expr); \
|
|
50
|
+
if (genx4r__status) \
|
|
51
|
+
rb_raise (rb_cGenXException, "%s", genxLastErrorMessage (w)); \
|
|
52
|
+
} while (0)
|
|
53
|
+
|
|
54
|
+
static VALUE
|
|
55
|
+
call_write (VALUE ary)
|
|
56
|
+
{
|
|
57
|
+
rb_funcall (rb_ary_entry (ary, 0),
|
|
58
|
+
rb_intern ("<<"),
|
|
59
|
+
1,
|
|
60
|
+
rb_ary_entry (ary, 1));
|
|
61
|
+
|
|
62
|
+
return Qtrue;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
static VALUE
|
|
66
|
+
call_flush (VALUE file)
|
|
67
|
+
{
|
|
68
|
+
rb_funcall (file, rb_intern ("flush"), 0);
|
|
69
|
+
|
|
70
|
+
return Qtrue;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
static VALUE
|
|
74
|
+
handle_exception (VALUE unused)
|
|
75
|
+
{
|
|
76
|
+
return Qfalse;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
static genxStatus
|
|
80
|
+
writer_send (void *baton, constUtf8 s)
|
|
81
|
+
{
|
|
82
|
+
VALUE file = (VALUE) baton;
|
|
83
|
+
VALUE ary;
|
|
84
|
+
|
|
85
|
+
if (! rb_respond_to (file, rb_intern ("<<")))
|
|
86
|
+
rb_raise (rb_eRuntimeError, "target must respond to '<<'");
|
|
87
|
+
|
|
88
|
+
ary = rb_ary_new2 (2);
|
|
89
|
+
|
|
90
|
+
rb_ary_store (ary, 0, file);
|
|
91
|
+
rb_ary_store (ary, 1, rb_str_new2 (s));
|
|
92
|
+
|
|
93
|
+
if (rb_rescue (call_write, ary, handle_exception, Qnil) == Qfalse)
|
|
94
|
+
return GENX_IO_ERROR;
|
|
95
|
+
else
|
|
96
|
+
return GENX_SUCCESS;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
static genxStatus
|
|
100
|
+
writer_send_bounded (void *baton, constUtf8 start, constUtf8 end)
|
|
101
|
+
{
|
|
102
|
+
VALUE file = (VALUE) baton;
|
|
103
|
+
VALUE ary;
|
|
104
|
+
|
|
105
|
+
if (! rb_respond_to (file, rb_intern ("<<")))
|
|
106
|
+
rb_raise (rb_eRuntimeError, "target must respond to '<<'");
|
|
107
|
+
|
|
108
|
+
ary = rb_ary_new2 (2);
|
|
109
|
+
|
|
110
|
+
rb_ary_store (ary, 0, file);
|
|
111
|
+
rb_ary_store (ary, 1, rb_str_new (start, end - start));
|
|
112
|
+
|
|
113
|
+
if (rb_rescue (call_write, ary, handle_exception, Qnil) == Qfalse)
|
|
114
|
+
return GENX_IO_ERROR;
|
|
115
|
+
else
|
|
116
|
+
return GENX_SUCCESS;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
static genxStatus
|
|
120
|
+
writer_flush (void *baton)
|
|
121
|
+
{
|
|
122
|
+
VALUE file = (VALUE) baton;
|
|
123
|
+
|
|
124
|
+
/* if we can't flush, just let it go... */
|
|
125
|
+
if (! rb_respond_to (file, rb_intern ("flush")))
|
|
126
|
+
return GENX_SUCCESS;
|
|
127
|
+
|
|
128
|
+
if (rb_rescue (call_flush, file, handle_exception, Qnil) == Qfalse)
|
|
129
|
+
return GENX_IO_ERROR;
|
|
130
|
+
else
|
|
131
|
+
return GENX_SUCCESS;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
static genxSender writer_sender = { writer_send,
|
|
135
|
+
writer_send_bounded,
|
|
136
|
+
writer_flush };
|
|
137
|
+
|
|
138
|
+
static VALUE
|
|
139
|
+
writer_begin_document (VALUE self, VALUE file)
|
|
140
|
+
{
|
|
141
|
+
genxWriter w;
|
|
142
|
+
|
|
143
|
+
Data_Get_Struct (self, struct genxWriter_rec, w);
|
|
144
|
+
|
|
145
|
+
if (! rb_respond_to (file, rb_intern ("<<")))
|
|
146
|
+
rb_raise (rb_eRuntimeError, "target must respond to '<<'");
|
|
147
|
+
|
|
148
|
+
genxSetUserData(w, (void *) file);
|
|
149
|
+
|
|
150
|
+
GENX4R_ERR (genxStartDocSender (w, &writer_sender), w);
|
|
151
|
+
|
|
152
|
+
return Qnil;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
static VALUE
|
|
156
|
+
writer_end_document (VALUE self)
|
|
157
|
+
{
|
|
158
|
+
genxWriter w;
|
|
159
|
+
|
|
160
|
+
Data_Get_Struct (self, struct genxWriter_rec, w);
|
|
161
|
+
|
|
162
|
+
GENX4R_ERR (genxEndDocument (w), w);
|
|
163
|
+
|
|
164
|
+
return Qnil;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
static VALUE
|
|
168
|
+
writer_document (VALUE self, VALUE file)
|
|
169
|
+
{
|
|
170
|
+
writer_begin_document (self, file);
|
|
171
|
+
|
|
172
|
+
if (rb_block_given_p ())
|
|
173
|
+
{
|
|
174
|
+
rb_yield (Qnil);
|
|
175
|
+
|
|
176
|
+
writer_end_document (self);
|
|
177
|
+
|
|
178
|
+
return Qnil;
|
|
179
|
+
}
|
|
180
|
+
else
|
|
181
|
+
rb_raise (rb_eRuntimeError, "must be called with a block");
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
static VALUE
|
|
185
|
+
writer_comment (VALUE self, VALUE arg)
|
|
186
|
+
{
|
|
187
|
+
genxWriter w;
|
|
188
|
+
|
|
189
|
+
Check_Type (arg, T_STRING);
|
|
190
|
+
|
|
191
|
+
Data_Get_Struct (self, struct genxWriter_rec, w);
|
|
192
|
+
|
|
193
|
+
GENX4R_ERR (genxComment (w, (constUtf8) RSTRING (arg)->ptr), w);
|
|
194
|
+
|
|
195
|
+
return Qnil;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
static VALUE
|
|
199
|
+
writer_attribute (int argc, VALUE *argv, VALUE self)
|
|
200
|
+
{
|
|
201
|
+
genxAttribute attr = 0;
|
|
202
|
+
genxWriter w;
|
|
203
|
+
VALUE xmlns, name, value;
|
|
204
|
+
int nslen = 0;
|
|
205
|
+
|
|
206
|
+
switch (argc)
|
|
207
|
+
{
|
|
208
|
+
case 2:
|
|
209
|
+
xmlns = 0;
|
|
210
|
+
if (CLASS_OF (argv[0]) == rb_cGenXAttribute)
|
|
211
|
+
{
|
|
212
|
+
Data_Get_Struct (argv[0], struct genxAttribute_rec, attr);
|
|
213
|
+
name = 0;
|
|
214
|
+
}
|
|
215
|
+
else
|
|
216
|
+
name = argv[0];
|
|
217
|
+
|
|
218
|
+
value = argv[1];
|
|
219
|
+
break;
|
|
220
|
+
|
|
221
|
+
case 3:
|
|
222
|
+
xmlns = argv[0];
|
|
223
|
+
name = argv[1];
|
|
224
|
+
value = argv[2];
|
|
225
|
+
break;
|
|
226
|
+
|
|
227
|
+
default:
|
|
228
|
+
rb_raise (rb_eRuntimeError, "invalid arguments");
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
if (xmlns)
|
|
232
|
+
{
|
|
233
|
+
Check_Type (xmlns, T_STRING);
|
|
234
|
+
nslen = RSTRING (xmlns)->len;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
if (name)
|
|
238
|
+
Check_Type (name, T_STRING);
|
|
239
|
+
|
|
240
|
+
Check_Type (value, T_STRING);
|
|
241
|
+
|
|
242
|
+
Data_Get_Struct (self, struct genxWriter_rec, w);
|
|
243
|
+
|
|
244
|
+
if (attr)
|
|
245
|
+
GENX4R_ERR (genxAddAttribute (attr, (constUtf8) RSTRING (value)->ptr), w);
|
|
246
|
+
else
|
|
247
|
+
GENX4R_ERR (genxAddAttributeLiteral
|
|
248
|
+
(w,
|
|
249
|
+
nslen ? (constUtf8) RSTRING (xmlns)->ptr : NULL,
|
|
250
|
+
(constUtf8) RSTRING (name)->ptr,
|
|
251
|
+
(constUtf8) RSTRING (value)->ptr), w);
|
|
252
|
+
|
|
253
|
+
return Qnil;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
static VALUE
|
|
257
|
+
writer_begin_element (int argc, VALUE *argv, VALUE self)
|
|
258
|
+
{
|
|
259
|
+
genxWriter w;
|
|
260
|
+
genxElement elem = 0;
|
|
261
|
+
VALUE xmlns, name;
|
|
262
|
+
int nslen = 0;
|
|
263
|
+
|
|
264
|
+
switch (argc)
|
|
265
|
+
{
|
|
266
|
+
case 1:
|
|
267
|
+
xmlns = 0;
|
|
268
|
+
if (CLASS_OF (argv[0]) == rb_cGenXElement)
|
|
269
|
+
{
|
|
270
|
+
Data_Get_Struct (argv[0], struct genxElement_rec, elem);
|
|
271
|
+
name = 0;
|
|
272
|
+
}
|
|
273
|
+
else
|
|
274
|
+
name = argv[0];
|
|
275
|
+
break;
|
|
276
|
+
|
|
277
|
+
case 2:
|
|
278
|
+
xmlns = argv[0];
|
|
279
|
+
name = argv[1];
|
|
280
|
+
break;
|
|
281
|
+
|
|
282
|
+
default:
|
|
283
|
+
rb_raise (rb_eRuntimeError, "invalid arguments");
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
if (xmlns)
|
|
287
|
+
{
|
|
288
|
+
Check_Type (xmlns, T_STRING);
|
|
289
|
+
nslen = RSTRING (xmlns)->len;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
if (name)
|
|
293
|
+
Check_Type (name, T_STRING);
|
|
294
|
+
|
|
295
|
+
Data_Get_Struct (self, struct genxWriter_rec, w);
|
|
296
|
+
|
|
297
|
+
if (elem)
|
|
298
|
+
GENX4R_ERR (genxStartElement (elem), w);
|
|
299
|
+
else
|
|
300
|
+
GENX4R_ERR (genxStartElementLiteral
|
|
301
|
+
(w,
|
|
302
|
+
nslen ? (constUtf8) RSTRING (xmlns)->ptr : NULL,
|
|
303
|
+
(constUtf8) RSTRING (name)->ptr), w);
|
|
304
|
+
|
|
305
|
+
return Qnil;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
static VALUE
|
|
309
|
+
writer_end_element (VALUE self)
|
|
310
|
+
{
|
|
311
|
+
genxWriter w;
|
|
312
|
+
|
|
313
|
+
Data_Get_Struct (self, struct genxWriter_rec, w);
|
|
314
|
+
|
|
315
|
+
GENX4R_ERR (genxEndElement (w), w);
|
|
316
|
+
|
|
317
|
+
return Qnil;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
static VALUE
|
|
321
|
+
writer_element (int argc, VALUE *argv, VALUE self)
|
|
322
|
+
{
|
|
323
|
+
writer_begin_element (argc, argv, self);
|
|
324
|
+
|
|
325
|
+
if (rb_block_given_p ())
|
|
326
|
+
{
|
|
327
|
+
rb_yield (Qnil);
|
|
328
|
+
|
|
329
|
+
writer_end_element (self);
|
|
330
|
+
|
|
331
|
+
return Qnil;
|
|
332
|
+
}
|
|
333
|
+
else
|
|
334
|
+
rb_raise (rb_eRuntimeError, "must be called with a block");
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
static VALUE
|
|
338
|
+
writer_pi (VALUE self, VALUE target, VALUE text)
|
|
339
|
+
{
|
|
340
|
+
genxWriter w;
|
|
341
|
+
|
|
342
|
+
Check_Type (target, T_STRING);
|
|
343
|
+
Check_Type (text, T_STRING);
|
|
344
|
+
|
|
345
|
+
Data_Get_Struct (self, struct genxWriter_rec, w);
|
|
346
|
+
|
|
347
|
+
GENX4R_ERR (genxPI (w,
|
|
348
|
+
(constUtf8) RSTRING (target)->ptr,
|
|
349
|
+
(constUtf8) RSTRING (text)->ptr), w);
|
|
350
|
+
|
|
351
|
+
return Qnil;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
static VALUE
|
|
355
|
+
writer_text (VALUE self, VALUE text)
|
|
356
|
+
{
|
|
357
|
+
genxWriter w;
|
|
358
|
+
|
|
359
|
+
Check_Type (text, T_STRING);
|
|
360
|
+
|
|
361
|
+
Data_Get_Struct (self, struct genxWriter_rec, w);
|
|
362
|
+
|
|
363
|
+
GENX4R_ERR (genxAddText (w, (constUtf8) RSTRING (text)->ptr), w);
|
|
364
|
+
|
|
365
|
+
return Qnil;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
static VALUE
|
|
369
|
+
writer_character (VALUE self, VALUE ch)
|
|
370
|
+
{
|
|
371
|
+
genxWriter w;
|
|
372
|
+
|
|
373
|
+
int c = NUM2INT (ch);
|
|
374
|
+
|
|
375
|
+
Data_Get_Struct (self, struct genxWriter_rec, w);
|
|
376
|
+
|
|
377
|
+
GENX4R_ERR (genxAddCharacter (w, c), w);
|
|
378
|
+
|
|
379
|
+
return Qnil;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
#if RUBY_VERSION_MAJOR >= 1 && RUBY_VERSION_MINOR >= 8
|
|
383
|
+
static VALUE
|
|
384
|
+
writer_allocate (VALUE klass)
|
|
385
|
+
{
|
|
386
|
+
genxWriter writer = genxNew (NULL, NULL, NULL);
|
|
387
|
+
|
|
388
|
+
return Data_Wrap_Struct (klass, writer_mark, writer_free, writer);
|
|
389
|
+
}
|
|
390
|
+
#else
|
|
391
|
+
static VALUE
|
|
392
|
+
writer_new (VALUE klass)
|
|
393
|
+
{
|
|
394
|
+
genxWriter writer = genxNew (NULL, NULL, NULL);
|
|
395
|
+
|
|
396
|
+
return Data_Wrap_Struct (klass, writer_mark, writer_free, writer);
|
|
397
|
+
}
|
|
398
|
+
#endif
|
|
399
|
+
|
|
400
|
+
static VALUE
|
|
401
|
+
writer_declare_namespace (int argc, VALUE *argv, VALUE self)
|
|
402
|
+
{
|
|
403
|
+
VALUE uri, prefix;
|
|
404
|
+
genxNamespace ns;
|
|
405
|
+
genxStatus st;
|
|
406
|
+
genxWriter w;
|
|
407
|
+
|
|
408
|
+
switch (argc)
|
|
409
|
+
{
|
|
410
|
+
case 1:
|
|
411
|
+
uri = argv[0];
|
|
412
|
+
prefix = 0;
|
|
413
|
+
break;
|
|
414
|
+
|
|
415
|
+
case 2:
|
|
416
|
+
uri = argv[0];
|
|
417
|
+
prefix = argv[1];
|
|
418
|
+
break;
|
|
419
|
+
|
|
420
|
+
default:
|
|
421
|
+
rb_raise (rb_eRuntimeError, "invalid arguments");
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
Check_Type (uri, T_STRING);
|
|
425
|
+
if (prefix)
|
|
426
|
+
Check_Type (prefix, T_STRING);
|
|
427
|
+
|
|
428
|
+
Data_Get_Struct (self, struct genxWriter_rec, w);
|
|
429
|
+
|
|
430
|
+
ns = genxDeclareNamespace (w,
|
|
431
|
+
(constUtf8) RSTRING (uri)->ptr,
|
|
432
|
+
prefix ? (constUtf8) RSTRING (prefix)->ptr : NULL,
|
|
433
|
+
&st);
|
|
434
|
+
|
|
435
|
+
if (st)
|
|
436
|
+
rb_raise (rb_cGenXException, "%s", genxLastErrorMessage (w));
|
|
437
|
+
|
|
438
|
+
return Data_Wrap_Struct (rb_cGenXNamespace, NULL, NULL, ns);
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
static VALUE
|
|
442
|
+
writer_declare_element (int argc, VALUE *argv, VALUE self)
|
|
443
|
+
{
|
|
444
|
+
genxNamespace ns = 0;
|
|
445
|
+
genxElement elem;
|
|
446
|
+
genxStatus st;
|
|
447
|
+
genxWriter w;
|
|
448
|
+
VALUE name;
|
|
449
|
+
|
|
450
|
+
switch (argc)
|
|
451
|
+
{
|
|
452
|
+
case 1:
|
|
453
|
+
name = argv[0];
|
|
454
|
+
break;
|
|
455
|
+
|
|
456
|
+
case 2:
|
|
457
|
+
if (CLASS_OF (argv[0]) == rb_cGenXNamespace) {
|
|
458
|
+
Data_Get_Struct (argv[0], struct genxNamespace_rec, ns);
|
|
459
|
+
} else {
|
|
460
|
+
rb_raise (rb_eRuntimeError, "invalid arguments");
|
|
461
|
+
}
|
|
462
|
+
name = argv[1];
|
|
463
|
+
break;
|
|
464
|
+
|
|
465
|
+
default:
|
|
466
|
+
rb_raise (rb_eRuntimeError, "invalid arguments");
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
Check_Type (name, T_STRING);
|
|
470
|
+
|
|
471
|
+
Data_Get_Struct (self, struct genxWriter_rec, w);
|
|
472
|
+
|
|
473
|
+
elem = genxDeclareElement (w, ns, RSTRING (name)->ptr, &st);
|
|
474
|
+
if (st)
|
|
475
|
+
rb_raise (rb_cGenXException, "%s", genxLastErrorMessage (w));
|
|
476
|
+
|
|
477
|
+
return Data_Wrap_Struct (rb_cGenXElement, NULL, NULL, elem);
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
static VALUE
|
|
481
|
+
writer_declare_attribute (int argc, VALUE *argv, VALUE self)
|
|
482
|
+
{
|
|
483
|
+
genxNamespace ns = 0;
|
|
484
|
+
genxAttribute attr;
|
|
485
|
+
genxStatus st;
|
|
486
|
+
genxWriter w;
|
|
487
|
+
VALUE name;
|
|
488
|
+
|
|
489
|
+
switch (argc)
|
|
490
|
+
{
|
|
491
|
+
case 1:
|
|
492
|
+
name = argv[0];
|
|
493
|
+
break;
|
|
494
|
+
|
|
495
|
+
case 2:
|
|
496
|
+
if (CLASS_OF (argv[0]) == rb_cGenXNamespace) {
|
|
497
|
+
Data_Get_Struct (argv[0], struct genxNamespace_rec, ns);
|
|
498
|
+
} else {
|
|
499
|
+
rb_raise (rb_eRuntimeError, "invalid arguments");
|
|
500
|
+
}
|
|
501
|
+
name = argv[1];
|
|
502
|
+
break;
|
|
503
|
+
|
|
504
|
+
default:
|
|
505
|
+
rb_raise (rb_eRuntimeError, "invalid arguments");
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
Check_Type (name, T_STRING);
|
|
509
|
+
|
|
510
|
+
Data_Get_Struct (self, struct genxWriter_rec, w);
|
|
511
|
+
|
|
512
|
+
attr = genxDeclareAttribute (w, ns, RSTRING (name)->ptr, &st);
|
|
513
|
+
if (st)
|
|
514
|
+
rb_raise (rb_cGenXException, "%s", genxLastErrorMessage (w));
|
|
515
|
+
|
|
516
|
+
return Data_Wrap_Struct (rb_cGenXAttribute, NULL, NULL, attr);
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
void
|
|
520
|
+
Init_genx4r ()
|
|
521
|
+
{
|
|
522
|
+
rb_mGenX = rb_define_module ("GenX");
|
|
523
|
+
|
|
524
|
+
rb_cGenXWriter = rb_define_class_under (rb_mGenX, "Writer", rb_cObject);
|
|
525
|
+
|
|
526
|
+
#if RUBY_VERSION_MAJOR >= 1 && RUBY_VERSION_MINOR >= 8
|
|
527
|
+
rb_define_alloc_func (rb_cGenXWriter, writer_allocate);
|
|
528
|
+
#else
|
|
529
|
+
rb_define_singleton_method(rb_cGenXWriter, "new", writer_new, 0);
|
|
530
|
+
#endif
|
|
531
|
+
|
|
532
|
+
rb_define_method (rb_cGenXWriter, "document", writer_document, 1);
|
|
533
|
+
|
|
534
|
+
rb_define_method (rb_cGenXWriter,
|
|
535
|
+
"begin_document",
|
|
536
|
+
writer_begin_document,
|
|
537
|
+
1);
|
|
538
|
+
|
|
539
|
+
rb_define_method (rb_cGenXWriter,
|
|
540
|
+
"end_document",
|
|
541
|
+
writer_end_document,
|
|
542
|
+
0);
|
|
543
|
+
|
|
544
|
+
rb_define_method (rb_cGenXWriter, "comment", writer_comment, 1);
|
|
545
|
+
rb_define_method (rb_cGenXWriter, "pi", writer_pi, 2);
|
|
546
|
+
|
|
547
|
+
rb_define_method (rb_cGenXWriter, "element", writer_element, -1);
|
|
548
|
+
|
|
549
|
+
rb_define_method (rb_cGenXWriter, "begin_element", writer_begin_element, -1);
|
|
550
|
+
rb_define_method (rb_cGenXWriter, "end_element", writer_end_element, 0);
|
|
551
|
+
|
|
552
|
+
rb_define_method (rb_cGenXWriter, "attribute", writer_attribute, -1);
|
|
553
|
+
rb_define_method (rb_cGenXWriter, "text", writer_text, 1);
|
|
554
|
+
rb_define_method (rb_cGenXWriter, "character", writer_character, 1);
|
|
555
|
+
|
|
556
|
+
rb_define_method (rb_cGenXWriter,
|
|
557
|
+
"declare_namespace",
|
|
558
|
+
writer_declare_namespace,
|
|
559
|
+
-1);
|
|
560
|
+
|
|
561
|
+
rb_define_method (rb_cGenXWriter,
|
|
562
|
+
"declare_element",
|
|
563
|
+
writer_declare_element,
|
|
564
|
+
-1);
|
|
565
|
+
|
|
566
|
+
rb_define_method (rb_cGenXWriter,
|
|
567
|
+
"declare_attribute",
|
|
568
|
+
writer_declare_attribute,
|
|
569
|
+
-1);
|
|
570
|
+
|
|
571
|
+
rb_cGenXNamespace = rb_define_class_under (rb_mGenX,
|
|
572
|
+
"Namespace",
|
|
573
|
+
rb_cObject);
|
|
574
|
+
|
|
575
|
+
rb_cGenXElement = rb_define_class_under (rb_mGenX, "Element", rb_cObject);
|
|
576
|
+
|
|
577
|
+
rb_cGenXAttribute = rb_define_class_under (rb_mGenX,
|
|
578
|
+
"Attribute",
|
|
579
|
+
rb_cObject);
|
|
580
|
+
|
|
581
|
+
rb_cGenXException = rb_define_class_under (rb_mGenX,
|
|
582
|
+
"Exception",
|
|
583
|
+
rb_eStandardError);
|
|
584
|
+
}
|