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.
Files changed (54) hide show
  1. data/.autotest.erb +8 -0
  2. data/.gemtest +0 -0
  3. data/CHANGELOG.rdoc +6 -0
  4. data/Manifest.txt +52 -0
  5. data/README.rdoc +51 -0
  6. data/Rakefile +32 -0
  7. data/ext/syck/bytecode.c +1165 -0
  8. data/ext/syck/emitter.c +1247 -0
  9. data/ext/syck/extconf.h +3 -0
  10. data/ext/syck/extconf.rb +5 -0
  11. data/ext/syck/gram.c +1894 -0
  12. data/ext/syck/gram.h +79 -0
  13. data/ext/syck/handler.c +173 -0
  14. data/ext/syck/implicit.c +2990 -0
  15. data/ext/syck/node.c +407 -0
  16. data/ext/syck/rubyext.c +2328 -0
  17. data/ext/syck/syck.c +524 -0
  18. data/ext/syck/syck.h +453 -0
  19. data/ext/syck/token.c +2724 -0
  20. data/ext/syck/yaml2byte.c +259 -0
  21. data/ext/syck/yamlbyte.h +171 -0
  22. data/lib/syck.bundle +0 -0
  23. data/lib/syck.rb +447 -0
  24. data/lib/syck/baseemitter.rb +242 -0
  25. data/lib/syck/basenode.rb +222 -0
  26. data/lib/syck/constants.rb +45 -0
  27. data/lib/syck/encoding.rb +35 -0
  28. data/lib/syck/error.rb +34 -0
  29. data/lib/syck/loader.rb +14 -0
  30. data/lib/syck/rubytypes.rb +450 -0
  31. data/lib/syck/stream.rb +41 -0
  32. data/lib/syck/stringio.rb +85 -0
  33. data/lib/syck/syck.rb +16 -0
  34. data/lib/syck/tag.rb +95 -0
  35. data/lib/syck/types.rb +192 -0
  36. data/lib/syck/yamlnode.rb +54 -0
  37. data/lib/syck/ypath.rb +54 -0
  38. data/lib/yaml/syck.rb +14 -0
  39. data/test/helper.rb +2 -0
  40. data/test/test_array.rb +13 -0
  41. data/test/test_boolean.rb +36 -0
  42. data/test/test_class.rb +11 -0
  43. data/test/test_exception.rb +45 -0
  44. data/test/test_hash.rb +24 -0
  45. data/test/test_null.rb +19 -0
  46. data/test/test_omap.rb +55 -0
  47. data/test/test_set.rb +30 -0
  48. data/test/test_string.rb +44 -0
  49. data/test/test_struct.rb +32 -0
  50. data/test/test_symbol.rb +21 -0
  51. data/test/test_time.rb +23 -0
  52. data/test/test_yaml.rb +1403 -0
  53. data/test/test_yaml_properties.rb +63 -0
  54. metadata +187 -0
@@ -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
+