File Coverage

blib/lib/YAML/Perl/Emitter.pm
Criterion Covered Total %
statement 564 821 68.7
branch 241 440 54.7
condition 159 372 42.7
subroutine 59 69 85.5
pod 0 58 0.0
total 1023 1760 58.1


line stmt bran cond sub pod time code
1             # pyyaml/lib/yaml/emitter.py
2              
3             # Emitter expects events obeying the following grammar:
4             # stream ::= STREAM-START document* STREAM-END
5             # document ::= DOCUMENT-START node DOCUMENT-END
6             # node ::= SCALAR | sequence | mapping
7             # sequence ::= SEQUENCE-START node* SEQUENCE-END
8             # mapping ::= MAPPING-START (node node)* MAPPING-END
9             # To Do:
10             # - Make encode stuff work
11              
12             package YAML::Perl::Emitter;
13 7     7   1095 use strict;
  7         12  
  7         310  
14 7     7   39 use warnings;
  7         14  
  7         208  
15              
16 7     7   1297 use YAML::Perl::Error;
  7         16  
  7         50  
17 7     7   2347 use YAML::Perl::Events;
  7         20  
  7         215  
18 7     7   4258 use YAML::Perl::Writer;
  7         23  
  7         75  
19              
20             package YAML::Perl::Error::Emitter;
21 7     7   42 use YAML::Perl::Error -base;
  7         16  
  7         52  
22              
23             package YAML::Perl::ScalarAnalysis;
24 7     7   39 use YAML::Perl::Base -base;
  7         19  
  7         37  
25              
26             field 'scalar';
27             field 'empty';
28             field 'multiline';
29             field 'allow_flow_plain';
30             field 'allow_block_plain';
31             field 'allow_single_quoted';
32             field 'allow_double_quoted';
33             field 'allow_block';
34              
35             package YAML::Perl::Emitter;
36 7     7   139 use YAML::Perl::Processor -base;
  7         24  
  7         42  
37              
38             field next_layer => 'writer';
39             field 'writer_class', -init => '"YAML::Perl::Writer"';
40             field 'writer', -init => '$self->create("writer")';
41              
42 7         7527 use constant DEFAULT_TAG_PREFIXES => {
43             '!' => '!',
44             'tag:yaml.org,2002:' => '!!',
45 7     7   39 };
  7         30  
46              
47             field 'encoding';
48             field 'states' => [];
49             field 'state' => 'expect_stream_start'; # Made this a function name instead of pointer
50             field 'events' => [];
51             field 'event';
52             field 'indents' => [];
53             field 'indent';
54             field 'flow_level' => 0;
55             field 'root_context' => False;
56             field 'sequence_context' => False;
57             field 'mapping_context' => False;
58             field 'simple_key_context' => False;
59             field 'line' => 0;
60             field 'column' => 0;
61             field 'whitespace' => True;
62             field 'indention' => True;
63             field 'canonical';
64             field 'allow_unicode';
65             field 'best_indent' => 2;
66             field 'best_width' => 80;
67             field 'best_line_break' => "\n";
68             field 'tag_prefixes';
69             field 'prepared_anchor';
70             field 'prepared_tag';
71             field 'analysis';
72             field 'style';
73              
74             sub init {
75 30     30 0 70 my $self = shift;
76 30         86 my %p = @_;
77 30 0 33     152 if ($p{indent} and $p{indent} > 1 and $p{indent} < 10) {
      33        
78 0         0 $p{best_indent} = delete $p{indent};
79             }
80 30 50 0     132 if ($p{width} and $p{width} > ($p{best_indent} || 2) * 2) {
      33        
81 0         0 $p{best_width} = delete $p{width};
82             }
83 30 50 33     123 if ($p{line_break} and $p{line_break} =~ /^(\r|\n|\r\n)$/) {
84 0         0 $p{best_line_break} = delete $p{line_break};
85             }
86 30         165 $self->SUPER::init(%p);
87             }
88              
89             sub emit {
90 202     202 0 298 my $self = shift;
91 202         5092 my $events = $self->events;
92 202         422 push @$events, @_;
93              
94 202         486 while (not $self->need_more_events()) {
95 249         6802 $self->event(shift @$events);
96 249         6490 my $state = $self->state;
97 249         946 $self->$state();
98 249         6253 $self->event(undef);
99             }
100 202         351 return ${$self->writer->stream->buffer};
  202         6449  
101             }
102              
103             sub need_more_events {
104 451     451 0 614 my $self = shift;
105 451 100       512 if (not @{$self->events}) {
  451         13272  
106 126         371 return True;
107             }
108 325         7751 my $event = $self->events->[0];
109 325 100       4424 if ($event->isa('YAML::Perl::Event::DocumentStart')) {
    100          
    100          
110 52         177 return $self->need_events(1);
111             }
112             elsif ($event->isa('YAML::Perl::Event::SequenceStart')) {
113 46         112 return $self->need_events(2);
114             }
115             elsif ($event->isa('YAML::Perl::Event::MappingStart')) {
116 44         109 return $self->need_events(3);
117             }
118             else {
119 183         1092 return False;
120             }
121             }
122              
123             sub need_events {
124 142     142 0 242 my $self = shift;
125 142         187 my $count = shift;
126 142         174 my $level = 0;
127 142         216 for my $event (@{$self->events}[1..$#{$self->events}]) {
  142         19745  
  142         3567  
128 188 100 66     4054 if ($event->isa('YAML::Perl::Event::DocumentStart') or
    100 100        
    50          
129             $event->isa('YAML::Perl::Event::CollectionStart')
130             ) {
131 44         72 $level++;
132             }
133             elsif ($event->isa('YAML::Perl::Event::DocumentEnd') or
134             $event->isa('YAML::Perl::Event::CollectionEnd')
135             ) {
136 37         59 $level--;
137             }
138             elsif ($event->isa('YAML::Perl::Event::StreamEnd')) {
139 0         0 $level = -1;
140             }
141 188 100       509 if ($level < 0) {
142 24         97 return False;
143             }
144             }
145 118         224 return (@{$self->events} < $count + 1);
  118         2821  
146             }
147              
148             sub increase_indent {
149 105     105 0 186 my $self = shift;
150 105 50       252 my $flow = @_ ? shift : False;
151 105 100       293 my $indentless = @_ ? shift : False;
152 105         140 push @{$self->indents}, $self->indent;
  105         3459  
153 105 100       2452 if (not defined $self->indent) {
    50          
154 29 100       80 if ($flow) {
155 5         133 $self->indent($self->best_indent);
156             }
157             else {
158 24         614 $self->indent(0);
159             }
160             }
161             elsif (not $indentless) {
162 76         1779 $self->indent($self->indent + $self->best_indent);
163             }
164             }
165              
166             sub expect_stream_start {
167 29     29 0 62 my $self = shift;
168 29 50       761 if ($self->event->isa('YAML::Perl::Event::StreamStart')) {
169 29 50       756 if ($self->event->encoding) {
170 0         0 $self->encoding($self->event->encoding);
171             }
172 29         144 $self->write_stream_start();
173 29         722 $self->state('expect_first_document_start');
174             }
175             else {
176 7     7   49 use strict;
  7         12  
  7         64416  
177 0         0 throw YAML::Perl::Error::Emitter(
178 0         0 "expected StreamStartEvent, but got ${\ $self->event}"
179             );
180             }
181             }
182              
183             sub expect_nothing {
184 0     0 0 0 my $self = shift;
185 0         0 throw YAML::Perl::Error::Emitter(
186 0         0 "expected nothing, but got ${\ $self->event}"
187             );
188             }
189              
190             sub expect_first_document_start {
191 29     29 0 60 my $self = shift;
192 29         111 return $self->expect_document_start(True);
193             }
194              
195             sub expect_document_start {
196 45     45 0 86 my $self = shift;
197 45 100       134 my $first = @_ ? shift : False;
198 45 100       1474 if ($self->event->isa('YAML::Perl::Event::DocumentStart')) {
    50          
199 29 100       737 if ($self->event->version) {
200 1         31 my $version_text = $self->prepare_version($self->event->version);
201 1         7 $self->write_version_directive($version_text);
202             }
203 29         66 $self->tag_prefixes({%{DEFAULT_TAG_PREFIXES()}});
  29         906  
204 29 50       723 if ($self->event->tags) {
205 0         0 for my $handle (sort keys %{$self->event->tags}) {
  0         0  
206 0         0 my $prefix = $self->event->tags->{$handle};
207 0         0 $self->tag_prefixes->{$prefix} = $handle;
208 0         0 my $handle_text = $self->prepare_tag_handle($handle);
209 0         0 my $prefix_text = $self->prepare_tag_prefix($prefix);
210 0         0 $self->write_tag_directive($handle_text, $prefix_text);
211             }
212             }
213 29   33     784 my $implicit = (
214             $first and
215             not $self->event->explicit and
216             not $self->canonical and
217             not $self->event->version and
218             not $self->event->tags and
219             not $self->check_empty_document()
220             );
221 29 100       119 if (not $implicit) {
222 28         124 $self->write_indent();
223 28         139 $self->write_indicator('---', True);
224 28 50       738 if ($self->canonical) {
225 0         0 $self->write_indent();
226             }
227             }
228 29         731 $self->state('expect_document_root');
229             }
230             elsif ($self->event->isa('YAML::Perl::Event::StreamEnd')) {
231 16         75 $self->write_stream_end();
232 16         457 $self->state('expect_nothing');
233             }
234             else {
235 0         0 throw YAML::Perl::Error::Emitter(
236 0         0 "expected DocumentStartEvent, but got ${\ $self->event}"
237             );
238             }
239             }
240              
241             sub expect_document_end {
242 29     29 0 61 my $self = shift;
243 29 50       759 if ($self->event->isa('YAML::Perl::Event::DocumentEnd')) {
244 29         92 $self->write_indent();
245 29 50       702 if ($self->event->explicit) {
246 0         0 $self->write_indicator('->->->', True);
247 0         0 $self->write_indent();
248             }
249 29         131 $self->flush_stream();
250 29         700 $self->state('expect_document_start');
251             }
252             else {
253 0         0 throw YAML::Perl::Error::Emitter(
254 0         0 "expected DocumentEndEvent, but got ${\ $self->event}"
255             );
256             }
257             }
258              
259             sub expect_document_root {
260 29     29 0 62 my $self = shift;
261 29         51 push @{$self->states}, 'expect_document_end';
  29         721  
262 29         140 $self->expect_node(root => True);
263             }
264              
265             sub expect_node {
266 109     109 0 188 my $self = shift;
267 109         495 my ($root, $sequence, $mapping, $simple_key) =
268 109         173 @{{@_}}{qw(root sequence mapping simple_key)};
269 109         2901 $self->root_context($root);
270 109         2661 $self->sequence_context($sequence);
271 109         2583 $self->mapping_context($mapping);
272 109 100 66     3028 if ($self->event->isa('YAML::Perl::Event::Alias')) {
    50          
273 4         22 $self->expect_alias();
274             }
275             elsif ($self->event->isa('YAML::Perl::Event::Scalar') or
276             $self->event->isa('YAML::Perl::Event::CollectionStart')
277             ) {
278 105         327 $self->process_anchor('&');
279 105         312 $self->process_tag();
280 105 100       2450 if ($self->event->isa('YAML::Perl::Event::Scalar')) {
    100          
    50          
281 68         226 $self->expect_scalar();
282             }
283             elsif ($self->event->isa('YAML::Perl::Event::SequenceStart')) {
284 17 100 33     417 if ($self->flow_level or
      33        
      66        
285             $self->canonical or
286             $self->event->flow_style or
287             $self->check_empty_sequence()
288             ) {
289 3         15 $self->expect_flow_sequence();
290             }
291             else {
292 14         81 $self->expect_block_sequence();
293             }
294             }
295             elsif ($self->event->isa('YAML::Perl::Event::MappingStart')) {
296 20 100 33     487 if ($self->flow_level or
      33        
      66        
297             $self->canonical or
298             $self->event->flow_style or
299             $self->check_empty_mapping()
300             ) {
301 6         28 $self->expect_flow_mapping();
302             }
303             else {
304 14         57 $self->expect_block_mapping();
305             }
306             }
307             }
308             else {
309 0         0 throw YAML::Perl::Error::Emitter(
310 0         0 "expected NodeEvent, but got ${\ $self->event}"
311             );
312             }
313             }
314              
315             sub expect_alias {
316 4     4 0 12 my $self = shift;
317 4 50       150 if (not $self->event->anchor) {
318 0         0 throw YAML::Perl::Error::Emitter("anchor is not specified for alias");
319             }
320 4         20 $self->process_anchor("*");
321 4         19 $self->state(pop @{$self->states});
  4         90  
322             }
323              
324             sub expect_scalar {
325 68     68 0 104 my $self = shift;
326 68         1025 $self->increase_indent(True);
327 68         206 $self->process_scalar();
328 68         104 $self->indent(pop @{$self->indents});
  68         1747  
329 68         115 $self->state(pop @{$self->states});
  68         1601  
330             }
331              
332             sub expect_flow_sequence {
333 3     3 0 7 my $self = shift;
334              
335 3         11 $self->write_indicator('[', True, whitespace => True);
336 3         74 $self->flow_level($self->flow_level + 1);
337 3         14 $self->increase_indent(True);
338 3         78 $self->state('expect_first_flow_sequence_item');
339             }
340              
341             sub expect_first_flow_sequence_item {
342 3     3 0 7 my $self = shift;
343              
344 3 50       76 if ($self->event->isa('YAML::Perl::Event::SequenceEnd')) {
345 3         4 $self->indent(pop @{$self->indents});
  3         80  
346 3         75 $self->flow_level($self->flow_level - 1);
347 3         11 $self->write_indicator(']', False);
348 3         7 $self->state(pop @{$self->states});
  3         69  
349             }
350             else {
351 0 0 0     0 if ($self->canonical or $self->column > $self->best_width) {
352 0         0 $self->write_indent();
353             }
354 0         0 push @{$self->states}, 'expect_flow_sequence_item';
  0         0  
355 0         0 $self->expect_node(sequence => True);
356             }
357             }
358              
359             sub expect_flow_sequence_item {
360 0     0 0 0 my $self = shift;
361              
362 0 0       0 if ($self->event->isa('YAML::Perl::Event::SequenceEnd')) {
363 0         0 $self->indent(pop @{$self->indents});
  0         0  
364 0         0 $self->flow_level($self->flow_level - 1);
365 0 0       0 if ($self->canonical) {
366 0         0 $self->write_indicator(',', False);
367 0         0 $self->write_indent();
368             }
369 0         0 $self->write_indicator(']', False);
370 0         0 $self->state(pop @{$self->states});
  0         0  
371             }
372             else {
373 0         0 $self->write_indicator(',', False);
374 0 0 0     0 if ($self->canonical or $self->column > $self->best_width) {
375 0         0 $self->write_indent();
376             }
377 0         0 push @{$self->states}, 'expect_flow_sequence_item';
  0         0  
378 0         0 $self->expect_node(sequence => True);
379             }
380             }
381              
382             sub expect_flow_mapping {
383 6     6 0 15 my $self = shift;
384 6         25 $self->write_indicator('{', True, whitespace => True);
385 6         180 $self->flow_level($self->flow_level + 1);
386 6         18 $self->increase_indent(True);
387 6         146 $self->state('expect_first_flow_mapping_key');
388             }
389              
390             sub expect_first_flow_mapping_key {
391 6     6 0 12 my $self = shift;
392 6 50       147 if ($self->event->isa('YAML::Perl::Event::MappingEnd')) {
393 6         12 $self->indent(pop @{$self->indents});
  6         167  
394 6         135 $self->flow_level($self->flow_level - 1);
395 6         17 $self->write_indicator('}', False);
396 6         16 $self->state(pop @{$self->states});
  6         152  
397             }
398             else {
399 0 0 0     0 if ($self->canonical or $self->column > $self->best_width) {
400 0         0 $self->write_indent();
401             }
402 0 0 0     0 if (not $self->canonical and $self->check_simple_key()) {
403 0         0 push @{$self->states}, 'expect_flow_mapping_simple_value';
  0         0  
404 0         0 $self->expect_node(mapping => True, simple_key => True);
405             }
406             else {
407 0         0 $self->write_indicator('?', True);
408 0         0 push @{$self->states}, 'expect_flow_mapping_value';
  0         0  
409 0         0 $self->expect_node(mapping => True);
410             }
411             }
412             }
413              
414             sub expect_flow_mapping_key {
415 0     0 0 0 my $self = shift;
416 0 0       0 if ($self->event->isa('YAML::Perl::Event::MappingEnd')) {
417 0         0 $self->indent(pop, @{$self->indents});
  0         0  
418 0         0 $self->flow_level($self->flow_level - 1);
419 0 0       0 if ($self->canonical) {
420 0         0 $self->write_indicator(',', False);
421 0         0 $self->write_indent();
422             }
423 0         0 $self->write_indicator('}', False);
424 0         0 $self->state(pop @{$self->states});
  0         0  
425             }
426             else {
427 0         0 $self->write_indicator(',', False);
428 0 0 0     0 if ($self->canonical or $self->column > $self->best_width) {
429 0         0 $self->write_indent();
430             }
431 0 0 0     0 if (not $self->canonical and $self->check_simple_key()) {
432 0         0 push @{$self->states}, 'expect_flow_mapping_simple_value';
  0         0  
433 0         0 $self->expect_node(mapping => True, simple_key => True);
434             }
435             else {
436 0         0 $self->write_indicator('?', True);
437 0         0 push @{$self->states}, 'expect_flow_mapping_value';
  0         0  
438 0         0 $self->expect_node(mapping => True);
439             }
440             }
441             }
442              
443             sub expect_flow_mapping_simple_value {
444 0     0 0 0 my $self = shift;
445 0         0 $self->write_indicator(':', False);
446 0         0 push @{$self->states}, 'expect_flow_mapping_key';
  0         0  
447 0         0 $self->expect_node(mapping => True);
448             }
449              
450             sub expect_flow_mapping_value {
451 0     0 0 0 my $self = shift;
452 0 0 0     0 if ($self->canonical or $self->column > $self->best_width) {
453 0         0 $self->write_indent();
454             }
455 0         0 $self->write_indicator(':', True);
456 0         0 push @{$self->states}, 'expect_flow_mapping_key';
  0         0  
457 0         0 $self->expect_node(mapping => True);
458             }
459              
460             sub expect_block_sequence {
461 14     14 0 27 my $self = shift;
462 14   33     338 my $indentless = ($self->mapping_context and not $self->indention);
463 14         56 $self->increase_indent(False, $indentless);
464 14         319 $self->state('expect_first_block_sequence_item');
465             }
466              
467             sub expect_first_block_sequence_item {
468 14     14 0 35 my $self = shift;
469 14         53 return $self->expect_block_sequence_item(False);
470             }
471              
472             sub expect_block_sequence_item {
473 50     50 0 78 my $self = shift;
474 50 100       129 my $first = @_ ? shift : False;
475 50 100 66     1289 if (not $first and $self->event->isa('YAML::Perl::Event::SequenceEnd')) {
476 14         129 $self->indent(pop @{$self->indents});
  14         340  
477 14         29 $self->state(pop @{$self->states});
  14         393  
478             }
479             else {
480 36         97 $self->write_indent();
481 36         126 $self->write_indicator('-', True, indention => True);
482 36         61 push @{$self->states}, 'expect_block_sequence_item';
  36         851  
483 36         109 $self->expect_node(sequence => True);
484             }
485             }
486              
487             sub expect_block_mapping {
488 14     14 0 26 my $self = shift;
489 14         46 $self->increase_indent(False);
490 14         328 $self->state('expect_first_block_mapping_key');
491             }
492              
493             sub expect_first_block_mapping_key {
494 14     14 0 28 my $self = shift;
495 14         51 return $self->expect_block_mapping_key(True);
496             }
497              
498             sub expect_block_mapping_key {
499 36     36 0 63 my $self = shift;
500 36 100       98 my $first = @_ ? shift : False;
501 36 100 100     626 if (not $first and $self->event->isa('YAML::Perl::Event::MappingEnd')) {
502 14         27 $self->indent(pop @{$self->indents});
  14         336  
503 14         30 $self->state(pop @{$self->states});
  14         326  
504             }
505             else {
506 22         67 $self->write_indent();
507 22 50       95 if ($self->check_simple_key()) {
508 22         36 push @{$self->states}, 'expect_block_mapping_simple_value';
  22         533  
509 22         76 $self->expect_node(mapping => True, simple_key => True);
510             }
511             else {
512 0         0 $self->write_indicator('?', True, indention => True);
513 0         0 push @{$self->states}, 'expect_block_mapping_value';
  0         0  
514 0         0 $self->expect_node(mapping => True);
515             }
516             }
517             }
518              
519             sub expect_block_mapping_simple_value {
520 22     22 0 37 my $self = shift;
521 22         1037 $self->write_indicator(':', False);
522 22         46 push @{$self->states}, 'expect_block_mapping_key';
  22         529  
523 22         68 $self->expect_node(mapping => True);
524             }
525              
526             sub expect_block_mapping_value {
527 0     0 0 0 die 'expect_block_mapping_value';
528             }
529              
530             sub check_empty_sequence {
531 17     17 0 26 my $self = shift;
532             return (
533             $self->event->isa('YAML::Perl::Event::SequenceStart') and
534 17   66     380 @{$self->events} and
535             $self->events->[0]->isa('YAML::Perl::Event::SequenceEnd')
536             );
537             }
538              
539             sub check_empty_mapping {
540 20     20 0 37 my $self = shift;
541             return (
542             $self->event->isa('YAML::Perl::Event::MappingStart') and
543 20   66     454 @{$self->events} and
544             $self->events->[0]->isa('YAML::Perl::Event::MappingEnd')
545             );
546             }
547              
548             sub check_empty_document {
549 1     1 0 2 my $self = shift;
550 1 50 33     22 if (not $self->event->isa('YAML::Perl::Event::DocumentStart') or
551             not $self->events
552             ) {
553 0         0 return False;
554             }
555 1         22 my $event = $self->events->[0];
556             return (
557 1   33     32 $event->isa('YAML::Perl::Event::Scalar') and
558             not defined $event->anchor and
559             not defined $event->tag and
560             $event->implicit and
561             $event->value eq ''
562             );
563             }
564              
565             sub check_simple_key {
566 22     22 0 49 my $self = shift;
567 22         38 my $length = 0;
568 22 50 33     516 if ($self->event->isa('YAML::Perl::Event::Node') and
569             defined $self->event->anchor
570             ) {
571 0 0       0 if (not $self->prepared_anchor) {
572 0         0 $self->prepared_anchor($self->prepare_anchor($self->event->anchor));
573             }
574 0         0 $length += length($self->prepared_anchor);
575             }
576 22 50 33     549 if ((
      33        
577             $self->event->isa('YAML::Perl::Event::Scalar') or
578             $self->event->isa('YAML::Perl::Event::CollectionStart')
579             ) and $self->event->tag
580             ) {
581 0 0       0 if (not $self->prepared_tag) {
582 0         0 $self->prepared_tag($self->prepare_tag($self->event->tag));
583             }
584 0         0 $length += length($self->prepared_tag);
585             }
586 22 50       518 if ($self->event->isa('YAML::Perl::Event::Scalar')) {
587 22 50       529 if (not $self->analysis) {
588 22         504 $self->analysis($self->analyze_scalar($self->event->value));
589             }
590 22         570 $length += length($self->analysis->scalar);
591             }
592             return (
593 22   33     989 $length < 128 and
594             (
595             $self->event->isa('YAML::Perl::Event::Alias') or
596             (
597             $self->event->isa('YAML::Perl::Event::Scalar') and
598             not $self->analysis->empty and
599             not $self->analysis->multiline
600             ) or
601             $self->check_empty_sequence() or
602             $self->check_empty_mapping()
603             )
604             );
605             }
606              
607             sub process_anchor {
608 109     109 0 169 my $self = shift;
609 109         168 my $indicator = shift;
610 109 100       2611 if (not defined $self->event->anchor) {
611 101         2482 $self->prepared_anchor(undef);
612 101         163 return;
613             }
614 8 50       190 if (not defined $self->prepared_anchor) {
615 8         290 $self->prepared_anchor($self->prepare_anchor($self->event->anchor));
616             }
617 8 50       186 if ($self->prepared_anchor) {
618 8         205 $self->write_indicator($indicator . $self->prepared_anchor, True);
619             }
620             }
621              
622             sub process_tag {
623 105     105 0 150 my $self = shift;
624 105         2526 my $tag = $self->event->tag;
625 105 100       2566 if ($self->event->isa('YAML::Perl::Event::Scalar')) {
626 68 50       1595 if (not $self->style) {
627 68         206 $self->style($self->choose_scalar_style());
628             }
629 68 100 33     3800 if ((not $self->canonical or not $tag) and
      66        
      33        
630             (
631             ($self->style eq '' and $self->event->implicit->[0]) or
632             ($self->style ne '' and $self->event->implicit->[1])
633             )
634             ) {
635 65         1719 $self->prepared_tag(undef);
636 65         454 return;
637             }
638 3 50 33     74 if ($self->event->implicit->[0] and not $tag) {
639 0         0 $tag = '!';
640 0         0 $self->prepared_tag(undef);
641             }
642             }
643             else {
644 37 100 33     859 if ((not $self->canonical or not $tag) and $self->event->implicit) {
      66        
645 31         1014 $self->prepared_tag(undef);
646 31         50 return;
647             }
648             }
649 9 50       46 if (not $tag) {
650 0         0 throw YAML::Perl::Error::Emitter("tag is not specified");
651             }
652 9 50       228 if (not $self->prepared_tag) {
653 9         36 $self->prepared_tag($self->prepare_tag($tag))
654             }
655 9 50       218 if ($self->prepared_tag) {
656 9         212 $self->write_indicator($self->prepared_tag, True)
657             }
658 9         209 $self->prepared_tag(undef);
659             }
660              
661             sub choose_scalar_style {
662 128     128 0 215 my $self = shift;
663 128 100       4311 if (not $self->analysis) {
664 46         1619 $self->analysis($self->analyze_scalar($self->event->value));
665             }
666 128 100 100     2949 if ($self->event->style and $self->event->style eq '"' or $self->canonical) {
      66        
667 1         28 return '"';
668             }
669              
670             # BEGIN Perl YAML.pm heuristics
671 127 100 100     2948 if ($self->event->value =~ /\n/ and length($self->event->value) >= 16) {
672 1         26 return '|';
673             }
674             # END Perl YAML.pm heuristics
675              
676 126 100 100     3082 if (not $self->event->style and $self->event->implicit->[0]) {
677 120 50 33     3183 if (not (
      33        
      33        
678             $self->simple_key_context and
679             ($self->analysis->empty or $self->analysis->multiline)
680             ) and
681             (
682             $self->flow_level and
683             $self->analysis->allow_flow_plain or
684             (not $self->flow_level and $self->analysis->allow_block_plain)
685             )
686             ) {
687 120         6604 return '';
688             }
689             }
690 6 100 66     143 if ($self->event->style and $self->event->style =~ /^[\|\>]$/) {
691 3 50 33     73 if (
      33        
692             not $self->flow_level and
693             not $self->simple_key_context and
694             $self->analysis->allow_block
695             ) {
696 3         77 return $self->event->style
697             }
698             }
699 3 50 33     75 if (not $self->event->style or $self->event->style eq '\'') {
700 3 50 33     74 if (
      33        
701             $self->analysis->allow_single_quoted and
702             not ($self->simple_key_context and $self->analysis->multiline)
703             ) {
704 3         75 return "'";
705             }
706             }
707 0         0 return '"';
708             }
709              
710             sub process_scalar {
711 68     68 0 123 my $self = shift;
712 68 50       1562 if (not $self->analysis) {
713 0         0 $self->analysis($self->analyze_scalar($self->event->value));
714             }
715 68 100       2414 if (not $self->style) {
716 60         135 $self->style($self->choose_scalar_style());
717             }
718 68         2515 my $split = (not $self->simple_key_context);
719             #if self->analysis->multiline and split \
720             # and (not self->style or self->style in '\'\"'):
721             # self->write_indent()
722 68 100       3586 if ($self->style eq '"') {
    100          
    50          
    100          
723 1         25 $self->write_double_quoted($self->analysis->scalar, $split);
724             }
725             elsif ($self->style eq "'") {
726 3         70 $self->write_single_quoted($self->analysis->scalar, $split);
727             }
728             elsif ($self->style eq '>') {
729 0         0 $self->write_folded($self->analysis->scalar);
730             }
731             elsif ($self->style eq '|') {
732 4         92 $self->write_literal($self->analysis->scalar);
733             }
734             else {
735 60         1448 $self->write_plain($self->analysis->scalar, $split)
736             }
737 68         2415 $self->analysis(undef);
738 68         1696 $self->style(undef);
739             }
740              
741             sub prepare_version {
742 1     1 0 3 my $self = shift;
743 1         4 my $version = shift;
744 1         5 my ($major, $minor) = split('\.', $version);
745 1 50       7 if ($major != 1) {
746 0         0 throw YAML::Perl::Error::Emitter->("unsupported YAML version: $major.$minor");
747             }
748 1         5 return "$major.$minor";
749             }
750              
751             sub prepare_tag_handle {
752 0     0 0 0 my $self = shift;
753 0         0 my $handle = shift;
754 0 0       0 if (not $handle) {
755 0         0 throw YAML::Perl::Error::Emitter("tag handle must not be empty");
756             }
757 0 0 0     0 if (substr($handle, 0, 1) ne '!' or substr($handle, -1, 1) ne '!') {
758 0         0 throw YAML::Perl::Error::Emitter(
759             "tag handle must start and end with '!': $handle"
760             # .encode('utf-8'))
761             );
762             }
763 0         0 for my $ch (split '', substr($handle, 1, length($handle) - 2)) {
764 0 0 0     0 if (not (
      0        
      0        
      0        
      0        
      0        
765             $ch ge '0' and $ch le '9' or
766             $ch ge 'A' and $ch le 'Z' or
767             $ch ge 'a' and $ch le 'z' or
768             $ch =~ /^[\-\_]$/
769             )) {
770 0         0 throw YAML::Perl::Error::Emitter(
771             "invalid character '$ch' in the tag handle: $handle"
772             # % (ch.encode('utf-8'), handle.encode('utf-8')))
773             );
774             }
775             }
776 0         0 return $handle;
777             }
778              
779             sub prepare_tag_prefix {
780 0     0 0 0 my $self = shift;
781 0         0 my $prefix = shift;
782 0 0       0 if (not length $prefix) {
783 0         0 throw YAML::Perl::Error::Emitter("tag prefix must not be empty");
784             }
785 0         0 my $chunks = [];
786 0         0 my $start = 0;
787 0         0 my $end = 0;
788 0 0       0 if (substr($prefix, 0, 1) eq '!') {
789 0         0 $end = 1;
790             }
791 0         0 while ($end < length($prefix)) {
792 0         0 my $ch = substr($prefix, $end, 1);
793 0 0 0     0 if ($ch ge '0' and $ch le '9' or
      0        
      0        
      0        
      0        
      0        
794             $ch ge 'A' and $ch le 'Z' or
795             $ch ge 'a' and $ch le 'z' or
796             $ch =~ /^[\-\;\/\?\!\:\@\&\=\+\$\,\_\.\~\*\\\'\(\)\[\]]$/
797             ) {
798 0         0 $end += 1;
799             }
800             else {
801 0 0       0 if ($start < $end) {
802 0         0 push @$chunks, substr($prefix, $start, $end);
803             }
804 0         0 $start = $end = $end + 1;
805 0         0 my $data = $ch; #.encode('utf-8')
806 0         0 for $ch (split '', $data) {
807 0         0 push @$chunks, sprintf '%%%02X', ord($ch);
808             }
809             }
810             }
811 0 0       0 if ($start < $end) {
812 0         0 push @$chunks, substr($prefix, $start, $end);
813             }
814 0         0 return join '', @$chunks;
815             }
816              
817             sub prepare_tag {
818 9     9 0 17 my $self = shift;
819 9         17 my $tag = shift;
820              
821 9 50       26 if (not $tag) {
822 0         0 throw YAML::Perl::Error::Emitter("tag must not be empty");
823             }
824 9 50       24 if ($tag eq '!') {
825 0         0 return $tag;
826             }
827 9         17 my $handle = undef;
828 9         12 my $suffix = $tag;
829 9         18 for my $prefix (keys %{$self->tag_prefixes}) {
  9         217  
830 18 50 33     392 if (
      66        
831             $tag =~ /^\Q$prefix\E/ and
832             ($prefix eq '!' or length($prefix) < length($tag))
833             ) {
834 9         227 $handle = $self->tag_prefixes->{$prefix};
835 9         40 $suffix = substr($tag, length($prefix));
836             }
837             }
838 9         25 my $chunks = [];
839 9         16 my $start = 0;
840 9         13 my $end = 0;
841 9         26 while ($end < length($suffix)) {
842 126         160 my $ch = substr($suffix, $end, 1);
843 126 50 66     1381 if (
      100        
      33        
      66        
      66        
      66        
      0        
      33        
844             $ch ge '0' and $ch le '9' or
845             $ch ge 'A' and $ch le 'Z' or
846             $ch ge 'a' and $ch le 'z' or
847             $ch =~ /^[\-\;\/\?\:\@\&\=\+\$\,\_\.\~\*\\\'\(\)\[\]]$/ or
848             ($ch eq '!' and $handle ne '!')
849             ) {
850 126         274 $end += 1;
851             }
852             else {
853 0 0       0 if ($start < $end) {
854 0         0 push @$chunks, substr($suffix, $start, $end - $start);
855             }
856 0         0 $start = $end = $end + 1;
857 0         0 my $data = $ch; #.encode('utf-8')
858 0         0 for $ch (split '', $data) {
859 0         0 push @$chunks, sprintf '%%%02X', ord($ch);
860             }
861             }
862             }
863 9 50       24 if ($start < $end) {
864 9         30 push @$chunks, substr($suffix, $start, $end - $start);
865             }
866 9         22 my $suffix_text = join '', @$chunks;
867 9 50       21 if ($handle) {
868 9         252 return "$handle$suffix_text";
869             }
870             else {
871 0         0 return "!<$suffix_text>";
872             }
873             }
874              
875             sub prepare_anchor {
876 8     8 0 15 my $self = shift;
877 8         15 my $anchor = shift;
878 8 50       37 if (not $anchor) {
879 0         0 throw YAML::Perl::Error::Emitter("anchor must not be empty");
880             }
881 8         45 foreach my $ch (split('', $anchor)) {
882 24 50       88 if ($ch !~ /[0-9A-Za-z-_]/) {
883 0         0 throw YAML::Perl::Error::Emitter("invalid character $ch in the anchor $anchor");
884             }
885             }
886 8         201 return $anchor;
887             }
888              
889             sub analyze_scalar {
890 68     68 0 115 my $self = shift;
891 68         120 my $scalar = shift;
892              
893             # Empty scalar is a special case.
894 68 50       299 if (not length $scalar) {
895 0         0 return YAML::Perl::ScalarAnalysis->new(
896             scalar => $scalar,
897             empty => True,
898             multiline => False,
899             allow_flow_plain => False,
900             allow_block_plain => True,
901             allow_single_quoted => True,
902             allow_double_quoted => True,
903             allow_block => False,
904             );
905             }
906              
907             # Indicators and special characters.
908 68         99 my $block_indicators = False;
909 68         108 my $flow_indicators = False;
910 68         85 my $line_breaks = False;
911 68         92 my $special_characters = False;
912              
913             # Whitespaces.
914 68         100 my $inline_spaces = False; # non-space space+ non-space
915 68         257 my $inline_breaks = False; # non-space break+ non-space
916 68         89 my $leading_spaces = False; # ^ space+ (non-space | $)
917 68         89 my $leading_breaks = False; # ^ break+ (non-space | $)
918 68         92 my $trailing_spaces = False; # (^ | non-space) space+ $
919 68         95 my $trailing_breaks = False; # (^ | non-space) break+ $
920 68         93 my $inline_breaks_spaces = False; # non-space break+ space+ non-space
921 68         94 my $mixed_breaks_spaces = False; # anything else
922              
923             # Check document indicators.
924 68 100 66     554 if ($scalar =~ /^---/ or $scalar =~ /^.../) {
925 8         16 $block_indicators = True;
926 8         17 $flow_indicators = True;
927             }
928              
929             # First character or preceded by a whitespace.
930 68         107 my $preceeded_by_space = True;
931              
932             # Last character or followed by a whitespace.
933 68   66     451 my $followed_by_space =
934             (length($scalar) == 1 or $scalar =~ /^.[\0 \t\r\n\x85\x{2028}\x{2029}]/s);
935              
936             # The current series of whitespaces contain plain spaces.
937 68         102 my $spaces = False;
938              
939             # The current series of whitespaces contain line breaks.
940 68         87 my $breaks = False;
941              
942             # The current series of whitespaces contain a space followed by a
943             # break.
944 68         95 my $mixed = False;
945              
946             # The current series of whitespaces start at the beginning of the
947             # scalar.
948 68         103 my $leading = False;
949              
950 68         95 my $index = 0;
951 68         178 while ($index < length($scalar)) {
952 229         411 my $ch = substr($scalar, $index, 1);
953              
954             # Check for indicators.
955              
956 229 100       397 if ($index == 0) {
957             # Leading indicators are special characters.
958 68 50       393 if ($ch =~ /^[\#\,\[\]\{\}\&\*\!\|\>\'\"\%\@\`]$/) {
959 0         0 $flow_indicators = True;
960 0         0 $block_indicators = True;
961             }
962 68 50       207 if ($ch =~ /^[\?\:]$/) {
963 0         0 $flow_indicators = True;
964 0 0       0 if ($followed_by_space) {
965 0         0 $block_indicators = True;
966             }
967             }
968 68 50 33     237 if ($ch eq '-' and $followed_by_space) {
969 0         0 $flow_indicators = True;
970 0         0 $block_indicators = True;
971             }
972             }
973             else {
974             # Some indicators cannot appear within a scalar as well.
975 161 50       552 if ($ch =~ /^[\,\?\[\]\{\}]$/) {
976 0         0 $flow_indicators = True;
977             }
978 161 50       321 if ($ch eq ':') {
979 0         0 $flow_indicators = True;
980 0 0       0 if ($followed_by_space) {
981 0         0 $block_indicators = True;
982             }
983             }
984 161 50 33     549 if ($ch eq '#' and $preceeded_by_space) {
985 0         0 $flow_indicators = True;
986 0         0 $block_indicators = True;
987             }
988             }
989              
990             # Check for line breaks, special, and unicode characters.
991              
992 229 100       575 if ($ch =~ /^[\n\x85\x{2028}\x{2029}]$/) {
993 11         17 $line_breaks = True;
994             }
995 229 50 33     2293 if (not ($ch eq "\n" or $ch ge "\x20" and $ch le "\x7E")) {
      66        
996 0 0 0     0 if (
      0        
997             (
998             $ch eq "\x85" or
999             $ch ge "\xA0" and $ch le "\x{D7FF}" or
1000             $ch ge "\x{E000}" and $ch le "\x{FFFD}"
1001             ) and $ch ne "\x{FEFF}"
1002             ) {
1003 0         0 my $unicode_characters = True;
1004 0 0       0 if (not $self->allow_unicode) {
1005 0         0 $special_characters = True;
1006             }
1007             }
1008             else {
1009 0         0 $special_characters = True;
1010             }
1011             }
1012              
1013             # Spaces, line breaks, and how they are mixed. State machine.
1014              
1015             # Start or continue series of whitespaces.
1016 229 100 100     1138 if ($ch =~ /^[\ \n\x85\x{2028}\x{2029}]$/) {
    100          
1017 24 50 33     144 if ($spaces and $breaks) {
    50          
    50          
1018 0 0       0 if ($ch ne ' ') { # break+ (space+ break+) => mixed
1019 0         0 $mixed = True;
1020             }
1021             }
1022             elsif ($spaces) {
1023 0 0       0 if ($ch ne ' ') { # (space+ break+) => mixed
1024 0         0 $breaks = True;
1025 0         0 $mixed = True;
1026             }
1027             }
1028             elsif ($breaks) {
1029 0 0       0 if ($ch eq ' ') { # break+ space+
1030 0         0 $spaces = True;
1031             }
1032             }
1033             else {
1034 24         41 $leading = ($index == 0);
1035 24 100       56 if ($ch eq ' ') { # space+
1036 13         26 $spaces = True;
1037             }
1038             else { # break+
1039 11         20 $breaks = True;
1040             }
1041             }
1042             }
1043              
1044             # Series of whitespaces ended with a non-space.
1045             elsif ($spaces or $breaks) {
1046 19 50       42 if ($leading) {
1047 0 0 0     0 if ($spaces and $breaks) {
    0          
    0          
1048 0         0 $mixed_breaks_spaces = True;
1049             }
1050             elsif ($spaces) {
1051 0         0 $leading_spaces = True;
1052             }
1053             elsif ($breaks) {
1054 0         0 $leading_breaks = True;
1055             }
1056             }
1057             else {
1058 19 50 66     130 if ($mixed) {
    50          
    100          
    50          
1059 0         0 $mixed_breaks_spaces = True;
1060             }
1061             elsif ($spaces and $breaks) {
1062 0         0 $inline_breaks_spaces = True;
1063             }
1064             elsif ($spaces) {
1065 13         37 $inline_spaces = True;
1066             }
1067             elsif ($breaks) {
1068 6         11 $inline_breaks = True;
1069             }
1070             }
1071 19         37 $spaces = $breaks = $mixed = $leading = False;
1072             }
1073              
1074             # Series of whitespaces reach the end.
1075 229 100 100     1205 if (($spaces or $breaks) and ($index == (length($scalar) - 1))) {
      100        
1076 5 50 33     40 if ($spaces and $breaks) {
    50          
    50          
1077 0         0 $mixed_breaks_spaces = True;
1078             }
1079             elsif ($spaces) {
1080 0         0 $trailing_spaces = True;
1081 0 0       0 if ($leading) {
1082 0         0 $leading_spaces = True;
1083             }
1084             }
1085             elsif ($breaks) {
1086 5         9 $trailing_breaks = True;
1087 5 50       14 if ($leading) {
1088 0         0 $leading_breaks = True;
1089             }
1090             }
1091 5         11 $spaces = $breaks = $mixed = $leading = False;
1092             }
1093              
1094             # Prepare for the next character.
1095 229         327 $index += 1;
1096 229         1352 $preceeded_by_space = ($ch =~ /^[\0 \t\r\n\x85\x{2028}\x{2029}]$/);
1097 229   66     1526 $followed_by_space = (
1098             $index + 1 >= length($scalar) or
1099             substr($scalar, index + 1, 1) =~ /^[\0\ \t\r\n\x85\x{2028}\x{2029}]$/
1100             );
1101             }
1102              
1103             # Let's decide what styles are allowed.
1104 68         117 my $allow_flow_plain = True;
1105 68         94 my $allow_block_plain = True;
1106 68         87 my $allow_single_quoted = True;
1107 68         81 my $allow_double_quoted = True;
1108 68         101 my $allow_block = True;
1109              
1110             # Leading and trailing whitespace are bad for plain scalars. We also
1111             # do not want to mess with leading whitespaces for block scalars.
1112 68 50 33     783 if ($leading_spaces or $leading_breaks or $trailing_spaces) {
      33        
1113 0         0 $allow_flow_plain = $allow_block_plain = $allow_block = False;
1114             }
1115              
1116             # Trailing breaks are fine for block scalars, but unacceptable for
1117             # plain scalars.
1118 68 100       152 if ($trailing_breaks) {
1119 5         13 $allow_flow_plain = $allow_block_plain = False;
1120             }
1121              
1122             # The combination of (space+ break+) is only acceptable for block
1123             # scalars.
1124 68 50       153 if ($inline_breaks_spaces) {
1125 0         0 $allow_flow_plain = $allow_block_plain = $allow_single_quoted = False;
1126             }
1127              
1128             # Mixed spaces and breaks, as well as special character are only
1129             # allowed for double quoted scalars.
1130 68 50 33     370 if ($mixed_breaks_spaces or $special_characters) {
1131 0         0 $allow_flow_plain = $allow_block_plain =
1132             $allow_single_quoted = $allow_block = False;
1133             }
1134              
1135             # We don't emit multiline plain scalars.
1136 68 100       504 if ($line_breaks) {
1137 5         11 $allow_flow_plain = $allow_block_plain = False;
1138             }
1139              
1140             # Flow indicators are forbidden for flow plain scalars.
1141 68 100       321 if ($flow_indicators) {
1142 8         16 $allow_flow_plain = False;
1143             }
1144              
1145             # Block indicators are forbidden for block plain scalars.
1146 68 100       131 if ($block_indicators) {
1147 8         14 $allow_block_plain = False;
1148             }
1149              
1150 68         449 return YAML::Perl::ScalarAnalysis->new(
1151             scalar => $scalar,
1152             empty => False,
1153             multiline => $line_breaks,
1154             allow_flow_plain => $allow_flow_plain,
1155             allow_block_plain => $allow_block_plain,
1156             allow_single_quoted => $allow_single_quoted,
1157             allow_double_quoted => $allow_double_quoted,
1158             allow_block => $allow_block,
1159             );
1160             }
1161              
1162             sub flush_stream {
1163 45     45 0 76 my $self = shift;
1164 45 50       1077 if ($self->writer->stream->can('flush')) {
1165 0         0 $self->writer->stream->flush();
1166             }
1167             }
1168              
1169             sub write_stream_start {
1170 29     29 0 63 my $self = shift;
1171 29 50 33     758 if ($self->encoding and $self->encoding =~ /^utf-16/) {
1172 0         0 $self->writer->write("\xff\xfe");
1173             }
1174             }
1175              
1176             sub write_stream_end {
1177 16     16 0 40 my $self = shift;
1178 16         49 $self->flush_stream();
1179             }
1180              
1181             sub write_indicator {
1182 133     133 0 212 my $self = shift;
1183 133         203 my $indicator = shift;
1184 133         175 my $need_whitespace = shift;
1185 133         189 my ($whitespace, $indention) = @{{@_}}{qw(whitespace indention)};
  133         402  
1186 133 100       390 $whitespace = False unless defined $whitespace;
1187 133 100       286 $indention = False unless defined $indention;
1188              
1189 133         163 my $data;
1190 133 100 100     3395 if ($self->whitespace or not $need_whitespace) {
1191 100         174 $data = $indicator;
1192             }
1193             else {
1194 33         57 $data = ' ' . $indicator;
1195             }
1196 133         3296 $self->whitespace($whitespace);
1197 133   100     3216 $self->indention($self->indention and $indention);
1198 133         3117 $self->column($self->column + length($data));
1199 133 50       3277 if ($self->encoding) {
1200             # my $data = $data->encode($self->encoding);
1201             }
1202 133         3117 $self->writer->write($data);
1203             }
1204              
1205             sub write_indent {
1206 124     124 0 261 my $self = shift;
1207 124   100     3117 my $indent = $self->indent || 0;
1208 124 50 66     3051 if (not $self->indention or
      66        
      66        
1209             $self->column > $indent or
1210             ($self->column == $indent and not $self->whitespace)
1211             ) {
1212 83         267 $self->write_line_break();
1213             }
1214 124 100       3114 if ($self->column < $indent) {
1215 17         475 $self->whitespace(True);
1216 17         424 my $data = ' ' x ($indent - $self->column);
1217 17         7815 $self->column($indent);
1218 17 50       424 if ($self->encoding) {
1219             # $data = $data->encode($self->encoding); #XXX
1220             }
1221 17         477 $self->writer->write($data);
1222             }
1223             }
1224              
1225             sub write_line_break {
1226 97     97 0 144 my $self = shift;
1227 97         151 my $data = shift;
1228 97 50       239 if (not defined $data) {
1229 97         2454 $data = $self->best_line_break;
1230             }
1231 97         2423 $self->whitespace(True);
1232 97         2298 $self->indention(True);
1233 97         2432 $self->line($self->line + 1);
1234 97         2667 $self->column(0);
1235 97 50       2292 if ($self->encoding) {
1236             # $data = $data->encode($self->encoding);
1237             }
1238 97         2250 $self->writer->write($data);
1239             }
1240              
1241             sub write_version_directive {
1242 1     1 0 2 my $self = shift;
1243 1         4 my $version_text = shift;
1244 1         3 my $data = "%YAML $version_text";
1245 1 50       29 if ($self->encoding) {
1246             # $data = $data->encode($self->encoding);
1247             }
1248 1         29 $self->writer->write($data);
1249 1         7 $self->write_line_break();
1250             }
1251              
1252             sub write_tag_directive {
1253 0     0 0 0 die 'write_tag_directive';
1254             }
1255              
1256             sub write_single_quoted {
1257 3     3 0 9 my $self = shift;
1258 3         13 my $text = shift;
1259 3 50       21 my $split = @_ ? shift : True;
1260              
1261 3         12 $self->write_indicator('\'', True);
1262 3         7 my $spaces = False;
1263 3         8 my $breaks = False;
1264 3         6 my $start = 0;
1265 3         6 my $end = 0;
1266 3         14 while ($end <= length($text)) {
1267 39         53 my $ch = undef;
1268 39 100       81 if ($end < length($text)) {
1269 36         66 $ch = substr($text, $end, 1);
1270             }
1271 39 100       90 if ($spaces) {
    50          
1272 3 50 33     29 if (not defined $ch or $ch ne ' ') {
1273 3 50 33     108 if ($start + 1 == $end and
      33        
      33        
      0        
1274             $self->column > $self->best_width and
1275             $split and
1276             $start != 0 and
1277             $end != length($text)
1278             ) {
1279 0         0 $self->write_indent();
1280             }
1281             else {
1282 3         10 my $data = substr($text, $start, $end - $start);
1283 3         75 $self->column($self->column + length($data));
1284 3 50       82 if ($self->encoding) {
1285             # my $data = $data->encode($self->encoding);
1286             }
1287 3         75 $self->writer->write($data);
1288             }
1289 3         8 $start = $end;
1290             }
1291             }
1292             elsif ($breaks) {
1293 0 0 0     0 if (not defined $ch or $ch !~ /^[\n\x85\x{2028}\x{2029}]$/) {
1294 0 0       0 if (substr($text, $start, 1) eq "\n") {
1295 0         0 $self->write_line_break();
1296             }
1297 0         0 for my $br (split '', substr($text, $start, $end - $start)) {
1298 0 0       0 if ($br eq "\n") {
1299 0         0 $self->write_line_break();
1300             }
1301             else {
1302 0         0 $self->write_line_break($br);
1303             }
1304             }
1305 0         0 $self->write_indent();
1306 0         0 $start = $end;
1307             }
1308             }
1309             else {
1310 36 100 100     254 if (not defined $ch or
      66        
1311             $ch =~ /^[\ \n\x85\x{2028}\x{2029}]$/ or
1312             $ch eq '\''
1313             ) {
1314 6 50       17 if ($start < $end) {
1315 6         15 my $data = substr($text, $start, $end - $start);
1316 6         150 $self->column($self->column + length($data));
1317 6 50       139 if ($self->encoding) {
1318             # $data = $data->encode($self->encoding);
1319             }
1320 6         145 $self->writer->write($data);
1321 6         17 $start = $end;
1322             }
1323             }
1324             }
1325 39 50 66     153 if ($ch and $ch eq '\'') {
1326 0         0 my $data = '\'\'';
1327 0         0 $self->column($self->column + 2);
1328 0 0       0 if ($self->encoding) {
1329             # $data = $data->encode($self->encoding);
1330             }
1331 0         0 $self->writer->write($data);
1332 0         0 $start = $end + 1;
1333             }
1334 39 100       84 if (defined $ch) {
1335 36         44 $spaces = ($ch eq ' ');
1336 36         84 $breaks = ($ch =~ /^[\n\x85\x{2028}\x{2029}]$/);
1337             }
1338 39         85 $end += 1;
1339             }
1340 3         19 $self->write_indicator('\'', False);
1341             }
1342              
1343 7         25805 use constant ESCAPE_REPLACEMENTS => {
1344             "\0" => '0',
1345             "\x07" => 'a',
1346             "\x08" => 'b',
1347             "\x09" => 't',
1348             "\x0A" => 'n',
1349             "\x0B" => 'v',
1350             "\x0C" => 'f',
1351             "\x0D" => 'r',
1352             "\x1B" => 'e',
1353             "\"" => '"',
1354             "\\" => '\\',
1355             "\x85" => 'N',
1356             "\xA0" => '_',
1357             "\x{2028}" => 'L',
1358             "\x{2029}" => 'P',
1359 7     7   92 };
  7         14  
1360              
1361             sub write_double_quoted {
1362 1     1 0 2 my $self = shift;
1363 1         3 my $text = shift;
1364 1 50       5 my $split = @_ ? shift : True;
1365              
1366 1         5 $self->write_indicator('"', True);
1367 1         2 my $start = 0;
1368 1         3 my $end = 0;
1369 1         5 while ($end <= length($text)) {
1370 9         14 my $ch = undef;
1371 9 100       23 if ($end < length($text)) {
1372 8         18 $ch = substr($text, $end, 1);
1373             }
1374 9 100 66     226 if (not defined $ch or
      66        
      100        
1375             $ch =~ /^[\"\\\x85\x{2028}\x{2029}\x{FEFF}]$/ or
1376             not (
1377             $ch ge "\x20" and $ch le "\x7E" or
1378             ($self->allow_unicode and
1379             (
1380             $ch ge "\xA0" and $ch le "\x{D7FF}" or
1381             $ch ge "\x{E000}" and $ch le "\x{FFFD}"
1382             )
1383             )
1384             )) {
1385 3 100       8 if ($start < $end) {
1386 2         6 my $data = substr($text, $start, $end - $start);
1387 2         55 $self->column($self->column + length($data));
1388 2 50       111 if ($self->encoding) {
1389             # $data = $data; # .encode(self.encoding)
1390             }
1391 2         55 $self->writer->write($data);
1392 2         5 $start = $end;
1393             }
1394 3 100       9 if (defined $ch) {
1395 2         5 my $data;
1396 2 50       8 if (defined ESCAPE_REPLACEMENTS->{$ch}) {
    0          
1397 2         14 $data = '\\' . ESCAPE_REPLACEMENTS->{$ch};
1398             }
1399             elsif ($ch le "\xFF") {
1400 0         0 $data = sprintf "\\x%02X", ord($ch);
1401             }
1402             # elsif ($ch le "\x{ffff}") {
1403             # $data = sprintf "\\u%04X", ord($ch);
1404             # }
1405             else {
1406 0         0 $data = printf "\\U%08X", ord($ch);
1407             }
1408 2         57 $self->column($self->column + length($data));
1409 2 50       55 if ($self->encoding) {
1410             # $data = $data; # .encode(self.encoding)
1411             }
1412 2         59 $self->writer->write($data);
1413 2         5 $start = $end + 1;
1414             }
1415             }
1416 9 50 100     189 if ($end > 0 and $end < (length($text) - 1) and
      66        
      66        
      66        
      33        
1417             ($ch eq ' ' or $start >= $end) and
1418             ($self->column + ($end - $start)) > $self->best_width and
1419             $split
1420             ) {
1421 0         0 my $data = substr($text, $start, $end - $start) . '\\';
1422 0 0       0 if ($start < $end) {
1423 0         0 $start = $end;
1424             }
1425 0         0 $self->column($self->column + length($data));
1426 0 0       0 if ($self->encoding) {
1427             # $data = $data; # .encode(self.encoding)
1428             }
1429 0         0 $self->writer->write($data);
1430 0         0 $self->write_indent();
1431 0         0 $self->whitespace(False);
1432 0         0 $self->indention(False);
1433 0 0       0 if (substr($text, $start, 1) eq ' ') {
1434 0         0 $data = '\\';
1435 0         0 $self->column($self->column + length($data));
1436 0 0       0 if ($self->encoding) {
1437             # $data = $data; # .encode(self.encoding)
1438             }
1439 0         0 $self->writer->write($data);
1440             }
1441             }
1442 9         24 $end += 1;
1443             }
1444 1         5 $self->write_indicator('"', False);
1445             }
1446              
1447             sub determine_block_hints {
1448 4     4 0 5 my $self = shift;
1449 4         7 my $text = shift;
1450 4         7 my $hints = '';
1451 4 50       12 if ($text) {
1452 4 50       19 if ($text =~ /^[ \n\x85\x{2028}\x{2029}]/) {
1453 0         0 $hints .= $self->best_indent;
1454             }
1455 4 50 33     54 if ($text !~ /[\n\x85\x{2028}\x{2029}]\z/) {
    50          
1456 0         0 $hints .= '-';
1457             }
1458             elsif (length($text) == 1 or $text =~ /[\n\x85\x{2028}\x{2029}].\z/s) {
1459 0         0 $hints .= '+';
1460             }
1461             }
1462 4         11 return $hints;
1463             }
1464              
1465             sub write_folded {
1466 0     0 0 0 die 'write_folded';
1467             }
1468              
1469             sub write_literal {
1470 4     4 0 10 my $self = shift;
1471 4         8 my $text = shift;
1472 4         18 my $chomp = $self->determine_block_hints($text);
1473 4         24 $self->write_indicator('|' . $chomp, True);
1474 4         21 $self->write_line_break();
1475 4         90 my $breaks = True;
1476 4         8 my ($start, $end) = (0, 0);
1477 4         18 while ($end <= length($text)) {
1478 103         123 my $ch = undef;
1479 103 100       281 if ($end < length($text)) {
1480 99         168 $ch = substr($text, $end, 1);
1481             }
1482 103 100       180 if ($breaks) {
1483 13 50 66     71 if (not defined $ch or $ch !~ /^[\n\x85\x{2028}\x{2029}]$/) {
1484 13         580 for my $br (split //, substr($text, $start, $end - $start)) {
1485 9 50       30 if ($br eq "\n") {
1486 9         27 $self->write_line_break();
1487             }
1488             else {
1489 0         0 $self->write_line_break($br);
1490             }
1491             }
1492 13 100       42 if (defined $ch) {
1493 9         27 $self->write_indent();
1494             }
1495 13         34 $start = $end;
1496             }
1497             }
1498             else {
1499 90 100 66     475 if (not defined $ch or $ch =~ /^[\n\x85\x{2028}\x{2029}]$/) {
1500 9         26 my $data = substr($text, $start, $end - $start);
1501 9 50       254 if ($self->encoding) {
1502             # $data = $data->encode($self->encoding);
1503             }
1504 9         237 $self->writer->write($data);
1505 9 50       30 if (not defined $ch) {
1506 0         0 $self->write_line_break();
1507             }
1508 9         17 $start = $end;
1509             }
1510             }
1511 103 100       204 if (defined $ch) {
1512 99 100       248 $breaks = ($ch =~ /^[\n\x85\x{2028}\x{2029}]$/) ? True : False;
1513             }
1514 103         1221 $end += 1;
1515             }
1516             }
1517              
1518             sub write_plain {
1519 60     60 0 116 my $self = shift;
1520 60         93 my $text = shift;
1521 60   50     184 my $split = shift || True;
1522 60 50       152 if (not length $text) {
1523 0         0 return;
1524             }
1525 60 100       1409 if (not $self->whitespace) {
1526 38         70 my $data = ' ';
1527 38         936 $self->column($self->column + length($data));
1528 38 50       1280 if ($self->encoding) {
1529             # $data = $data->encode($self->encoding);
1530             }
1531 38         913 $self->writer->write($data);
1532             }
1533 60         2099 $self->whitespace(False);
1534 60         1872 $self->indention(False);
1535 60         88 my $spaces = False;
1536 60         78 my $breaks = False;
1537 60         95 my ($start, $end) = (0, 0);
1538 60         182 while ($end <= length($text)) {
1539 146         167 my $ch = undef;
1540 146 100       296 if ($end < length($text)) {
1541 86         162 $ch = substr($text, $end, 1);
1542             }
1543 146 50       345 if ($spaces) {
    50          
1544 0 0       0 if ($ch ne ' ') {
1545 0 0 0     0 if ($start + 1 == $end and
      0        
1546             $self->column > $self->best_width and
1547             $split
1548             ) {
1549 0         0 $self->write_indent();
1550 0         0 $self->whitespace(False);
1551 0         0 $self->indention(False);
1552             }
1553             else {
1554 0         0 my $data = substr($text, $start, $end - $start);
1555 0         0 $self->column($self->column + length($data));
1556 0 0       0 if ($self->encoding) {
1557             # $data = $data->encode($self->encoding)
1558             }
1559 0         0 $self->writer->write($data);
1560             }
1561 0         0 $start = $end;
1562             }
1563             }
1564             elsif ($breaks) {
1565 0 0       0 if ($ch !~ /^[\n\x85\x{2028}\x{2029}]$/) {
1566 0 0       0 if (substr($text, $start, 1) eq "\n") {
1567 0         0 $self->write_line_break();
1568             }
1569 0         0 for my $br (split '', substr($text, $start, $end)) {
1570 0 0       0 if ($br eq "\n") {
1571 0         0 $self->write_line_break();
1572             }
1573             else {
1574 0         0 $self->write_line_break($br);
1575             }
1576             }
1577 0         0 $self->write_indent();
1578 0         0 $self->whitespace = False;
1579 0         0 $self->indention = False;
1580 0         0 $start = $end;
1581             }
1582             }
1583             else {
1584 146 100 66     1584 if (not(defined $ch) or $ch =~ /^[\ \n\x85\x{2028}\x{2029}]$/) {
1585 60         142 my $data = substr($text, $start, $end - $start);
1586 60         1486 $self->column($self->column + length($data));
1587 60 50       7212 if ($self->encoding) {
1588             # $data = $data->encode($self->encoding);
1589             }
1590 60         1412 $self->writer->write($data);
1591 60         118 $start = $end;
1592             }
1593             }
1594 146 100       308 if (defined $ch) {
1595 86         142 $spaces = ($ch eq ' ');
1596 86         221 $breaks = ($ch =~ /^[\n\x85\x{2028}\x{2029}]$/);
1597             }
1598 146         399 $end += 1;
1599             }
1600             }
1601              
1602             1;