rubysl-syck 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+