Coverage Report

Created: 2017-08-18 19:41

/Users/buildslave/jenkins/sharedspace/clang-stage2-coverage-R@2/llvm/tools/polly/lib/External/JSON/json_writer.cpp
Line
Count
Source (jump to first uncovered line)
1
#include <json/writer.h>
2
#include <utility>
3
#include <assert.h>
4
#include <stdio.h>
5
#include <string.h>
6
#include <iostream>
7
#include <sstream>
8
#include <iomanip>
9
10
#if _MSC_VER >= 1400 // VC++ 8.0
11
#pragma warning( disable : 4996 )   // disable warning about strdup being deprecated.
12
#endif
13
14
namespace Json {
15
16
static bool isControlCharacter(char ch)
17
0
{
18
0
   return ch > 0 && ch <= 0x1F;
19
0
}
20
21
static bool containsControlCharacter( const char* str )
22
0
{
23
0
   while ( *str ) 
24
0
   {
25
0
      if ( isControlCharacter( *(str++) ) )
26
0
         return true;
27
0
   }
28
0
   return false;
29
0
}
30
static void uintToString( unsigned int value, 
31
                          char *&current )
32
0
{
33
0
   *--current = 0;
34
0
   do
35
0
   {
36
0
      *--current = (value % 10) + '0';
37
0
      value /= 10;
38
0
   }
39
0
   while ( value != 0 );
40
0
}
41
42
std::string valueToString( Int value )
43
0
{
44
0
   char buffer[32];
45
0
   char *current = buffer + sizeof(buffer);
46
0
   bool isNegative = value < 0;
47
0
   if ( isNegative )
48
0
      value = -value;
49
0
   uintToString( UInt(value), current );
50
0
   if ( isNegative )
51
0
      *--current = '-';
52
0
   assert( current >= buffer );
53
0
   return current;
54
0
}
55
56
57
std::string valueToString( UInt value )
58
0
{
59
0
   char buffer[32];
60
0
   char *current = buffer + sizeof(buffer);
61
0
   uintToString( value, current );
62
0
   assert( current >= buffer );
63
0
   return current;
64
0
}
65
66
std::string valueToString( double value )
67
0
{
68
0
   char buffer[32];
69
0
#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) // Use secure version with visual studio 2005 to avoid warning. 
70
   sprintf_s(buffer, sizeof(buffer), "%#.16g", value); 
71
#else  
72
0
   sprintf(buffer, "%#.16g", value); 
73
0
#endif
74
0
   char* ch = buffer + strlen(buffer) - 1;
75
0
   if (
*ch != '0'0
)
return buffer0
; // nothing to truncate, so save time
76
0
   
while(0
ch > buffer && 0
*ch == '0'0
)
{0
77
0
     --ch;
78
0
   }
79
0
   char* last_nonzero = ch;
80
0
   while(
ch >= buffer0
)
{0
81
0
     switch(*ch){
82
0
     case '0':
83
0
     case '1':
84
0
     case '2':
85
0
     case '3':
86
0
     case '4':
87
0
     case '5':
88
0
     case '6':
89
0
     case '7':
90
0
     case '8':
91
0
     case '9':
92
0
       --ch;
93
0
       continue;
94
0
     case '.':
95
0
       // Truncate zeroes to save bytes in output, but keep one.
96
0
       *(last_nonzero+2) = '\0';
97
0
       return buffer;
98
0
     default:
99
0
       return buffer;
100
0
     }
101
0
   }
102
0
   return buffer;
103
0
}
104
105
106
std::string valueToString( bool value )
107
0
{
108
0
   return value ? 
"true"0
:
"false"0
;
109
0
}
110
111
std::string valueToQuotedString( const char *value )
112
0
{
113
0
   // Not sure how to handle unicode...
114
0
   if (
strpbrk(value, "\"\\\b\f\n\r\t") == nullptr && 0
!containsControlCharacter( value )0
)
115
0
      return std::string("\"") + value + "\"";
116
0
   // We have to walk value and escape any special characters.
117
0
   // Appending to std::string is not efficient, but this should be rare.
118
0
   // (Note: forward slashes are *not* rare, but I am not escaping them.)
119
0
   unsigned maxsize = strlen(value)*2 + 3; // allescaped+quotes+nullptr
120
0
   std::string result;
121
0
   result.reserve(maxsize); // to avoid lots of mallocs
122
0
   result += "\"";
123
0
   for (const char* c = value; 
*c != 00
;
++c0
)
124
0
   {
125
0
      switch(*c)
126
0
      {
127
0
         case '\"':
128
0
            result += "\\\"";
129
0
            break;
130
0
         case '\\':
131
0
            result += "\\\\";
132
0
            break;
133
0
         case '\b':
134
0
            result += "\\b";
135
0
            break;
136
0
         case '\f':
137
0
            result += "\\f";
138
0
            break;
139
0
         case '\n':
140
0
            result += "\\n";
141
0
            break;
142
0
         case '\r':
143
0
            result += "\\r";
144
0
            break;
145
0
         case '\t':
146
0
            result += "\\t";
147
0
            break;
148
0
         //case '/':
149
0
            // Even though \/ is considered a legal escape in JSON, a bare
150
0
            // slash is also legal, so I see no reason to escape it.
151
0
            // (I hope I am not misunderstanding something.
152
0
            // blep notes: actually escaping \/ may be useful in javascript to avoid </ 
153
0
            // sequence.
154
0
            // Should add a flag to allow this compatibility mode and prevent this 
155
0
            // sequence from occurring.
156
0
         default:
157
0
            if ( isControlCharacter( *c ) )
158
0
            {
159
0
               std::ostringstream oss;
160
0
               oss << "\\u" << std::hex << std::uppercase << std::setfill('0') << std::setw(4) << static_cast<int>(*c);
161
0
               result += oss.str();
162
0
            }
163
0
            else
164
0
            {
165
0
               result += *c;
166
0
            }
167
0
            break;
168
0
      }
169
0
   }
170
0
   result += "\"";
171
0
   return result;
172
0
}
173
174
// Class Writer
175
// //////////////////////////////////////////////////////////////////
176
Writer::~Writer()
177
0
{
178
0
}
179
180
181
// Class FastWriter
182
// //////////////////////////////////////////////////////////////////
183
184
FastWriter::FastWriter()
185
   : yamlCompatiblityEnabled_( false )
186
0
{
187
0
}
188
189
190
void 
191
FastWriter::enableYAMLCompatibility()
192
0
{
193
0
   yamlCompatiblityEnabled_ = true;
194
0
}
195
196
197
std::string 
198
FastWriter::write( const Value &root )
199
0
{
200
0
   document_ = "";
201
0
   writeValue( root );
202
0
   document_ += "\n";
203
0
   return document_;
204
0
}
205
206
207
void 
208
FastWriter::writeValue( const Value &value )
209
0
{
210
0
   switch ( value.type() )
211
0
   {
212
0
   case nullValue:
213
0
      document_ += "null";
214
0
      break;
215
0
   case intValue:
216
0
      document_ += valueToString( value.asInt() );
217
0
      break;
218
0
   case uintValue:
219
0
      document_ += valueToString( value.asUInt() );
220
0
      break;
221
0
   case realValue:
222
0
      document_ += valueToString( value.asDouble() );
223
0
      break;
224
0
   case stringValue:
225
0
      document_ += valueToQuotedString( value.asCString() );
226
0
      break;
227
0
   case booleanValue:
228
0
      document_ += valueToString( value.asBool() );
229
0
      break;
230
0
   case arrayValue:
231
0
      {
232
0
         document_ += "[";
233
0
         int size = value.size();
234
0
         for ( int index =0; 
index < size0
;
++index0
)
235
0
         {
236
0
            if ( index > 0 )
237
0
               document_ += ",";
238
0
            writeValue( value[index] );
239
0
         }
240
0
         document_ += "]";
241
0
      }
242
0
      break;
243
0
   case objectValue:
244
0
      {
245
0
         Value::Members members( value.getMemberNames() );
246
0
         document_ += "{";
247
0
         for ( Value::Members::iterator it = members.begin(); 
248
0
               it != members.end(); 
249
0
               ++it )
250
0
         {
251
0
            const std::string &name = *it;
252
0
            if ( it != members.begin() )
253
0
               document_ += ",";
254
0
            document_ += valueToQuotedString( name.c_str() );
255
0
            document_ += yamlCompatiblityEnabled_ ? ": " 
256
0
                                                  : ":";
257
0
            writeValue( value[name] );
258
0
         }
259
0
         document_ += "}";
260
0
      }
261
0
      break;
262
0
   }
263
0
}
264
265
266
// Class StyledWriter
267
// //////////////////////////////////////////////////////////////////
268
269
StyledWriter::StyledWriter()
270
   : rightMargin_( 74 )
271
   , indentSize_( 3 )
272
0
{
273
0
}
274
275
276
std::string 
277
StyledWriter::write( const Value &root )
278
0
{
279
0
   document_ = "";
280
0
   addChildValues_ = false;
281
0
   indentString_ = "";
282
0
   writeCommentBeforeValue( root );
283
0
   writeValue( root );
284
0
   writeCommentAfterValueOnSameLine( root );
285
0
   document_ += "\n";
286
0
   return document_;
287
0
}
288
289
290
void 
291
StyledWriter::writeValue( const Value &value )
292
0
{
293
0
   switch ( value.type() )
294
0
   {
295
0
   case nullValue:
296
0
      pushValue( "null" );
297
0
      break;
298
0
   case intValue:
299
0
      pushValue( valueToString( value.asInt() ) );
300
0
      break;
301
0
   case uintValue:
302
0
      pushValue( valueToString( value.asUInt() ) );
303
0
      break;
304
0
   case realValue:
305
0
      pushValue( valueToString( value.asDouble() ) );
306
0
      break;
307
0
   case stringValue:
308
0
      pushValue( valueToQuotedString( value.asCString() ) );
309
0
      break;
310
0
   case booleanValue:
311
0
      pushValue( valueToString( value.asBool() ) );
312
0
      break;
313
0
   case arrayValue:
314
0
      writeArrayValue( value);
315
0
      break;
316
0
   case objectValue:
317
0
      {
318
0
         Value::Members members( value.getMemberNames() );
319
0
         if ( members.empty() )
320
0
            pushValue( "{}" );
321
0
         else
322
0
         {
323
0
            writeWithIndent( "{" );
324
0
            indent();
325
0
            Value::Members::iterator it = members.begin();
326
0
            while ( true )
327
0
            {
328
0
               const std::string &name = *it;
329
0
               const Value &childValue = value[name];
330
0
               writeCommentBeforeValue( childValue );
331
0
               writeWithIndent( valueToQuotedString( name.c_str() ) );
332
0
               document_ += " : ";
333
0
               writeValue( childValue );
334
0
               if ( ++it == members.end() )
335
0
               {
336
0
                  writeCommentAfterValueOnSameLine( childValue );
337
0
                  break;
338
0
               }
339
0
               document_ += ",";
340
0
               writeCommentAfterValueOnSameLine( childValue );
341
0
            }
342
0
            unindent();
343
0
            writeWithIndent( "}" );
344
0
         }
345
0
      }
346
0
      break;
347
0
   }
348
0
}
349
350
351
void 
352
StyledWriter::writeArrayValue( const Value &value )
353
0
{
354
0
   unsigned size = value.size();
355
0
   if ( size == 0 )
356
0
      pushValue( "[]" );
357
0
   else
358
0
   {
359
0
      bool isArrayMultiLine = isMultineArray( value );
360
0
      if ( isArrayMultiLine )
361
0
      {
362
0
         writeWithIndent( "[" );
363
0
         indent();
364
0
         bool hasChildValue = !childValues_.empty();
365
0
         unsigned index =0;
366
0
         while ( true )
367
0
         {
368
0
            const Value &childValue = value[index];
369
0
            writeCommentBeforeValue( childValue );
370
0
            if ( hasChildValue )
371
0
               writeWithIndent( childValues_[index] );
372
0
            else
373
0
            {
374
0
               writeIndent();
375
0
               writeValue( childValue );
376
0
            }
377
0
            if ( ++index == size )
378
0
            {
379
0
               writeCommentAfterValueOnSameLine( childValue );
380
0
               break;
381
0
            }
382
0
            document_ += ",";
383
0
            writeCommentAfterValueOnSameLine( childValue );
384
0
         }
385
0
         unindent();
386
0
         writeWithIndent( "]" );
387
0
      }
388
0
      else // output on a single line
389
0
      {
390
0
         assert( childValues_.size() == size );
391
0
         document_ += "[ ";
392
0
         for ( unsigned index =0; 
index < size0
;
++index0
)
393
0
         {
394
0
            if ( index > 0 )
395
0
               document_ += ", ";
396
0
            document_ += childValues_[index];
397
0
         }
398
0
         document_ += " ]";
399
0
      }
400
0
   }
401
0
}
402
403
404
bool 
405
StyledWriter::isMultineArray( const Value &value )
406
0
{
407
0
   int size = value.size();
408
0
   bool isMultiLine = size*3 >= rightMargin_ ;
409
0
   childValues_.clear();
410
0
   for ( int index =0; 
index < size && 0
!isMultiLine0
;
++index0
)
411
0
   {
412
0
      const Value &childValue = value[index];
413
0
      isMultiLine = isMultiLine  ||
414
0
                     
( (childValue.isArray() || 0
childValue.isObject()0
) &&
415
0
                        childValue.size() > 0 );
416
0
   }
417
0
   if ( !isMultiLine ) // check if line length > max line length
418
0
   {
419
0
      childValues_.reserve( size );
420
0
      addChildValues_ = true;
421
0
      int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]'
422
0
      for ( int index =0; 
index < size && 0
!isMultiLine0
;
++index0
)
423
0
      {
424
0
         writeValue( value[index] );
425
0
         lineLength += int( childValues_[index].length() );
426
0
         isMultiLine = isMultiLine  &&  hasCommentForValue( value[index] );
427
0
      }
428
0
      addChildValues_ = false;
429
0
      isMultiLine = isMultiLine  ||  lineLength >= rightMargin_;
430
0
   }
431
0
   return isMultiLine;
432
0
}
433
434
435
void 
436
StyledWriter::pushValue( const std::string &value )
437
0
{
438
0
   if ( addChildValues_ )
439
0
      childValues_.push_back( value );
440
0
   else
441
0
      document_ += value;
442
0
}
443
444
445
void 
446
StyledWriter::writeIndent()
447
0
{
448
0
   if ( !document_.empty() )
449
0
   {
450
0
      char last = document_[document_.length()-1];
451
0
      if ( last == ' ' )     // already indented
452
0
         return;
453
0
      
if ( 0
last != '\n'0
) // Comments may add new-line
454
0
         document_ += '\n';
455
0
   }
456
0
   document_ += indentString_;
457
0
}
458
459
460
void 
461
StyledWriter::writeWithIndent( const std::string &value )
462
0
{
463
0
   writeIndent();
464
0
   document_ += value;
465
0
}
466
467
468
void 
469
StyledWriter::indent()
470
0
{
471
0
   indentString_ += std::string( indentSize_, ' ' );
472
0
}
473
474
475
void 
476
StyledWriter::unindent()
477
0
{
478
0
   assert( int(indentString_.size()) >= indentSize_ );
479
0
   indentString_.resize( indentString_.size() - indentSize_ );
480
0
}
481
482
483
void 
484
StyledWriter::writeCommentBeforeValue( const Value &root )
485
0
{
486
0
   if ( !root.hasComment( commentBefore ) )
487
0
      return;
488
0
   document_ += normalizeEOL( root.getComment( commentBefore ) );
489
0
   document_ += "\n";
490
0
}
491
492
493
void 
494
StyledWriter::writeCommentAfterValueOnSameLine( const Value &root )
495
0
{
496
0
   if ( root.hasComment( commentAfterOnSameLine ) )
497
0
      document_ += " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) );
498
0
499
0
   if ( root.hasComment( commentAfter ) )
500
0
   {
501
0
      document_ += "\n";
502
0
      document_ += normalizeEOL( root.getComment( commentAfter ) );
503
0
      document_ += "\n";
504
0
   }
505
0
}
506
507
508
bool 
509
StyledWriter::hasCommentForValue( const Value &value )
510
0
{
511
0
   return value.hasComment( commentBefore )
512
0
          ||  value.hasComment( commentAfterOnSameLine )
513
0
          ||  value.hasComment( commentAfter );
514
0
}
515
516
517
std::string 
518
StyledWriter::normalizeEOL( const std::string &text )
519
0
{
520
0
   std::string normalized;
521
0
   normalized.reserve( text.length() );
522
0
   const char *begin = text.c_str();
523
0
   const char *end = begin + text.length();
524
0
   const char *current = begin;
525
0
   while ( current != end )
526
0
   {
527
0
      char c = *current++;
528
0
      if ( c == '\r' ) // mac or dos EOL
529
0
      {
530
0
         if ( *current == '\n' ) // convert dos EOL
531
0
            ++current;
532
0
         normalized += '\n';
533
0
      }
534
0
      else // handle unix EOL & other char
535
0
         normalized += c;
536
0
   }
537
0
   return normalized;
538
0
}
539
540
541
// Class StyledStreamWriter
542
// //////////////////////////////////////////////////////////////////
543
544
StyledStreamWriter::StyledStreamWriter( std::string indentation )
545
   : document_(nullptr)
546
   , rightMargin_( 74 )
547
   , indentation_( indentation )
548
0
{
549
0
}
550
551
552
void
553
StyledStreamWriter::write( std::ostream &out, const Value &root )
554
0
{
555
0
   document_ = &out;
556
0
   addChildValues_ = false;
557
0
   indentString_ = "";
558
0
   writeCommentBeforeValue( root );
559
0
   writeValue( root );
560
0
   writeCommentAfterValueOnSameLine( root );
561
0
   *document_ << "\n";
562
0
   document_ = nullptr; // Forget the stream, for safety.
563
0
}
564
565
566
void 
567
StyledStreamWriter::writeValue( const Value &value )
568
0
{
569
0
   switch ( value.type() )
570
0
   {
571
0
   case nullValue:
572
0
      pushValue( "null" );
573
0
      break;
574
0
   case intValue:
575
0
      pushValue( valueToString( value.asInt() ) );
576
0
      break;
577
0
   case uintValue:
578
0
      pushValue( valueToString( value.asUInt() ) );
579
0
      break;
580
0
   case realValue:
581
0
      pushValue( valueToString( value.asDouble() ) );
582
0
      break;
583
0
   case stringValue:
584
0
      pushValue( valueToQuotedString( value.asCString() ) );
585
0
      break;
586
0
   case booleanValue:
587
0
      pushValue( valueToString( value.asBool() ) );
588
0
      break;
589
0
   case arrayValue:
590
0
      writeArrayValue( value);
591
0
      break;
592
0
   case objectValue:
593
0
      {
594
0
         Value::Members members( value.getMemberNames() );
595
0
         if ( members.empty() )
596
0
            pushValue( "{}" );
597
0
         else
598
0
         {
599
0
            writeWithIndent( "{" );
600
0
            indent();
601
0
            Value::Members::iterator it = members.begin();
602
0
            while ( true )
603
0
            {
604
0
               const std::string &name = *it;
605
0
               const Value &childValue = value[name];
606
0
               writeCommentBeforeValue( childValue );
607
0
               writeWithIndent( valueToQuotedString( name.c_str() ) );
608
0
               *document_ << " : ";
609
0
               writeValue( childValue );
610
0
               if ( ++it == members.end() )
611
0
               {
612
0
                  writeCommentAfterValueOnSameLine( childValue );
613
0
                  break;
614
0
               }
615
0
               *document_ << ",";
616
0
               writeCommentAfterValueOnSameLine( childValue );
617
0
            }
618
0
            unindent();
619
0
            writeWithIndent( "}" );
620
0
         }
621
0
      }
622
0
      break;
623
0
   }
624
0
}
625
626
627
void 
628
StyledStreamWriter::writeArrayValue( const Value &value )
629
0
{
630
0
   unsigned size = value.size();
631
0
   if ( size == 0 )
632
0
      pushValue( "[]" );
633
0
   else
634
0
   {
635
0
      bool isArrayMultiLine = isMultineArray( value );
636
0
      if ( isArrayMultiLine )
637
0
      {
638
0
         writeWithIndent( "[" );
639
0
         indent();
640
0
         bool hasChildValue = !childValues_.empty();
641
0
         unsigned index =0;
642
0
         while ( true )
643
0
         {
644
0
            const Value &childValue = value[index];
645
0
            writeCommentBeforeValue( childValue );
646
0
            if ( hasChildValue )
647
0
               writeWithIndent( childValues_[index] );
648
0
            else
649
0
            {
650
0
         writeIndent();
651
0
               writeValue( childValue );
652
0
            }
653
0
            if ( ++index == size )
654
0
            {
655
0
               writeCommentAfterValueOnSameLine( childValue );
656
0
               break;
657
0
            }
658
0
            *document_ << ",";
659
0
            writeCommentAfterValueOnSameLine( childValue );
660
0
         }
661
0
         unindent();
662
0
         writeWithIndent( "]" );
663
0
      }
664
0
      else // output on a single line
665
0
      {
666
0
         assert( childValues_.size() == size );
667
0
         *document_ << "[ ";
668
0
         for ( unsigned index =0; 
index < size0
;
++index0
)
669
0
         {
670
0
            if ( index > 0 )
671
0
               *document_ << ", ";
672
0
            *document_ << childValues_[index];
673
0
         }
674
0
         *document_ << " ]";
675
0
      }
676
0
   }
677
0
}
678
679
680
bool 
681
StyledStreamWriter::isMultineArray( const Value &value )
682
0
{
683
0
   int size = value.size();
684
0
   bool isMultiLine = size*3 >= rightMargin_ ;
685
0
   childValues_.clear();
686
0
   for ( int index =0; 
index < size && 0
!isMultiLine0
;
++index0
)
687
0
   {
688
0
      const Value &childValue = value[index];
689
0
      isMultiLine = isMultiLine  ||
690
0
                     
( (childValue.isArray() || 0
childValue.isObject()0
) &&
691
0
                        childValue.size() > 0 );
692
0
   }
693
0
   if ( !isMultiLine ) // check if line length > max line length
694
0
   {
695
0
      childValues_.reserve( size );
696
0
      addChildValues_ = true;
697
0
      int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]'
698
0
      for ( int index =0; 
index < size && 0
!isMultiLine0
;
++index0
)
699
0
      {
700
0
         writeValue( value[index] );
701
0
         lineLength += int( childValues_[index].length() );
702
0
         isMultiLine = isMultiLine  &&  hasCommentForValue( value[index] );
703
0
      }
704
0
      addChildValues_ = false;
705
0
      isMultiLine = isMultiLine  ||  lineLength >= rightMargin_;
706
0
   }
707
0
   return isMultiLine;
708
0
}
709
710
711
void 
712
StyledStreamWriter::pushValue( const std::string &value )
713
0
{
714
0
   if ( addChildValues_ )
715
0
      childValues_.push_back( value );
716
0
   else
717
0
      *document_ << value;
718
0
}
719
720
721
void 
722
StyledStreamWriter::writeIndent()
723
0
{
724
0
  /*
725
0
    Some comments in this method would have been nice. ;-)
726
0
727
0
   if ( !document_.empty() )
728
0
   {
729
0
      char last = document_[document_.length()-1];
730
0
      if ( last == ' ' )     // already indented
731
0
         return;
732
0
      if ( last != '\n' )    // Comments may add new-line
733
0
         *document_ << '\n';
734
0
   }
735
0
  */
736
0
   *document_ << '\n' << indentString_;
737
0
}
738
739
740
void 
741
StyledStreamWriter::writeWithIndent( const std::string &value )
742
0
{
743
0
   writeIndent();
744
0
   *document_ << value;
745
0
}
746
747
748
void 
749
StyledStreamWriter::indent()
750
0
{
751
0
   indentString_ += indentation_;
752
0
}
753
754
755
void 
756
StyledStreamWriter::unindent()
757
0
{
758
0
   assert( indentString_.size() >= indentation_.size() );
759
0
   indentString_.resize( indentString_.size() - indentation_.size() );
760
0
}
761
762
763
void 
764
StyledStreamWriter::writeCommentBeforeValue( const Value &root )
765
0
{
766
0
   if ( !root.hasComment( commentBefore ) )
767
0
      return;
768
0
   *document_ << normalizeEOL( root.getComment( commentBefore ) );
769
0
   *document_ << "\n";
770
0
}
771
772
773
void 
774
StyledStreamWriter::writeCommentAfterValueOnSameLine( const Value &root )
775
0
{
776
0
   if ( root.hasComment( commentAfterOnSameLine ) )
777
0
      *document_ << " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) );
778
0
779
0
   if ( root.hasComment( commentAfter ) )
780
0
   {
781
0
      *document_ << "\n";
782
0
      *document_ << normalizeEOL( root.getComment( commentAfter ) );
783
0
      *document_ << "\n";
784
0
   }
785
0
}
786
787
788
bool 
789
StyledStreamWriter::hasCommentForValue( const Value &value )
790
0
{
791
0
   return value.hasComment( commentBefore )
792
0
          ||  value.hasComment( commentAfterOnSameLine )
793
0
          ||  value.hasComment( commentAfter );
794
0
}
795
796
797
std::string 
798
StyledStreamWriter::normalizeEOL( const std::string &text )
799
0
{
800
0
   std::string normalized;
801
0
   normalized.reserve( text.length() );
802
0
   const char *begin = text.c_str();
803
0
   const char *end = begin + text.length();
804
0
   const char *current = begin;
805
0
   while ( current != end )
806
0
   {
807
0
      char c = *current++;
808
0
      if ( c == '\r' ) // mac or dos EOL
809
0
      {
810
0
         if ( *current == '\n' ) // convert dos EOL
811
0
            ++current;
812
0
         normalized += '\n';
813
0
      }
814
0
      else // handle unix EOL & other char
815
0
         normalized += c;
816
0
   }
817
0
   return normalized;
818
0
}
819
820
821
std::ostream& operator<<( std::ostream &sout, const Value &root )
822
0
{
823
0
   Json::StyledStreamWriter writer;
824
0
   writer.write(sout, root);
825
0
   return sout;
826
0
}
827
828
829
} // namespace Json