rubysl-yaml 2.0.0 → 2.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,1247 @@
1
+ /*
2
+ * emitter.c
3
+ *
4
+ * $Author: naruse $
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
+