syck 1.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/.autotest.erb +8 -0
- data/.gemtest +0 -0
- data/CHANGELOG.rdoc +6 -0
- data/Manifest.txt +52 -0
- data/README.rdoc +51 -0
- data/Rakefile +32 -0
- data/ext/syck/bytecode.c +1165 -0
- data/ext/syck/emitter.c +1247 -0
- data/ext/syck/extconf.h +3 -0
- data/ext/syck/extconf.rb +5 -0
- data/ext/syck/gram.c +1894 -0
- data/ext/syck/gram.h +79 -0
- data/ext/syck/handler.c +173 -0
- data/ext/syck/implicit.c +2990 -0
- data/ext/syck/node.c +407 -0
- data/ext/syck/rubyext.c +2328 -0
- data/ext/syck/syck.c +524 -0
- data/ext/syck/syck.h +453 -0
- data/ext/syck/token.c +2724 -0
- data/ext/syck/yaml2byte.c +259 -0
- data/ext/syck/yamlbyte.h +171 -0
- data/lib/syck.bundle +0 -0
- data/lib/syck.rb +447 -0
- data/lib/syck/baseemitter.rb +242 -0
- data/lib/syck/basenode.rb +222 -0
- data/lib/syck/constants.rb +45 -0
- data/lib/syck/encoding.rb +35 -0
- data/lib/syck/error.rb +34 -0
- data/lib/syck/loader.rb +14 -0
- data/lib/syck/rubytypes.rb +450 -0
- data/lib/syck/stream.rb +41 -0
- data/lib/syck/stringio.rb +85 -0
- data/lib/syck/syck.rb +16 -0
- data/lib/syck/tag.rb +95 -0
- data/lib/syck/types.rb +192 -0
- data/lib/syck/yamlnode.rb +54 -0
- data/lib/syck/ypath.rb +54 -0
- data/lib/yaml/syck.rb +14 -0
- data/test/helper.rb +2 -0
- data/test/test_array.rb +13 -0
- data/test/test_boolean.rb +36 -0
- data/test/test_class.rb +11 -0
- data/test/test_exception.rb +45 -0
- data/test/test_hash.rb +24 -0
- data/test/test_null.rb +19 -0
- data/test/test_omap.rb +55 -0
- data/test/test_set.rb +30 -0
- data/test/test_string.rb +44 -0
- data/test/test_struct.rb +32 -0
- data/test/test_symbol.rb +21 -0
- data/test/test_time.rb +23 -0
- data/test/test_yaml.rb +1403 -0
- data/test/test_yaml_properties.rb +63 -0
- metadata +187 -0
data/ext/syck/emitter.c
ADDED
@@ -0,0 +1,1247 @@
|
|
1
|
+
/*
|
2
|
+
* emitter.c
|
3
|
+
*
|
4
|
+
* $Author$
|
5
|
+
*
|
6
|
+
* Copyright (C) 2003 why the lucky stiff
|
7
|
+
*
|
8
|
+
* All Base64 code from Ruby's pack.c.
|
9
|
+
* Ruby is Copyright (C) 1993-2007 Yukihiro Matsumoto
|
10
|
+
*/
|
11
|
+
#include "ruby/ruby.h"
|
12
|
+
|
13
|
+
#include <stdio.h>
|
14
|
+
#include <string.h>
|
15
|
+
|
16
|
+
#include "syck.h"
|
17
|
+
|
18
|
+
#define DEFAULT_ANCHOR_FORMAT "id%03d"
|
19
|
+
|
20
|
+
const char hex_table[] =
|
21
|
+
"0123456789ABCDEF";
|
22
|
+
static char b64_table[] =
|
23
|
+
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
24
|
+
|
25
|
+
/*
|
26
|
+
* Built-in base64 (from Ruby's pack.c)
|
27
|
+
*/
|
28
|
+
char *
|
29
|
+
syck_base64enc( char *s, long len )
|
30
|
+
{
|
31
|
+
long i = 0;
|
32
|
+
int padding = '=';
|
33
|
+
char *buff = S_ALLOC_N(char, len * 4 / 3 + 6);
|
34
|
+
|
35
|
+
while (len >= 3) {
|
36
|
+
buff[i++] = b64_table[077 & (*s >> 2)];
|
37
|
+
buff[i++] = b64_table[077 & (((*s << 4) & 060) | ((s[1] >> 4) & 017))];
|
38
|
+
buff[i++] = b64_table[077 & (((s[1] << 2) & 074) | ((s[2] >> 6) & 03))];
|
39
|
+
buff[i++] = b64_table[077 & s[2]];
|
40
|
+
s += 3;
|
41
|
+
len -= 3;
|
42
|
+
}
|
43
|
+
if (len == 2) {
|
44
|
+
buff[i++] = b64_table[077 & (*s >> 2)];
|
45
|
+
buff[i++] = b64_table[077 & (((*s << 4) & 060) | ((s[1] >> 4) & 017))];
|
46
|
+
buff[i++] = b64_table[077 & (((s[1] << 2) & 074) | (('\0' >> 6) & 03))];
|
47
|
+
buff[i++] = padding;
|
48
|
+
}
|
49
|
+
else if (len == 1) {
|
50
|
+
buff[i++] = b64_table[077 & (*s >> 2)];
|
51
|
+
buff[i++] = b64_table[077 & (((*s << 4) & 060) | (('\0' >> 4) & 017))];
|
52
|
+
buff[i++] = padding;
|
53
|
+
buff[i++] = padding;
|
54
|
+
}
|
55
|
+
buff[i++] = '\n';
|
56
|
+
return buff;
|
57
|
+
}
|
58
|
+
|
59
|
+
char *
|
60
|
+
syck_base64dec( char *s, long len )
|
61
|
+
{
|
62
|
+
int a = -1,b = -1,c = 0,d;
|
63
|
+
static int first = 1;
|
64
|
+
static int b64_xtable[256];
|
65
|
+
char *ptr = syck_strndup( s, len );
|
66
|
+
char *end = ptr;
|
67
|
+
char *send = s + len;
|
68
|
+
|
69
|
+
if (first) {
|
70
|
+
int i;
|
71
|
+
first = 0;
|
72
|
+
|
73
|
+
for (i = 0; i < 256; i++) {
|
74
|
+
b64_xtable[i] = -1;
|
75
|
+
}
|
76
|
+
for (i = 0; i < 64; i++) {
|
77
|
+
b64_xtable[(int)b64_table[i]] = i;
|
78
|
+
}
|
79
|
+
}
|
80
|
+
while (s < send) {
|
81
|
+
while (s[0] == '\r' || s[0] == '\n') { s++; }
|
82
|
+
if ((a = b64_xtable[(int)s[0]]) == -1) break;
|
83
|
+
if ((b = b64_xtable[(int)s[1]]) == -1) break;
|
84
|
+
if ((c = b64_xtable[(int)s[2]]) == -1) break;
|
85
|
+
if ((d = b64_xtable[(int)s[3]]) == -1) break;
|
86
|
+
*end++ = a << 2 | b >> 4;
|
87
|
+
*end++ = b << 4 | c >> 2;
|
88
|
+
*end++ = c << 6 | d;
|
89
|
+
s += 4;
|
90
|
+
}
|
91
|
+
if (a != -1 && b != -1) {
|
92
|
+
if (s + 2 < send && s[2] == '=')
|
93
|
+
*end++ = a << 2 | b >> 4;
|
94
|
+
if (c != -1 && s + 3 < send && s[3] == '=') {
|
95
|
+
*end++ = a << 2 | b >> 4;
|
96
|
+
*end++ = b << 4 | c >> 2;
|
97
|
+
}
|
98
|
+
}
|
99
|
+
*end = '\0';
|
100
|
+
/*RSTRING_LEN(buf) = ptr - RSTRING_PTR(buf);*/
|
101
|
+
return ptr;
|
102
|
+
}
|
103
|
+
|
104
|
+
/*
|
105
|
+
* Allocate an emitter
|
106
|
+
*/
|
107
|
+
SyckEmitter *
|
108
|
+
syck_new_emitter(void)
|
109
|
+
{
|
110
|
+
SyckEmitter *e;
|
111
|
+
e = S_ALLOC( SyckEmitter );
|
112
|
+
e->headless = 0;
|
113
|
+
e->use_header = 0;
|
114
|
+
e->use_version = 0;
|
115
|
+
e->sort_keys = 0;
|
116
|
+
e->anchor_format = NULL;
|
117
|
+
e->explicit_typing = 0;
|
118
|
+
e->best_width = 80;
|
119
|
+
e->style = scalar_none;
|
120
|
+
e->stage = doc_open;
|
121
|
+
e->indent = 2;
|
122
|
+
e->level = -1;
|
123
|
+
e->anchors = NULL;
|
124
|
+
e->markers = NULL;
|
125
|
+
e->anchored = NULL;
|
126
|
+
e->bufsize = SYCK_BUFFERSIZE;
|
127
|
+
e->buffer = NULL;
|
128
|
+
e->marker = NULL;
|
129
|
+
e->bufpos = 0;
|
130
|
+
e->emitter_handler = NULL;
|
131
|
+
e->output_handler = NULL;
|
132
|
+
e->lvl_idx = 0;
|
133
|
+
e->lvl_capa = ALLOC_CT;
|
134
|
+
e->levels = S_ALLOC_N( SyckLevel, e->lvl_capa );
|
135
|
+
syck_emitter_reset_levels( e );
|
136
|
+
e->bonus = NULL;
|
137
|
+
return e;
|
138
|
+
}
|
139
|
+
|
140
|
+
int
|
141
|
+
syck_st_free_anchors( char *key, char *name, char *arg )
|
142
|
+
{
|
143
|
+
S_FREE( name );
|
144
|
+
return ST_CONTINUE;
|
145
|
+
}
|
146
|
+
|
147
|
+
void
|
148
|
+
syck_emitter_st_free( SyckEmitter *e )
|
149
|
+
{
|
150
|
+
/*
|
151
|
+
* Free the anchor tables
|
152
|
+
*/
|
153
|
+
if ( e->anchors != NULL )
|
154
|
+
{
|
155
|
+
st_foreach( e->anchors, syck_st_free_anchors, 0 );
|
156
|
+
st_free_table( e->anchors );
|
157
|
+
e->anchors = NULL;
|
158
|
+
}
|
159
|
+
|
160
|
+
if ( e->anchored != NULL )
|
161
|
+
{
|
162
|
+
st_free_table( e->anchored );
|
163
|
+
e->anchored = NULL;
|
164
|
+
}
|
165
|
+
|
166
|
+
/*
|
167
|
+
* Free the markers tables
|
168
|
+
*/
|
169
|
+
if ( e->markers != NULL )
|
170
|
+
{
|
171
|
+
st_free_table( e->markers );
|
172
|
+
e->markers = NULL;
|
173
|
+
}
|
174
|
+
}
|
175
|
+
|
176
|
+
SyckLevel *
|
177
|
+
syck_emitter_current_level( SyckEmitter *e )
|
178
|
+
{
|
179
|
+
return &e->levels[e->lvl_idx-1];
|
180
|
+
}
|
181
|
+
|
182
|
+
SyckLevel *
|
183
|
+
syck_emitter_parent_level( SyckEmitter *e )
|
184
|
+
{
|
185
|
+
return &e->levels[e->lvl_idx-2];
|
186
|
+
}
|
187
|
+
|
188
|
+
void
|
189
|
+
syck_emitter_pop_level( SyckEmitter *e )
|
190
|
+
{
|
191
|
+
ASSERT( e != NULL );
|
192
|
+
|
193
|
+
/* The root level should never be popped */
|
194
|
+
if ( e->lvl_idx <= 1 ) return;
|
195
|
+
|
196
|
+
e->lvl_idx -= 1;
|
197
|
+
free( e->levels[e->lvl_idx].domain );
|
198
|
+
}
|
199
|
+
|
200
|
+
void
|
201
|
+
syck_emitter_add_level( SyckEmitter *e, int len, enum syck_level_status status )
|
202
|
+
{
|
203
|
+
ASSERT( e != NULL );
|
204
|
+
if ( e->lvl_idx + 1 > e->lvl_capa )
|
205
|
+
{
|
206
|
+
e->lvl_capa += ALLOC_CT;
|
207
|
+
S_REALLOC_N( e->levels, SyckLevel, e->lvl_capa );
|
208
|
+
}
|
209
|
+
|
210
|
+
ASSERT( len > e->levels[e->lvl_idx-1].spaces );
|
211
|
+
e->levels[e->lvl_idx].spaces = len;
|
212
|
+
e->levels[e->lvl_idx].ncount = 0;
|
213
|
+
e->levels[e->lvl_idx].domain = syck_strndup( e->levels[e->lvl_idx-1].domain, strlen( e->levels[e->lvl_idx-1].domain ) );
|
214
|
+
e->levels[e->lvl_idx].status = status;
|
215
|
+
e->levels[e->lvl_idx].anctag = 0;
|
216
|
+
e->lvl_idx += 1;
|
217
|
+
}
|
218
|
+
|
219
|
+
void
|
220
|
+
syck_emitter_reset_levels( SyckEmitter *e )
|
221
|
+
{
|
222
|
+
while ( e->lvl_idx > 1 )
|
223
|
+
{
|
224
|
+
syck_emitter_pop_level( e );
|
225
|
+
}
|
226
|
+
|
227
|
+
if ( e->lvl_idx < 1 )
|
228
|
+
{
|
229
|
+
e->lvl_idx = 1;
|
230
|
+
e->levels[0].spaces = -1;
|
231
|
+
e->levels[0].ncount = 0;
|
232
|
+
e->levels[0].domain = syck_strndup( "", 0 );
|
233
|
+
e->levels[0].anctag = 0;
|
234
|
+
}
|
235
|
+
e->levels[0].status = syck_lvl_header;
|
236
|
+
}
|
237
|
+
|
238
|
+
void
|
239
|
+
syck_emitter_handler( SyckEmitter *e, SyckEmitterHandler hdlr )
|
240
|
+
{
|
241
|
+
e->emitter_handler = hdlr;
|
242
|
+
}
|
243
|
+
|
244
|
+
void
|
245
|
+
syck_output_handler( SyckEmitter *e, SyckOutputHandler hdlr )
|
246
|
+
{
|
247
|
+
e->output_handler = hdlr;
|
248
|
+
}
|
249
|
+
|
250
|
+
void
|
251
|
+
syck_free_emitter( SyckEmitter *e )
|
252
|
+
{
|
253
|
+
/*
|
254
|
+
* Free tables
|
255
|
+
*/
|
256
|
+
syck_emitter_st_free( e );
|
257
|
+
syck_emitter_reset_levels( e );
|
258
|
+
S_FREE( e->levels[0].domain );
|
259
|
+
S_FREE( e->levels );
|
260
|
+
if ( e->buffer != NULL )
|
261
|
+
{
|
262
|
+
S_FREE( e->buffer );
|
263
|
+
}
|
264
|
+
S_FREE( e );
|
265
|
+
}
|
266
|
+
|
267
|
+
void
|
268
|
+
syck_emitter_clear( SyckEmitter *e )
|
269
|
+
{
|
270
|
+
if ( e->buffer == NULL )
|
271
|
+
{
|
272
|
+
e->buffer = S_ALLOC_N( char, e->bufsize );
|
273
|
+
S_MEMZERO( e->buffer, char, e->bufsize );
|
274
|
+
}
|
275
|
+
e->buffer[0] = '\0';
|
276
|
+
e->marker = e->buffer;
|
277
|
+
e->bufpos = 0;
|
278
|
+
}
|
279
|
+
|
280
|
+
/*
|
281
|
+
* Raw write to the emitter buffer.
|
282
|
+
*/
|
283
|
+
void
|
284
|
+
syck_emitter_write( SyckEmitter *e, const char *str, long len )
|
285
|
+
{
|
286
|
+
long at;
|
287
|
+
ASSERT( str != NULL );
|
288
|
+
if ( e->buffer == NULL )
|
289
|
+
{
|
290
|
+
syck_emitter_clear( e );
|
291
|
+
}
|
292
|
+
|
293
|
+
/*
|
294
|
+
* Flush if at end of buffer
|
295
|
+
*/
|
296
|
+
at = e->marker - e->buffer;
|
297
|
+
if ( len + at >= (long)e->bufsize )
|
298
|
+
{
|
299
|
+
syck_emitter_flush( e, 0 );
|
300
|
+
for (;;) {
|
301
|
+
long rest = e->bufsize - (e->marker - e->buffer);
|
302
|
+
if (len <= rest) break;
|
303
|
+
S_MEMCPY( e->marker, str, char, rest );
|
304
|
+
e->marker += rest;
|
305
|
+
str += rest;
|
306
|
+
len -= rest;
|
307
|
+
syck_emitter_flush( e, 0 );
|
308
|
+
}
|
309
|
+
}
|
310
|
+
|
311
|
+
/*
|
312
|
+
* Write to buffer
|
313
|
+
*/
|
314
|
+
S_MEMCPY( e->marker, str, char, len );
|
315
|
+
e->marker += len;
|
316
|
+
}
|
317
|
+
|
318
|
+
/*
|
319
|
+
* Write a chunk of data out.
|
320
|
+
*/
|
321
|
+
void
|
322
|
+
syck_emitter_flush( SyckEmitter *e, long check_room )
|
323
|
+
{
|
324
|
+
/*
|
325
|
+
* Check for enough space in the buffer for check_room length.
|
326
|
+
*/
|
327
|
+
if ( check_room > 0 )
|
328
|
+
{
|
329
|
+
if ( (long)e->bufsize > ( e->marker - e->buffer ) + check_room )
|
330
|
+
{
|
331
|
+
return;
|
332
|
+
}
|
333
|
+
}
|
334
|
+
else
|
335
|
+
{
|
336
|
+
check_room = e->bufsize;
|
337
|
+
}
|
338
|
+
|
339
|
+
/*
|
340
|
+
* Commit buffer.
|
341
|
+
*/
|
342
|
+
if ( check_room > e->marker - e->buffer )
|
343
|
+
{
|
344
|
+
check_room = e->marker - e->buffer;
|
345
|
+
}
|
346
|
+
(e->output_handler)( e, e->buffer, check_room );
|
347
|
+
e->bufpos += check_room;
|
348
|
+
e->marker -= check_room;
|
349
|
+
}
|
350
|
+
|
351
|
+
/*
|
352
|
+
* Start emitting from the given node, check for anchoring and then
|
353
|
+
* issue the callback to the emitter handler.
|
354
|
+
*/
|
355
|
+
void
|
356
|
+
syck_emit( SyckEmitter *e, st_data_t n )
|
357
|
+
{
|
358
|
+
SYMID oid;
|
359
|
+
char *anchor_name = NULL;
|
360
|
+
int indent = 0;
|
361
|
+
long x = 0;
|
362
|
+
SyckLevel *lvl = syck_emitter_current_level( e );
|
363
|
+
|
364
|
+
/*
|
365
|
+
* Determine headers.
|
366
|
+
*/
|
367
|
+
if ( e->stage == doc_open && ( e->headless == 0 || e->use_header == 1 ) )
|
368
|
+
{
|
369
|
+
if ( e->use_version == 1 )
|
370
|
+
{
|
371
|
+
char *header = S_ALLOC_N( char, 64 );
|
372
|
+
S_MEMZERO( header, char, 64 );
|
373
|
+
sprintf( header, "--- %%YAML:%d.%d ", SYCK_YAML_MAJOR, SYCK_YAML_MINOR );
|
374
|
+
syck_emitter_write( e, header, strlen( header ) );
|
375
|
+
S_FREE( header );
|
376
|
+
}
|
377
|
+
else
|
378
|
+
{
|
379
|
+
syck_emitter_write( e, "--- ", 4 );
|
380
|
+
}
|
381
|
+
e->stage = doc_processing;
|
382
|
+
}
|
383
|
+
|
384
|
+
/* Add new level */
|
385
|
+
if ( lvl->spaces >= 0 ) {
|
386
|
+
indent = lvl->spaces + e->indent;
|
387
|
+
}
|
388
|
+
syck_emitter_add_level( e, indent, syck_lvl_open );
|
389
|
+
lvl = syck_emitter_current_level( e );
|
390
|
+
|
391
|
+
/* Look for anchor */
|
392
|
+
if ( e->anchors != NULL &&
|
393
|
+
st_lookup( e->markers, n, (st_data_t *)&oid ) &&
|
394
|
+
st_lookup( e->anchors, (st_data_t)oid, (void *)&anchor_name ) )
|
395
|
+
{
|
396
|
+
if ( e->anchored == NULL )
|
397
|
+
{
|
398
|
+
e->anchored = st_init_numtable();
|
399
|
+
}
|
400
|
+
|
401
|
+
if ( ! st_lookup( e->anchored, (st_data_t)anchor_name, (st_data_t *)&x ) )
|
402
|
+
{
|
403
|
+
char *an = S_ALLOC_N( char, strlen( anchor_name ) + 3 );
|
404
|
+
sprintf( an, "&%s ", anchor_name );
|
405
|
+
syck_emitter_write( e, an, strlen( anchor_name ) + 2 );
|
406
|
+
free( an );
|
407
|
+
|
408
|
+
x = 1;
|
409
|
+
st_insert( e->anchored, (st_data_t)anchor_name, (st_data_t)x );
|
410
|
+
lvl->anctag = 1;
|
411
|
+
}
|
412
|
+
else
|
413
|
+
{
|
414
|
+
char *an = S_ALLOC_N( char, strlen( anchor_name ) + 2 );
|
415
|
+
sprintf( an, "*%s", anchor_name );
|
416
|
+
syck_emitter_write( e, an, strlen( anchor_name ) + 1 );
|
417
|
+
free( an );
|
418
|
+
|
419
|
+
goto end_emit;
|
420
|
+
}
|
421
|
+
}
|
422
|
+
|
423
|
+
(e->emitter_handler)( e, n );
|
424
|
+
|
425
|
+
/* Pop the level */
|
426
|
+
end_emit:
|
427
|
+
syck_emitter_pop_level( e );
|
428
|
+
if ( e->lvl_idx == 1 ) {
|
429
|
+
syck_emitter_write( e, "\n", 1 );
|
430
|
+
e->headless = 0;
|
431
|
+
e->stage = doc_open;
|
432
|
+
}
|
433
|
+
}
|
434
|
+
|
435
|
+
/*
|
436
|
+
* Determine what tag needs to be written, based on the taguri of the node
|
437
|
+
* and the implicit tag which would be assigned to this node. If a tag is
|
438
|
+
* required, write the tag.
|
439
|
+
*/
|
440
|
+
void syck_emit_tag( SyckEmitter *e, const char *tag, const char *ignore )
|
441
|
+
{
|
442
|
+
SyckLevel *lvl;
|
443
|
+
if ( tag == NULL ) return;
|
444
|
+
if ( ignore != NULL && syck_tagcmp( tag, ignore ) == 0 && e->explicit_typing == 0 ) return;
|
445
|
+
lvl = syck_emitter_current_level( e );
|
446
|
+
|
447
|
+
/* implicit */
|
448
|
+
if ( strlen( tag ) == 0 ) {
|
449
|
+
syck_emitter_write( e, "! ", 2 );
|
450
|
+
|
451
|
+
/* global types */
|
452
|
+
} else if ( strncmp( tag, "tag:", 4 ) == 0 ) {
|
453
|
+
int taglen = (int)strlen( tag );
|
454
|
+
syck_emitter_write( e, "!", 1 );
|
455
|
+
if ( strncmp( tag + 4, YAML_DOMAIN, strlen( YAML_DOMAIN ) ) == 0 ) {
|
456
|
+
int skip = 4 + strlen( YAML_DOMAIN ) + 1;
|
457
|
+
syck_emitter_write( e, tag + skip, taglen - skip );
|
458
|
+
} else {
|
459
|
+
const char *subd = tag + 4;
|
460
|
+
while ( *subd != ':' && *subd != '\0' ) subd++;
|
461
|
+
if ( *subd == ':' ) {
|
462
|
+
if ( subd - tag > ( (long)( strlen( YAML_DOMAIN ) + 5 )) &&
|
463
|
+
strncmp( subd - strlen( YAML_DOMAIN ), YAML_DOMAIN, strlen( YAML_DOMAIN ) ) == 0 ) {
|
464
|
+
syck_emitter_write( e, tag + 4, subd - strlen( YAML_DOMAIN ) - ( tag + 4 ) - 1 );
|
465
|
+
syck_emitter_write( e, "/", 1 );
|
466
|
+
syck_emitter_write( e, subd + 1, ( tag + taglen ) - ( subd + 1 ) );
|
467
|
+
} else {
|
468
|
+
syck_emitter_write( e, tag + 4, subd - ( tag + 4 ) );
|
469
|
+
syck_emitter_write( e, "/", 1 );
|
470
|
+
syck_emitter_write( e, subd + 1, ( tag + taglen ) - ( subd + 1 ) );
|
471
|
+
}
|
472
|
+
} else {
|
473
|
+
/* TODO: Invalid tag (no colon after domain) */
|
474
|
+
return;
|
475
|
+
}
|
476
|
+
}
|
477
|
+
syck_emitter_write( e, " ", 1 );
|
478
|
+
|
479
|
+
/* private types */
|
480
|
+
} else if ( strncmp( tag, "x-private:", 10 ) == 0 ) {
|
481
|
+
syck_emitter_write( e, "!!", 2 );
|
482
|
+
syck_emitter_write( e, tag + 10, strlen( tag ) - 10 );
|
483
|
+
syck_emitter_write( e, " ", 1 );
|
484
|
+
}
|
485
|
+
lvl->anctag = 1;
|
486
|
+
}
|
487
|
+
|
488
|
+
/*
|
489
|
+
* Emit a newline and an appropriately spaced indent.
|
490
|
+
*/
|
491
|
+
void syck_emit_indent( SyckEmitter *e )
|
492
|
+
{
|
493
|
+
int i;
|
494
|
+
SyckLevel *lvl = syck_emitter_current_level( e );
|
495
|
+
if ( e->bufpos == 0 && ( e->marker - e->buffer ) == 0 ) return;
|
496
|
+
if ( lvl->spaces >= 0 ) {
|
497
|
+
char *spcs = S_ALLOC_N( char, lvl->spaces + 2 );
|
498
|
+
|
499
|
+
spcs[0] = '\n'; spcs[lvl->spaces + 1] = '\0';
|
500
|
+
for ( i = 0; i < lvl->spaces; i++ ) spcs[i+1] = ' ';
|
501
|
+
syck_emitter_write( e, spcs, lvl->spaces + 1 );
|
502
|
+
free( spcs );
|
503
|
+
}
|
504
|
+
}
|
505
|
+
|
506
|
+
/* Clear the scan */
|
507
|
+
#define SCAN_NONE 0
|
508
|
+
/* All printable characters? */
|
509
|
+
#define SCAN_NONPRINT 1
|
510
|
+
/* Any indented lines? */
|
511
|
+
#define SCAN_INDENTED 2
|
512
|
+
/* Larger than the requested width? */
|
513
|
+
#define SCAN_WIDE 4
|
514
|
+
/* Opens or closes with whitespace? */
|
515
|
+
#define SCAN_WHITEEDGE 8
|
516
|
+
/* Contains a newline */
|
517
|
+
#define SCAN_NEWLINE 16
|
518
|
+
/* Contains a single quote */
|
519
|
+
#define SCAN_SINGLEQ 32
|
520
|
+
/* Contains a double quote */
|
521
|
+
#define SCAN_DOUBLEQ 64
|
522
|
+
/* Starts with a token */
|
523
|
+
#define SCAN_INDIC_S 128
|
524
|
+
/* Contains a flow indicator */
|
525
|
+
#define SCAN_INDIC_C 256
|
526
|
+
/* Ends without newlines */
|
527
|
+
#define SCAN_NONL_E 512
|
528
|
+
/* Ends with many newlines */
|
529
|
+
#define SCAN_MANYNL_E 1024
|
530
|
+
/* Contains flow map indicators */
|
531
|
+
#define SCAN_FLOWMAP 2048
|
532
|
+
/* Contains flow seq indicators */
|
533
|
+
#define SCAN_FLOWSEQ 4096
|
534
|
+
/* Contains a valid doc separator */
|
535
|
+
#define SCAN_DOCSEP 8192
|
536
|
+
|
537
|
+
/*
|
538
|
+
* Basic printable test for LATIN-1 characters.
|
539
|
+
*/
|
540
|
+
int
|
541
|
+
syck_scan_scalar( int req_width, const char *cursor, long len )
|
542
|
+
{
|
543
|
+
long i = 0, start = 0;
|
544
|
+
int flags = SCAN_NONE;
|
545
|
+
|
546
|
+
if ( len < 1 ) return flags;
|
547
|
+
|
548
|
+
/* c-indicators from the spec */
|
549
|
+
if ( cursor[0] == '[' || cursor[0] == ']' ||
|
550
|
+
cursor[0] == '{' || cursor[0] == '}' ||
|
551
|
+
cursor[0] == '!' || cursor[0] == '*' ||
|
552
|
+
cursor[0] == '&' || cursor[0] == '|' ||
|
553
|
+
cursor[0] == '>' || cursor[0] == '\'' ||
|
554
|
+
cursor[0] == '"' || cursor[0] == '#' ||
|
555
|
+
cursor[0] == '%' || cursor[0] == '@' ||
|
556
|
+
cursor[0] == '&' ) {
|
557
|
+
flags |= SCAN_INDIC_S;
|
558
|
+
}
|
559
|
+
if ( ( cursor[0] == '-' || cursor[0] == ':' ||
|
560
|
+
cursor[0] == '?' || cursor[0] == ',' ) &&
|
561
|
+
( len == 1 || cursor[1] == ' ' || cursor[1] == '\n' ) )
|
562
|
+
{
|
563
|
+
flags |= SCAN_INDIC_S;
|
564
|
+
}
|
565
|
+
|
566
|
+
/* whitespace edges */
|
567
|
+
if ( cursor[len-1] != '\n' ) {
|
568
|
+
flags |= SCAN_NONL_E;
|
569
|
+
} else if ( len > 1 && cursor[len-2] == '\n' ) {
|
570
|
+
flags |= SCAN_MANYNL_E;
|
571
|
+
}
|
572
|
+
if (
|
573
|
+
( len > 0 && ( cursor[0] == ' ' || cursor[0] == '\t' || cursor[0] == '\n' || cursor[0] == '\r' ) ) ||
|
574
|
+
( len > 1 && ( cursor[len-1] == ' ' || cursor[len-1] == '\t' ) )
|
575
|
+
) {
|
576
|
+
flags |= SCAN_WHITEEDGE;
|
577
|
+
}
|
578
|
+
|
579
|
+
/* opening doc sep */
|
580
|
+
if ( len >= 3 && strncmp( cursor, "---", 3 ) == 0 )
|
581
|
+
flags |= SCAN_DOCSEP;
|
582
|
+
|
583
|
+
/* scan string */
|
584
|
+
for ( i = 0; i < len; i++ ) {
|
585
|
+
|
586
|
+
if ( ! ( cursor[i] == 0x9 ||
|
587
|
+
cursor[i] == 0xA ||
|
588
|
+
cursor[i] == 0xD ||
|
589
|
+
( cursor[i] >= 0x20 && cursor[i] <= 0x7E ) )
|
590
|
+
) {
|
591
|
+
flags |= SCAN_NONPRINT;
|
592
|
+
}
|
593
|
+
else if ( cursor[i] == '\n' ) {
|
594
|
+
flags |= SCAN_NEWLINE;
|
595
|
+
if ( len - i >= 3 && strncmp( &cursor[i+1], "---", 3 ) == 0 )
|
596
|
+
flags |= SCAN_DOCSEP;
|
597
|
+
if ( cursor[i+1] == ' ' || cursor[i+1] == '\t' )
|
598
|
+
flags |= SCAN_INDENTED;
|
599
|
+
if ( req_width > 0 && i - start > req_width )
|
600
|
+
flags |= SCAN_WIDE;
|
601
|
+
start = i;
|
602
|
+
}
|
603
|
+
else if ( cursor[i] == '\'' )
|
604
|
+
{
|
605
|
+
flags |= SCAN_SINGLEQ;
|
606
|
+
}
|
607
|
+
else if ( cursor[i] == '"' )
|
608
|
+
{
|
609
|
+
flags |= SCAN_DOUBLEQ;
|
610
|
+
}
|
611
|
+
else if ( cursor[i] == ']' )
|
612
|
+
{
|
613
|
+
flags |= SCAN_FLOWSEQ;
|
614
|
+
}
|
615
|
+
else if ( cursor[i] == '}' )
|
616
|
+
{
|
617
|
+
flags |= SCAN_FLOWMAP;
|
618
|
+
}
|
619
|
+
/* remember, if plain collections get implemented, to add nb-plain-flow-char */
|
620
|
+
else if ( ( cursor[i] == ' ' && cursor[i+1] == '#' ) ||
|
621
|
+
( cursor[i] == ':' &&
|
622
|
+
( cursor[i+1] == ' ' || cursor[i+1] == '\n' || i == len - 1 ) ) )
|
623
|
+
{
|
624
|
+
flags |= SCAN_INDIC_C;
|
625
|
+
}
|
626
|
+
else if ( cursor[i] == ',' &&
|
627
|
+
( cursor[i+1] == ' ' || cursor[i+1] == '\n' || i == len - 1 ) )
|
628
|
+
{
|
629
|
+
flags |= SCAN_FLOWMAP;
|
630
|
+
flags |= SCAN_FLOWSEQ;
|
631
|
+
}
|
632
|
+
}
|
633
|
+
|
634
|
+
/* printf( "---STR---\n%s\nFLAGS: %d\n", cursor, flags ); */
|
635
|
+
return flags;
|
636
|
+
}
|
637
|
+
/*
|
638
|
+
* All scalars should be emitted through this function, which determines an appropriate style,
|
639
|
+
* tag and indent.
|
640
|
+
*/
|
641
|
+
void syck_emit_scalar( SyckEmitter *e, const char *tag, enum scalar_style force_style, int force_indent, int force_width,
|
642
|
+
char keep_nl, const char *str, long len )
|
643
|
+
{
|
644
|
+
enum scalar_style favor_style = scalar_literal;
|
645
|
+
SyckLevel *parent = syck_emitter_parent_level( e );
|
646
|
+
SyckLevel *lvl = syck_emitter_current_level( e );
|
647
|
+
int scan = 0;
|
648
|
+
const char *match_implicit;
|
649
|
+
char *implicit;
|
650
|
+
|
651
|
+
if ( str == NULL ) str = "";
|
652
|
+
|
653
|
+
/* No empty nulls as map keys */
|
654
|
+
if ( len == 0 && ( parent->status == syck_lvl_map || parent->status == syck_lvl_imap ) &&
|
655
|
+
parent->ncount % 2 == 1 && syck_tagcmp( tag, "tag:yaml.org,2002:null" ) == 0 )
|
656
|
+
{
|
657
|
+
str = "~";
|
658
|
+
len = 1;
|
659
|
+
}
|
660
|
+
|
661
|
+
scan = syck_scan_scalar( force_width, str, len );
|
662
|
+
match_implicit = syck_match_implicit( str, len );
|
663
|
+
|
664
|
+
/* quote strings which default to implicits */
|
665
|
+
implicit = syck_taguri( YAML_DOMAIN, match_implicit, (int)strlen( match_implicit ) );
|
666
|
+
if ( syck_tagcmp( tag, implicit ) != 0 && syck_tagcmp( tag, "tag:yaml.org,2002:str" ) == 0 ) {
|
667
|
+
force_style = scalar_2quote;
|
668
|
+
} else {
|
669
|
+
/* complex key */
|
670
|
+
if ( parent->status == syck_lvl_map && parent->ncount % 2 == 1 &&
|
671
|
+
( !( tag == NULL ||
|
672
|
+
( implicit != NULL && syck_tagcmp( tag, implicit ) == 0 && e->explicit_typing == 0 ) ) ) )
|
673
|
+
{
|
674
|
+
syck_emitter_write( e, "? ", 2 );
|
675
|
+
parent->status = syck_lvl_mapx;
|
676
|
+
}
|
677
|
+
syck_emit_tag( e, tag, implicit );
|
678
|
+
}
|
679
|
+
S_FREE( implicit );
|
680
|
+
|
681
|
+
/* if still arbitrary, sniff a good block style. */
|
682
|
+
if ( force_style == scalar_none ) {
|
683
|
+
if ( scan & SCAN_NEWLINE ) {
|
684
|
+
force_style = scalar_literal;
|
685
|
+
} else {
|
686
|
+
force_style = scalar_plain;
|
687
|
+
}
|
688
|
+
}
|
689
|
+
|
690
|
+
if ( e->style == scalar_fold ) {
|
691
|
+
favor_style = scalar_fold;
|
692
|
+
}
|
693
|
+
|
694
|
+
/* Determine block style */
|
695
|
+
if ( scan & SCAN_NONPRINT ) {
|
696
|
+
force_style = scalar_2quote;
|
697
|
+
} else if ( scan & SCAN_WHITEEDGE ) {
|
698
|
+
force_style = scalar_2quote;
|
699
|
+
} else if ( force_style != scalar_fold && ( scan & SCAN_INDENTED ) ) {
|
700
|
+
force_style = scalar_literal;
|
701
|
+
} else if ( force_style == scalar_plain && ( scan & SCAN_NEWLINE ) ) {
|
702
|
+
force_style = favor_style;
|
703
|
+
} else if ( force_style == scalar_plain && parent->status == syck_lvl_iseq && ( scan & SCAN_FLOWSEQ ) ) {
|
704
|
+
force_style = scalar_2quote;
|
705
|
+
} else if ( force_style == scalar_plain && parent->status == syck_lvl_imap && ( scan & SCAN_FLOWMAP ) ) {
|
706
|
+
force_style = scalar_2quote;
|
707
|
+
/* } else if ( force_style == scalar_fold && ( ! ( scan & SCAN_WIDE ) ) ) {
|
708
|
+
force_style = scalar_literal; */
|
709
|
+
} else if ( force_style == scalar_plain && ( scan & SCAN_INDIC_S || scan & SCAN_INDIC_C ) ) {
|
710
|
+
if ( scan & SCAN_NEWLINE ) {
|
711
|
+
force_style = favor_style;
|
712
|
+
} else {
|
713
|
+
force_style = scalar_2quote;
|
714
|
+
}
|
715
|
+
}
|
716
|
+
|
717
|
+
if ( force_indent > 0 ) {
|
718
|
+
lvl->spaces = parent->spaces + force_indent;
|
719
|
+
} else if ( scan & SCAN_DOCSEP ) {
|
720
|
+
lvl->spaces = parent->spaces + e->indent;
|
721
|
+
}
|
722
|
+
|
723
|
+
/* For now, all ambiguous keys are going to be double-quoted */
|
724
|
+
if ( ( parent->status == syck_lvl_map || parent->status == syck_lvl_mapx ) && parent->ncount % 2 == 1 ) {
|
725
|
+
if ( force_style != scalar_plain ) {
|
726
|
+
force_style = scalar_2quote;
|
727
|
+
}
|
728
|
+
}
|
729
|
+
|
730
|
+
/* If the parent is an inline, double quote anything complex */
|
731
|
+
if ( parent->status == syck_lvl_imap || parent->status == syck_lvl_iseq ) {
|
732
|
+
if ( force_style != scalar_plain && force_style != scalar_1quote ) {
|
733
|
+
force_style = scalar_2quote;
|
734
|
+
}
|
735
|
+
}
|
736
|
+
|
737
|
+
/* Fix the ending newlines */
|
738
|
+
if ( scan & SCAN_NONL_E ) {
|
739
|
+
keep_nl = NL_CHOMP;
|
740
|
+
} else if ( scan & SCAN_MANYNL_E ) {
|
741
|
+
keep_nl = NL_KEEP;
|
742
|
+
}
|
743
|
+
|
744
|
+
/* Write the text node */
|
745
|
+
switch ( force_style )
|
746
|
+
{
|
747
|
+
case scalar_1quote:
|
748
|
+
syck_emit_1quoted( e, force_width, str, len );
|
749
|
+
break;
|
750
|
+
|
751
|
+
case scalar_none:
|
752
|
+
case scalar_2quote:
|
753
|
+
syck_emit_2quoted( e, force_width, str, len );
|
754
|
+
break;
|
755
|
+
|
756
|
+
case scalar_fold:
|
757
|
+
syck_emit_folded( e, force_width, keep_nl, str, len );
|
758
|
+
break;
|
759
|
+
|
760
|
+
case scalar_literal:
|
761
|
+
syck_emit_literal( e, keep_nl, str, len );
|
762
|
+
break;
|
763
|
+
|
764
|
+
case scalar_plain:
|
765
|
+
syck_emitter_write( e, str, len );
|
766
|
+
break;
|
767
|
+
}
|
768
|
+
|
769
|
+
if ( parent->status == syck_lvl_mapx )
|
770
|
+
{
|
771
|
+
syck_emitter_write( e, "\n", 1 );
|
772
|
+
}
|
773
|
+
}
|
774
|
+
|
775
|
+
void
|
776
|
+
syck_emitter_escape( SyckEmitter *e, const char *src, long len )
|
777
|
+
{
|
778
|
+
int i;
|
779
|
+
for( i = 0; i < len; i++ )
|
780
|
+
{
|
781
|
+
if( (src[i] < 0x20) || (0x7E < src[i]) )
|
782
|
+
{
|
783
|
+
syck_emitter_write( e, "\\", 1 );
|
784
|
+
if( '\0' == src[i] )
|
785
|
+
syck_emitter_write( e, "0", 1 );
|
786
|
+
else
|
787
|
+
{
|
788
|
+
syck_emitter_write( e, "x", 1 );
|
789
|
+
syck_emitter_write( e, (const char *)hex_table + ((src[i] & 0xF0) >> 4), 1 );
|
790
|
+
syck_emitter_write( e, (const char *)hex_table + (src[i] & 0x0F), 1 );
|
791
|
+
}
|
792
|
+
}
|
793
|
+
else
|
794
|
+
{
|
795
|
+
syck_emitter_write( e, src + i, 1 );
|
796
|
+
if( '\\' == src[i] )
|
797
|
+
syck_emitter_write( e, "\\", 1 );
|
798
|
+
}
|
799
|
+
}
|
800
|
+
}
|
801
|
+
|
802
|
+
/*
|
803
|
+
* Outputs a single-quoted block.
|
804
|
+
*/
|
805
|
+
void
|
806
|
+
syck_emit_1quoted( SyckEmitter *e, int width, const char *str, long len )
|
807
|
+
{
|
808
|
+
char do_indent = 0;
|
809
|
+
const char *mark = str;
|
810
|
+
const char *start = str;
|
811
|
+
const char *end = str;
|
812
|
+
syck_emitter_write( e, "'", 1 );
|
813
|
+
while ( mark < str + len ) {
|
814
|
+
if ( do_indent ) {
|
815
|
+
syck_emit_indent( e );
|
816
|
+
do_indent = 0;
|
817
|
+
}
|
818
|
+
switch ( *mark ) {
|
819
|
+
case '\'': syck_emitter_write( e, "'", 1 ); break;
|
820
|
+
|
821
|
+
case '\n':
|
822
|
+
end = mark + 1;
|
823
|
+
if ( *start != ' ' && *start != '\n' && *end != '\n' && *end != ' ' ) {
|
824
|
+
syck_emitter_write( e, "\n\n", 2 );
|
825
|
+
} else {
|
826
|
+
syck_emitter_write( e, "\n", 1 );
|
827
|
+
}
|
828
|
+
do_indent = 1;
|
829
|
+
start = mark + 1;
|
830
|
+
break;
|
831
|
+
|
832
|
+
case ' ':
|
833
|
+
if ( width > 0 && *start != ' ' && mark - end > width ) {
|
834
|
+
do_indent = 1;
|
835
|
+
end = mark + 1;
|
836
|
+
} else {
|
837
|
+
syck_emitter_write( e, " ", 1 );
|
838
|
+
}
|
839
|
+
break;
|
840
|
+
|
841
|
+
default:
|
842
|
+
syck_emitter_write( e, mark, 1 );
|
843
|
+
break;
|
844
|
+
}
|
845
|
+
mark++;
|
846
|
+
}
|
847
|
+
syck_emitter_write( e, "'", 1 );
|
848
|
+
}
|
849
|
+
|
850
|
+
/*
|
851
|
+
* Outputs a double-quoted block.
|
852
|
+
*/
|
853
|
+
void
|
854
|
+
syck_emit_2quoted( SyckEmitter *e, int width, const char *str, long len )
|
855
|
+
{
|
856
|
+
char do_indent = 0;
|
857
|
+
const char *mark = str;
|
858
|
+
const char *start = str;
|
859
|
+
const char *end = str;
|
860
|
+
syck_emitter_write( e, "\"", 1 );
|
861
|
+
while ( mark < str + len ) {
|
862
|
+
if ( do_indent > 0 ) {
|
863
|
+
if ( do_indent == 2 ) {
|
864
|
+
syck_emitter_write( e, "\\", 1 );
|
865
|
+
}
|
866
|
+
syck_emit_indent( e );
|
867
|
+
do_indent = 0;
|
868
|
+
}
|
869
|
+
switch ( *mark ) {
|
870
|
+
|
871
|
+
/* Escape sequences allowed within double quotes. */
|
872
|
+
case '"': syck_emitter_write( e, "\\\"", 2 ); break;
|
873
|
+
case '\\': syck_emitter_write( e, "\\\\", 2 ); break;
|
874
|
+
case '\0': syck_emitter_write( e, "\\0", 2 ); break;
|
875
|
+
case '\a': syck_emitter_write( e, "\\a", 2 ); break;
|
876
|
+
case '\b': syck_emitter_write( e, "\\b", 2 ); break;
|
877
|
+
case '\f': syck_emitter_write( e, "\\f", 2 ); break;
|
878
|
+
case '\r': syck_emitter_write( e, "\\r", 2 ); break;
|
879
|
+
case '\t': syck_emitter_write( e, "\\t", 2 ); break;
|
880
|
+
case '\v': syck_emitter_write( e, "\\v", 2 ); break;
|
881
|
+
case 0x1b: syck_emitter_write( e, "\\e", 2 ); break;
|
882
|
+
|
883
|
+
case '\n':
|
884
|
+
end = mark + 1;
|
885
|
+
syck_emitter_write( e, "\\n", 2 );
|
886
|
+
do_indent = 2;
|
887
|
+
start = mark + 1;
|
888
|
+
if ( start < str + len && ( *start == ' ' || *start == '\n' ) ) {
|
889
|
+
do_indent = 0;
|
890
|
+
}
|
891
|
+
break;
|
892
|
+
|
893
|
+
case ' ':
|
894
|
+
if ( width > 0 && *start != ' ' && mark - end > width ) {
|
895
|
+
do_indent = 1;
|
896
|
+
end = mark + 1;
|
897
|
+
} else {
|
898
|
+
syck_emitter_write( e, " ", 1 );
|
899
|
+
}
|
900
|
+
break;
|
901
|
+
|
902
|
+
default:
|
903
|
+
syck_emitter_escape( e, mark, 1 );
|
904
|
+
break;
|
905
|
+
}
|
906
|
+
mark++;
|
907
|
+
}
|
908
|
+
syck_emitter_write( e, "\"", 1 );
|
909
|
+
}
|
910
|
+
|
911
|
+
/*
|
912
|
+
* Outputs a literal block.
|
913
|
+
*/
|
914
|
+
void
|
915
|
+
syck_emit_literal( SyckEmitter *e, char keep_nl, const char *str, long len )
|
916
|
+
{
|
917
|
+
const char *mark = str;
|
918
|
+
const char *start = str;
|
919
|
+
const char *end = str;
|
920
|
+
syck_emitter_write( e, "|", 1 );
|
921
|
+
if ( keep_nl == NL_CHOMP ) {
|
922
|
+
syck_emitter_write( e, "-", 1 );
|
923
|
+
} else if ( keep_nl == NL_KEEP ) {
|
924
|
+
syck_emitter_write( e, "+", 1 );
|
925
|
+
}
|
926
|
+
syck_emit_indent( e );
|
927
|
+
while ( mark < str + len ) {
|
928
|
+
if ( *mark == '\n' ) {
|
929
|
+
end = mark;
|
930
|
+
if ( *start != ' ' && *start != '\n' && *end != '\n' && *end != ' ' ) end += 1;
|
931
|
+
syck_emitter_write( e, start, end - start );
|
932
|
+
if ( mark + 1 == str + len ) {
|
933
|
+
if ( keep_nl != NL_KEEP ) syck_emitter_write( e, "\n", 1 );
|
934
|
+
} else {
|
935
|
+
syck_emit_indent( e );
|
936
|
+
}
|
937
|
+
start = mark + 1;
|
938
|
+
}
|
939
|
+
mark++;
|
940
|
+
}
|
941
|
+
end = str + len;
|
942
|
+
if ( start < end ) {
|
943
|
+
syck_emitter_write( e, start, end - start );
|
944
|
+
}
|
945
|
+
}
|
946
|
+
|
947
|
+
/*
|
948
|
+
* Outputs a folded block.
|
949
|
+
*/
|
950
|
+
void
|
951
|
+
syck_emit_folded( SyckEmitter *e, int width, char keep_nl, const char *str, long len )
|
952
|
+
{
|
953
|
+
const char *mark = str;
|
954
|
+
const char *start = str;
|
955
|
+
const char *end = str;
|
956
|
+
syck_emitter_write( e, ">", 1 );
|
957
|
+
if ( keep_nl == NL_CHOMP ) {
|
958
|
+
syck_emitter_write( e, "-", 1 );
|
959
|
+
} else if ( keep_nl == NL_KEEP ) {
|
960
|
+
syck_emitter_write( e, "+", 1 );
|
961
|
+
}
|
962
|
+
syck_emit_indent( e );
|
963
|
+
if ( width <= 0 ) width = e->best_width;
|
964
|
+
while ( mark < str + len ) {
|
965
|
+
switch ( *mark ) {
|
966
|
+
case '\n':
|
967
|
+
syck_emitter_write( e, end, mark - end );
|
968
|
+
end = mark + 1;
|
969
|
+
if ( *start != ' ' && *start != '\n' && *end != '\n' && *end != ' ' ) {
|
970
|
+
syck_emitter_write( e, "\n", 1 );
|
971
|
+
}
|
972
|
+
if ( mark + 1 == str + len ) {
|
973
|
+
if ( keep_nl != NL_KEEP ) syck_emitter_write( e, "\n", 1 );
|
974
|
+
} else {
|
975
|
+
syck_emit_indent( e );
|
976
|
+
}
|
977
|
+
start = mark + 1;
|
978
|
+
break;
|
979
|
+
|
980
|
+
case ' ':
|
981
|
+
if ( *start != ' ' ) {
|
982
|
+
if ( mark - end > width ) {
|
983
|
+
syck_emitter_write( e, end, mark - end );
|
984
|
+
syck_emit_indent( e );
|
985
|
+
end = mark + 1;
|
986
|
+
}
|
987
|
+
}
|
988
|
+
break;
|
989
|
+
}
|
990
|
+
mark++;
|
991
|
+
}
|
992
|
+
if ( end < mark ) {
|
993
|
+
syck_emitter_write( e, end, mark - end );
|
994
|
+
}
|
995
|
+
}
|
996
|
+
|
997
|
+
/*
|
998
|
+
* Begins emission of a sequence.
|
999
|
+
*/
|
1000
|
+
void syck_emit_seq( SyckEmitter *e, const char *tag, enum seq_style style )
|
1001
|
+
{
|
1002
|
+
SyckLevel *parent = syck_emitter_parent_level( e );
|
1003
|
+
SyckLevel *lvl = syck_emitter_current_level( e );
|
1004
|
+
syck_emit_tag( e, tag, "tag:yaml.org,2002:seq" );
|
1005
|
+
if ( style == seq_inline || ( parent->status == syck_lvl_imap || parent->status == syck_lvl_iseq ) ) {
|
1006
|
+
syck_emitter_write( e, "[", 1 );
|
1007
|
+
lvl->status = syck_lvl_iseq;
|
1008
|
+
} else {
|
1009
|
+
/* complex key */
|
1010
|
+
if ( parent->status == syck_lvl_map && parent->ncount % 2 == 1 ) {
|
1011
|
+
syck_emitter_write( e, "? ", 2 );
|
1012
|
+
parent->status = syck_lvl_mapx;
|
1013
|
+
}
|
1014
|
+
lvl->status = syck_lvl_seq;
|
1015
|
+
}
|
1016
|
+
}
|
1017
|
+
|
1018
|
+
/*
|
1019
|
+
* Begins emission of a mapping.
|
1020
|
+
*/
|
1021
|
+
void
|
1022
|
+
syck_emit_map( SyckEmitter *e, const char *tag, enum map_style style )
|
1023
|
+
{
|
1024
|
+
SyckLevel *parent = syck_emitter_parent_level( e );
|
1025
|
+
SyckLevel *lvl = syck_emitter_current_level( e );
|
1026
|
+
syck_emit_tag( e, tag, "tag:yaml.org,2002:map" );
|
1027
|
+
if ( style == map_inline || ( parent->status == syck_lvl_imap || parent->status == syck_lvl_iseq ) ) {
|
1028
|
+
syck_emitter_write( e, "{", 1 );
|
1029
|
+
lvl->status = syck_lvl_imap;
|
1030
|
+
} else {
|
1031
|
+
/* complex key */
|
1032
|
+
if ( parent->status == syck_lvl_map && parent->ncount % 2 == 1 ) {
|
1033
|
+
syck_emitter_write( e, "? ", 2 );
|
1034
|
+
parent->status = syck_lvl_mapx;
|
1035
|
+
}
|
1036
|
+
lvl->status = syck_lvl_map;
|
1037
|
+
}
|
1038
|
+
}
|
1039
|
+
|
1040
|
+
/*
|
1041
|
+
* Handles emitting of a collection item (for both
|
1042
|
+
* sequences and maps)
|
1043
|
+
*/
|
1044
|
+
void syck_emit_item( SyckEmitter *e, st_data_t n )
|
1045
|
+
{
|
1046
|
+
SyckLevel *lvl = syck_emitter_current_level( e );
|
1047
|
+
switch ( lvl->status )
|
1048
|
+
{
|
1049
|
+
case syck_lvl_seq:
|
1050
|
+
{
|
1051
|
+
SyckLevel *parent = syck_emitter_parent_level( e );
|
1052
|
+
|
1053
|
+
/* seq-in-map shortcut -- the lvl->anctag check should be unneccesary but
|
1054
|
+
* there is a nasty shift/reduce in the parser on this point and
|
1055
|
+
* i'm not ready to tickle it. */
|
1056
|
+
if ( lvl->anctag == 0 && parent->status == syck_lvl_map && lvl->ncount == 0 ) {
|
1057
|
+
lvl->spaces = parent->spaces;
|
1058
|
+
}
|
1059
|
+
|
1060
|
+
/* seq-in-seq shortcut */
|
1061
|
+
else if ( lvl->anctag == 0 && parent->status == syck_lvl_seq && lvl->ncount == 0 ) {
|
1062
|
+
int spcs = ( lvl->spaces - parent->spaces ) - 2;
|
1063
|
+
if ( spcs >= 0 ) {
|
1064
|
+
int i = 0;
|
1065
|
+
for ( i = 0; i < spcs; i++ ) {
|
1066
|
+
syck_emitter_write( e, " ", 1 );
|
1067
|
+
}
|
1068
|
+
syck_emitter_write( e, "- ", 2 );
|
1069
|
+
break;
|
1070
|
+
}
|
1071
|
+
}
|
1072
|
+
|
1073
|
+
syck_emit_indent( e );
|
1074
|
+
syck_emitter_write( e, "- ", 2 );
|
1075
|
+
}
|
1076
|
+
break;
|
1077
|
+
|
1078
|
+
case syck_lvl_iseq:
|
1079
|
+
{
|
1080
|
+
if ( lvl->ncount > 0 ) {
|
1081
|
+
syck_emitter_write( e, ", ", 2 );
|
1082
|
+
}
|
1083
|
+
}
|
1084
|
+
break;
|
1085
|
+
|
1086
|
+
case syck_lvl_map:
|
1087
|
+
{
|
1088
|
+
SyckLevel *parent = syck_emitter_parent_level( e );
|
1089
|
+
|
1090
|
+
/* map-in-seq shortcut */
|
1091
|
+
if ( lvl->anctag == 0 && parent->status == syck_lvl_seq && lvl->ncount == 0 ) {
|
1092
|
+
int spcs = ( lvl->spaces - parent->spaces ) - 2;
|
1093
|
+
if ( spcs >= 0 ) {
|
1094
|
+
int i = 0;
|
1095
|
+
for ( i = 0; i < spcs; i++ ) {
|
1096
|
+
syck_emitter_write( e, " ", 1 );
|
1097
|
+
}
|
1098
|
+
break;
|
1099
|
+
}
|
1100
|
+
}
|
1101
|
+
|
1102
|
+
if ( lvl->ncount % 2 == 0 ) {
|
1103
|
+
syck_emit_indent( e );
|
1104
|
+
} else {
|
1105
|
+
syck_emitter_write( e, ": ", 2 );
|
1106
|
+
}
|
1107
|
+
}
|
1108
|
+
break;
|
1109
|
+
|
1110
|
+
case syck_lvl_mapx:
|
1111
|
+
{
|
1112
|
+
if ( lvl->ncount % 2 == 0 ) {
|
1113
|
+
syck_emit_indent( e );
|
1114
|
+
lvl->status = syck_lvl_map;
|
1115
|
+
} else {
|
1116
|
+
int i;
|
1117
|
+
if ( lvl->spaces > 0 ) {
|
1118
|
+
char *spcs = S_ALLOC_N( char, lvl->spaces + 1 );
|
1119
|
+
|
1120
|
+
spcs[lvl->spaces] = '\0';
|
1121
|
+
for ( i = 0; i < lvl->spaces; i++ ) spcs[i] = ' ';
|
1122
|
+
syck_emitter_write( e, spcs, lvl->spaces );
|
1123
|
+
S_FREE( spcs );
|
1124
|
+
}
|
1125
|
+
syck_emitter_write( e, ": ", 2 );
|
1126
|
+
}
|
1127
|
+
}
|
1128
|
+
break;
|
1129
|
+
|
1130
|
+
case syck_lvl_imap:
|
1131
|
+
{
|
1132
|
+
if ( lvl->ncount > 0 ) {
|
1133
|
+
if ( lvl->ncount % 2 == 0 ) {
|
1134
|
+
syck_emitter_write( e, ", ", 2 );
|
1135
|
+
} else {
|
1136
|
+
syck_emitter_write( e, ": ", 2 );
|
1137
|
+
}
|
1138
|
+
}
|
1139
|
+
}
|
1140
|
+
break;
|
1141
|
+
|
1142
|
+
default: break;
|
1143
|
+
}
|
1144
|
+
lvl->ncount++;
|
1145
|
+
|
1146
|
+
syck_emit( e, n );
|
1147
|
+
}
|
1148
|
+
|
1149
|
+
/*
|
1150
|
+
* Closes emission of a collection.
|
1151
|
+
*/
|
1152
|
+
void syck_emit_end( SyckEmitter *e )
|
1153
|
+
{
|
1154
|
+
SyckLevel *lvl = syck_emitter_current_level( e );
|
1155
|
+
SyckLevel *parent = syck_emitter_parent_level( e );
|
1156
|
+
switch ( lvl->status )
|
1157
|
+
{
|
1158
|
+
case syck_lvl_seq:
|
1159
|
+
if ( lvl->ncount == 0 ) {
|
1160
|
+
syck_emitter_write( e, "[]\n", 3 );
|
1161
|
+
} else if ( parent->status == syck_lvl_mapx ) {
|
1162
|
+
syck_emitter_write( e, "\n", 1 );
|
1163
|
+
}
|
1164
|
+
break;
|
1165
|
+
|
1166
|
+
case syck_lvl_iseq:
|
1167
|
+
syck_emitter_write( e, "]\n", 1 );
|
1168
|
+
break;
|
1169
|
+
|
1170
|
+
case syck_lvl_map:
|
1171
|
+
if ( lvl->ncount == 0 ) {
|
1172
|
+
syck_emitter_write( e, "{}\n", 3 );
|
1173
|
+
} else if ( lvl->ncount % 2 == 1 ) {
|
1174
|
+
syck_emitter_write( e, ":\n", 1 );
|
1175
|
+
} else if ( parent->status == syck_lvl_mapx ) {
|
1176
|
+
syck_emitter_write( e, "\n", 1 );
|
1177
|
+
}
|
1178
|
+
break;
|
1179
|
+
|
1180
|
+
case syck_lvl_imap:
|
1181
|
+
syck_emitter_write( e, "}\n", 1 );
|
1182
|
+
break;
|
1183
|
+
|
1184
|
+
default: break;
|
1185
|
+
}
|
1186
|
+
}
|
1187
|
+
|
1188
|
+
/*
|
1189
|
+
* Fill markers table with emitter nodes in the
|
1190
|
+
* soon-to-be-emitted tree.
|
1191
|
+
*/
|
1192
|
+
SYMID
|
1193
|
+
syck_emitter_mark_node( SyckEmitter *e, st_data_t n )
|
1194
|
+
{
|
1195
|
+
SYMID oid = 0;
|
1196
|
+
char *anchor_name = NULL;
|
1197
|
+
|
1198
|
+
/*
|
1199
|
+
* Ensure markers table is initialized.
|
1200
|
+
*/
|
1201
|
+
if ( e->markers == NULL )
|
1202
|
+
{
|
1203
|
+
e->markers = st_init_numtable();
|
1204
|
+
}
|
1205
|
+
|
1206
|
+
/*
|
1207
|
+
* Markers table initially marks the string position of the
|
1208
|
+
* object. Doesn't yet create an anchor, simply notes the
|
1209
|
+
* position.
|
1210
|
+
*/
|
1211
|
+
if ( ! st_lookup( e->markers, n, (st_data_t *)&oid ) )
|
1212
|
+
{
|
1213
|
+
/*
|
1214
|
+
* Store all markers
|
1215
|
+
*/
|
1216
|
+
oid = e->markers->num_entries + 1;
|
1217
|
+
st_insert( e->markers, n, (st_data_t)oid );
|
1218
|
+
}
|
1219
|
+
else
|
1220
|
+
{
|
1221
|
+
if ( e->anchors == NULL )
|
1222
|
+
{
|
1223
|
+
e->anchors = st_init_numtable();
|
1224
|
+
}
|
1225
|
+
|
1226
|
+
if ( ! st_lookup( e->anchors, (st_data_t)oid, (void *)&anchor_name ) )
|
1227
|
+
{
|
1228
|
+
int idx = 0;
|
1229
|
+
const char *anc = ( e->anchor_format == NULL ? DEFAULT_ANCHOR_FORMAT : e->anchor_format );
|
1230
|
+
|
1231
|
+
/*
|
1232
|
+
* Second time hitting this object, let's give it an anchor
|
1233
|
+
*/
|
1234
|
+
idx = (int)(e->anchors->num_entries + 1);
|
1235
|
+
anchor_name = S_ALLOC_N( char, strlen( anc ) + 10 );
|
1236
|
+
S_MEMZERO( anchor_name, char, strlen( anc ) + 10 );
|
1237
|
+
sprintf( anchor_name, anc, idx );
|
1238
|
+
|
1239
|
+
/*
|
1240
|
+
* Insert into anchors table
|
1241
|
+
*/
|
1242
|
+
st_insert( e->anchors, (st_data_t)oid, (st_data_t)anchor_name );
|
1243
|
+
}
|
1244
|
+
}
|
1245
|
+
return oid;
|
1246
|
+
}
|
1247
|
+
|