rubysl-syck 1.0.1

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