emitter.cpp 15.5 KB
Newer Older
1
#include "yaml-cpp/emitter.h"
2
3
4
#include "emitterstate.h"
#include "emitterutils.h"
#include "indentation.h"
5
#include "yaml-cpp/exceptions.h"
6
7
8
9
10
11
12
13
14
15
16
17
#include <sstream>

namespace YAML
{	
	Emitter::Emitter(): m_pState(new EmitterState)
	{
	}
	
	Emitter::~Emitter()
	{
	}
	
18
	const char *Emitter::c_str() const
19
	{
20
		return m_stream.str();
21
22
	}
	
23
	unsigned Emitter::size() const
24
	{
25
		return m_stream.pos();
26
27
28
29
30
31
32
33
34
35
36
37
38
39
	}
	
	// state checking
	bool Emitter::good() const
	{
		return m_pState->good();
	}
	
	const std::string Emitter::GetLastError() const
	{
		return m_pState->GetLastError();
	}

	// global setters
40
41
	bool Emitter::SetOutputCharset(EMITTER_MANIP value)
	{
42
		return m_pState->SetOutputCharset(value, FmtScope::Global);
43
44
	}

45
46
	bool Emitter::SetStringFormat(EMITTER_MANIP value)
	{
47
		return m_pState->SetStringFormat(value, FmtScope::Global);
48
49
50
51
52
	}
	
	bool Emitter::SetBoolFormat(EMITTER_MANIP value)
	{
		bool ok = false;
53
		if(m_pState->SetBoolFormat(value, FmtScope::Global))
54
			ok = true;
55
		if(m_pState->SetBoolCaseFormat(value, FmtScope::Global))
56
			ok = true;
57
		if(m_pState->SetBoolLengthFormat(value, FmtScope::Global))
58
59
60
61
62
63
			ok = true;
		return ok;
	}
	
	bool Emitter::SetIntBase(EMITTER_MANIP value)
	{
64
		return m_pState->SetIntFormat(value, FmtScope::Global);
65
66
67
68
	}
	
	bool Emitter::SetSeqFormat(EMITTER_MANIP value)
	{
69
		return m_pState->SetFlowType(GroupType::Seq, value, FmtScope::Global);
70
71
72
73
74
	}
	
	bool Emitter::SetMapFormat(EMITTER_MANIP value)
	{
		bool ok = false;
75
		if(m_pState->SetFlowType(GroupType::Map, value, FmtScope::Global))
76
			ok = true;
77
		if(m_pState->SetMapKeyFormat(value, FmtScope::Global))
78
79
80
81
82
83
			ok = true;
		return ok;
	}
	
	bool Emitter::SetIndent(unsigned n)
	{
84
		return m_pState->SetIndent(n, FmtScope::Global);
85
86
87
88
	}
	
	bool Emitter::SetPreCommentIndent(unsigned n)
	{
89
		return m_pState->SetPreCommentIndent(n, FmtScope::Global);
90
91
92
93
	}
	
	bool Emitter::SetPostCommentIndent(unsigned n)
	{
94
		return m_pState->SetPostCommentIndent(n, FmtScope::Global);
95
	}
96
97
98
    
    bool Emitter::SetFloatPrecision(unsigned n)
    {
99
        return m_pState->SetFloatPrecision(n, FmtScope::Global);
100
101
102
103
    }

    bool Emitter::SetDoublePrecision(unsigned n)
    {
104
        return m_pState->SetDoublePrecision(n, FmtScope::Global);
105
    }
106
107
108
109
110
111
112
113
114

	// SetLocalValue
	// . Either start/end a group, or set a modifier locally
	Emitter& Emitter::SetLocalValue(EMITTER_MANIP value)
	{
		if(!good())
			return *this;
		
		switch(value) {
115
116
117
118
119
120
			case BeginDoc:
				EmitBeginDoc();
				break;
			case EndDoc:
				EmitEndDoc();
				break;
121
122
123
124
125
126
127
128
129
130
131
132
133
134
			case BeginSeq:
				EmitBeginSeq();
				break;
			case EndSeq:
				EmitEndSeq();
				break;
			case BeginMap:
				EmitBeginMap();
				break;
			case EndMap:
				EmitEndMap();
				break;
			case Key:
			case Value:
Jesse Beder's avatar
Jesse Beder committed
135
                // deprecated (these can be deduced by the parity of nodes in a map)
136
				break;
137
138
139
			case TagByKind:
				EmitKindTag();
				break;
140
141
142
			case Newline:
				EmitNewline();
				break;
143
144
145
146
147
148
149
150
151
			default:
				m_pState->SetLocalValue(value);
				break;
		}
		return *this;
	}
	
	Emitter& Emitter::SetLocalIndent(const _Indent& indent)
	{
152
		m_pState->SetIndent(indent.value, FmtScope::Local);
153
154
155
		return *this;
	}

156
157
158
    Emitter& Emitter::SetLocalPrecision(const _Precision& precision)
    {
        if(precision.floatPrecision >= 0)
159
            m_pState->SetFloatPrecision(precision.floatPrecision, FmtScope::Local);
160
        if(precision.doublePrecision >= 0)
161
            m_pState->SetDoublePrecision(precision.doublePrecision, FmtScope::Local);
162
163
164
        return *this;
    }

165
166
167
168
169
	// EmitBeginDoc
	void Emitter::EmitBeginDoc()
	{
		if(!good())
			return;
Jesse Beder's avatar
Jesse Beder committed
170
171
172
173
174
175
176
177
178
179
180
181
182
183
        
        if(m_pState->CurGroupType() != GroupType::None) {
			m_pState->SetError("Unexpected begin document");
			return;
        }
        
        if(m_pState->HasAnchor() || m_pState->HasTag()) {
			m_pState->SetError("Unexpected begin document");
			return;
        }
        
        if(m_stream.col() > 0)
            m_stream << "\n";
        m_stream << "---\n";
184
185
186
187
188
189
190
	}
	
	// EmitEndDoc
	void Emitter::EmitEndDoc()
	{
		if(!good())
			return;
Jesse Beder's avatar
Jesse Beder committed
191
192
193
194
195
196
197
198
199
200
201
202
203
204
        
        if(m_pState->CurGroupType() != GroupType::None) {
			m_pState->SetError("Unexpected begin document");
			return;
        }
        
        if(m_pState->HasAnchor() || m_pState->HasTag()) {
			m_pState->SetError("Unexpected begin document");
			return;
        }
        
        if(m_stream.col() > 0)
            m_stream << "\n";
        m_stream << "...\n";
205
206
	}

207
208
209
210
211
	// EmitBeginSeq
	void Emitter::EmitBeginSeq()
	{
		if(!good())
			return;
Jesse Beder's avatar
Jesse Beder committed
212
        
213
        PrepareNode(m_pState->NextGroupType(GroupType::Seq));
Jesse Beder's avatar
Jesse Beder committed
214
        
215
        m_pState->StartedGroup(GroupType::Seq);
216
217
218
219
220
221
222
	}
	
	// EmitEndSeq
	void Emitter::EmitEndSeq()
	{
		if(!good())
			return;
Jesse Beder's avatar
Jesse Beder committed
223
        
224
        m_pState->EndedGroup(GroupType::Seq);
225
226
227
228
229
230
231
	}
	
	// EmitBeginMap
	void Emitter::EmitBeginMap()
	{
		if(!good())
			return;
Jesse Beder's avatar
Jesse Beder committed
232

233
        PrepareNode(m_pState->NextGroupType(GroupType::Map));
Jesse Beder's avatar
Jesse Beder committed
234
        
235
        m_pState->StartedGroup(GroupType::Map);
236
237
238
239
240
241
242
	}
	
	// EmitEndMap
	void Emitter::EmitEndMap()
	{
		if(!good())
			return;
Jesse Beder's avatar
Jesse Beder committed
243

244
        m_pState->EndedGroup(GroupType::Map);
Jesse Beder's avatar
Jesse Beder committed
245
    }
246

247
248
249
250
251
	// EmitNewline
	void Emitter::EmitNewline()
	{
		if(!good())
			return;
Jesse Beder's avatar
Jesse Beder committed
252
        
Jesse Beder's avatar
Jesse Beder committed
253
        PrepareNode(EmitterNodeType::None);
Jesse Beder's avatar
Jesse Beder committed
254
255
        m_stream << "\n";
        m_pState->SetNonContent();
256
257
258
259
	}

	bool Emitter::CanEmitNewline() const
	{
Jesse Beder's avatar
Jesse Beder committed
260
        return true;
261
262
	}

Jesse Beder's avatar
Jesse Beder committed
263
264
    // Put the stream in a state so we can simply write the next node
    // E.g., if we're in a sequence, write the "- "
265
    void Emitter::PrepareNode(EmitterNodeType::value child)
Jesse Beder's avatar
Jesse Beder committed
266
    {
267
268
269
        switch(m_pState->CurGroupNodeType()) {
            case EmitterNodeType::None:
                PrepareTopNode(child);
Jesse Beder's avatar
Jesse Beder committed
270
                break;
271
272
            case EmitterNodeType::FlowSeq:
                FlowSeqPrepareNode(child);
Jesse Beder's avatar
Jesse Beder committed
273
                break;
274
275
276
277
278
279
280
281
282
            case EmitterNodeType::BlockSeq:
                BlockSeqPrepareNode(child);
                break;
            case EmitterNodeType::FlowMap:
                FlowMapPrepareNode(child);
                break;
            case EmitterNodeType::BlockMap:
                BlockMapPrepareNode(child);
                break;
283
            case EmitterNodeType::Property:
284
285
            case EmitterNodeType::Scalar:
                assert(false);
Jesse Beder's avatar
Jesse Beder committed
286
287
288
289
                break;
        }
    }
    
290
    void Emitter::PrepareTopNode(EmitterNodeType::value child)
Jesse Beder's avatar
Jesse Beder committed
291
    {
292
293
294
        if(m_pState->CurGroupChildCount() > 0 && m_stream.pos() > 0) {
            if(child != EmitterNodeType::None)
                EmitBeginDoc();
295
296
        }
        
Jesse Beder's avatar
Jesse Beder committed
297
298
        switch(child) {
            case EmitterNodeType::None:
299
            case EmitterNodeType::Property:
Jesse Beder's avatar
Jesse Beder committed
300
301
302
303
304
            case EmitterNodeType::Scalar:
            case EmitterNodeType::FlowSeq:
            case EmitterNodeType::FlowMap:
                // TODO: if we were writing null, and
                // we wanted it blank, we wouldn't want a space
Jesse Beder's avatar
Jesse Beder committed
305
                if(m_pState->HasBegunContent())
Jesse Beder's avatar
Jesse Beder committed
306
307
308
309
310
311
312
313
                    m_stream << " ";
                break;
            case EmitterNodeType::BlockSeq:
            case EmitterNodeType::BlockMap:
                if(m_pState->HasBegunNode())
                    m_stream << "\n";
                break;
        }
Jesse Beder's avatar
Jesse Beder committed
314
315
    }
    
316
    void Emitter::FlowSeqPrepareNode(EmitterNodeType::value child)
Jesse Beder's avatar
Jesse Beder committed
317
318
319
    {
    }

320
    void Emitter::BlockSeqPrepareNode(EmitterNodeType::value child)
Jesse Beder's avatar
Jesse Beder committed
321
    {
Jesse Beder's avatar
Jesse Beder committed
322
        const unsigned curIndent = m_pState->CurIndent();
323
324
        const unsigned nextIndent = curIndent + m_pState->CurGroupIndent();
        
Jesse Beder's avatar
Jesse Beder committed
325
326
327
328
329
        if(child == EmitterNodeType::None)
            return;
        
        if(!m_pState->HasBegunContent()) {
            if(m_pState->CurGroupChildCount() > 0 || m_stream.comment()) {
330
331
332
333
                m_stream << "\n";
            }
            m_stream << IndentTo(curIndent);
            m_stream << "-";
Jesse Beder's avatar
Jesse Beder committed
334
        }
335
336
337
        
        switch(child) {
            case EmitterNodeType::None:
Jesse Beder's avatar
Jesse Beder committed
338
                break;
339
            case EmitterNodeType::Property:
340
341
342
            case EmitterNodeType::Scalar:
            case EmitterNodeType::FlowSeq:
            case EmitterNodeType::FlowMap:
Jesse Beder's avatar
Jesse Beder committed
343
                SpaceOrIndentTo(m_pState->HasBegunContent(), nextIndent);
344
345
346
347
348
                break;
            case EmitterNodeType::BlockSeq:
                m_stream << "\n";
                break;
            case EmitterNodeType::BlockMap:
Jesse Beder's avatar
Jesse Beder committed
349
                if(m_pState->HasBegunContent() || m_stream.comment())
Jesse Beder's avatar
Jesse Beder committed
350
                    m_stream << "\n";
351
352
                break;
        }
Jesse Beder's avatar
Jesse Beder committed
353
354
    }
    
355
    void Emitter::FlowMapPrepareNode(EmitterNodeType::value child)
Jesse Beder's avatar
Jesse Beder committed
356
357
358
    {
    }

359
    void Emitter::BlockMapPrepareNode(EmitterNodeType::value child)
Jesse Beder's avatar
Jesse Beder committed
360
    {
361
362
363
364
        const unsigned curIndent = m_pState->CurIndent();
        const unsigned nextIndent = curIndent + m_pState->CurGroupIndent();
        const std::size_t childCount = m_pState->CurGroupChildCount();

Jesse Beder's avatar
Jesse Beder committed
365
        if(!m_pState->HasBegunNode()) {
366
367
368
369
370
            if(childCount % 2 == 0) {
                // key
                if(childCount > 0) {
                    m_stream << "\n";
                }
371
372
                if(false /* long key */) {
                }
373
374
            } else {
                // value
375
376
377
378
379
380
381
382
383
384
385
                if(false /* was long key */) {
                } else {
                    m_stream << ":";
                }
            }
        }
        
        if(childCount % 2 == 0) {
            // key
            switch(child) {
                case EmitterNodeType::None:
Jesse Beder's avatar
Jesse Beder committed
386
                    break;
387
                case EmitterNodeType::Property:
388
389
390
                case EmitterNodeType::Scalar:
                case EmitterNodeType::FlowSeq:
                case EmitterNodeType::FlowMap:
Jesse Beder's avatar
Jesse Beder committed
391
                    SpaceOrIndentTo(m_pState->HasBegunContent(), curIndent);
392
393
394
395
396
397
398
399
400
                    break;
                case EmitterNodeType::BlockSeq:
                case EmitterNodeType::BlockMap:
                    break;
            }
        } else {
            // value
            switch(child) {
                case EmitterNodeType::None:
Jesse Beder's avatar
Jesse Beder committed
401
                    break;
402
                case EmitterNodeType::Property:
403
404
405
                case EmitterNodeType::Scalar:
                case EmitterNodeType::FlowSeq:
                case EmitterNodeType::FlowMap:
Jesse Beder's avatar
Jesse Beder committed
406
                    SpaceOrIndentTo(true, nextIndent);
407
408
409
410
411
                    break;
                case EmitterNodeType::BlockSeq:
                case EmitterNodeType::BlockMap:
                    m_stream << "\n";
                    break;
412
413
            }
        }
Jesse Beder's avatar
Jesse Beder committed
414
415
    }

Jesse Beder's avatar
Jesse Beder committed
416
417
418
419
420
421
422
423
424
425
426
    // SpaceOrIndentTo
    // . Prepares for some more content by proper spacing
    void Emitter::SpaceOrIndentTo(bool requireSpace, unsigned indent)
    {
        if(m_stream.comment())
            m_stream << "\n";
        if(m_stream.col() > 0 && requireSpace)
            m_stream << " ";
        m_stream << IndentTo(indent);
    }

427
428
429
430
431
432
433
	// *******************************************************************************************
	// overloads of Write
	
	Emitter& Emitter::Write(const std::string& str)
	{
		if(!good())
			return *this;
Jesse Beder's avatar
Jesse Beder committed
434
        
435
        PrepareNode(EmitterNodeType::Scalar);
Jesse Beder's avatar
Jesse Beder committed
436
        
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
		const bool escapeNonAscii = m_pState->GetOutputCharset() == EscapeNonAscii;
        const StringFormat::value strFormat = Utils::ComputeStringFormat(str, m_pState->GetStringFormat(), m_pState->CurGroupFlowType(), escapeNonAscii);
        
        switch(strFormat) {
            case StringFormat::Plain:
                m_stream << str;
                break;
            case StringFormat::SingleQuoted:
                Utils::WriteSingleQuotedString(m_stream, str);
                break;
            case StringFormat::DoubleQuoted:
                Utils::WriteDoubleQuotedString(m_stream, str, escapeNonAscii);
                break;
            case StringFormat::Literal:
                Utils::WriteLiteralString(m_stream, str, m_pState->CurIndent() + m_pState->GetIndent());
                break;
        }

455
        m_pState->StartedScalar();
Jesse Beder's avatar
Jesse Beder committed
456
        
457
458
		return *this;
	}
459

460
461
462
463
464
465
466
467
468
469
    unsigned Emitter::GetFloatPrecision() const
    {
        return m_pState->GetFloatPrecision();
    }
    
    unsigned Emitter::GetDoublePrecision() const
    {
        return m_pState->GetDoublePrecision();
    }

470
471
472
473
474
475
476
	const char *Emitter::ComputeFullBoolName(bool b) const
	{
		const EMITTER_MANIP mainFmt = (m_pState->GetBoolLengthFormat() == ShortBool ? YesNoBool : m_pState->GetBoolFormat());
		const EMITTER_MANIP caseFmt = m_pState->GetBoolCaseFormat();
		switch(mainFmt) {
			case YesNoBool:
				switch(caseFmt) {
477
478
479
480
					case UpperCase: return b ? "YES" : "NO";
					case CamelCase: return b ? "Yes" : "No";
					case LowerCase: return b ? "yes" : "no";
					default: break;
481
				}
482
				break;
483
484
			case OnOffBool:
				switch(caseFmt) {
485
486
487
488
					case UpperCase: return b ? "ON" : "OFF";
					case CamelCase: return b ? "On" : "Off";
					case LowerCase: return b ? "on" : "off";
					default: break;
489
				}
490
491
				break;
			case TrueFalseBool:
492
				switch(caseFmt) {
493
494
495
496
					case UpperCase: return b ? "TRUE" : "FALSE";
					case CamelCase: return b ? "True" : "False";
					case LowerCase: return b ? "true" : "false";
					default: break;
497
				}
498
499
500
				break;
			default:
				break;
501
		}
502
		return b ? "y" : "n"; // should never get here, but it can't hurt to give these answers
503
	}
504

505
506
507
508
	Emitter& Emitter::Write(bool b)
	{
		if(!good())
			return *this;
509

510
        m_pState->StartedScalar();
Jesse Beder's avatar
Jesse Beder committed
511

512
513
514
		return *this;
	}

Jesse Beder's avatar
Jesse Beder committed
515
516
517
518
	Emitter& Emitter::Write(char ch)
	{
		if(!good())
			return *this;
519

520
        m_pState->StartedScalar();
Jesse Beder's avatar
Jesse Beder committed
521

Jesse Beder's avatar
Jesse Beder committed
522
523
524
		return *this;
	}

525
526
527
528
	Emitter& Emitter::Write(const _Alias& alias)
	{
		if(!good())
			return *this;
Jesse Beder's avatar
Jesse Beder committed
529
530
531
532
533
        
        if(m_pState->HasAnchor() || m_pState->HasTag()) {
            m_pState->SetError(ErrorMsg::INVALID_ALIAS);
            return *this;
        }
534

Jesse Beder's avatar
Jesse Beder committed
535
536
537
538
539
540
541
        PrepareNode(EmitterNodeType::Scalar);

		if(!Utils::WriteAlias(m_stream, alias.content)) {
			m_pState->SetError(ErrorMsg::INVALID_ALIAS);
			return *this;
		}
        
542
        m_pState->StartedScalar();
Jesse Beder's avatar
Jesse Beder committed
543

544
545
546
547
548
549
550
		return *this;
	}
	
	Emitter& Emitter::Write(const _Anchor& anchor)
	{
		if(!good())
			return *this;
Jesse Beder's avatar
Jesse Beder committed
551
552
553
554
555
        
        if(m_pState->HasAnchor()) {
            m_pState->SetError(ErrorMsg::INVALID_ANCHOR);
            return *this;
        }
556

557
        PrepareNode(EmitterNodeType::Property);
Jesse Beder's avatar
Jesse Beder committed
558
559
560
561
562
563
564

		if(!Utils::WriteAnchor(m_stream, anchor.content)) {
			m_pState->SetError(ErrorMsg::INVALID_ANCHOR);
			return *this;
		}
        
        m_pState->SetAnchor();
Jesse Beder's avatar
Jesse Beder committed
565

566
567
568
		return *this;
	}
	
569
570
571
572
	Emitter& Emitter::Write(const _Tag& tag)
	{
		if(!good())
			return *this;
573
        
Jesse Beder's avatar
Jesse Beder committed
574
575
576
577
578
        if(m_pState->HasTag()) {
            m_pState->SetError(ErrorMsg::INVALID_TAG);
            return *this;
        }
        
579
        PrepareNode(EmitterNodeType::Property);
Jesse Beder's avatar
Jesse Beder committed
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
        
		bool success = false;
		if(tag.type == _Tag::Type::Verbatim)
			success = Utils::WriteTag(m_stream, tag.content, true);
		else if(tag.type == _Tag::Type::PrimaryHandle)
			success = Utils::WriteTag(m_stream, tag.content, false);
		else
			success = Utils::WriteTagWithPrefix(m_stream, tag.prefix, tag.content);
		
		if(!success) {
			m_pState->SetError(ErrorMsg::INVALID_TAG);
			return *this;
		}

        m_pState->SetTag();

596
		return *this;
597
	}
598

599
600
	void Emitter::EmitKindTag()
	{
601
		Write(LocalTag(""));
602
603
	}

604
605
606
607
	Emitter& Emitter::Write(const _Comment& comment)
	{
		if(!good())
			return *this;
608

609
610
611
612
613
614
615
        PrepareNode(EmitterNodeType::None);
        
		if(m_stream.col() > 0)
			m_stream << Indentation(m_pState->GetPreCommentIndent());
		Utils::WriteComment(m_stream, comment.content, m_pState->GetPostCommentIndent());

        m_pState->SetNonContent();
Jesse Beder's avatar
Jesse Beder committed
616

617
618
		return *this;
	}
619
620
621
622
623

	Emitter& Emitter::Write(const _Null& /*null*/)
	{
		if(!good())
			return *this;
624

625
        m_pState->StartedScalar();
Jesse Beder's avatar
Jesse Beder committed
626

627
628
		return *this;
	}
629

630
	Emitter& Emitter::Write(const Binary& binary)
631
	{
632
633
		Write(SecondaryTag("binary"));

634
635
		if(!good())
			return *this;
636

637
        m_pState->StartedScalar();
Jesse Beder's avatar
Jesse Beder committed
638

639
640
		return *this;
	}
641
}
642