diff --git a/src/scanscalar.cpp b/src/scanscalar.cpp index 3432653..cdbdb60 100644 --- a/src/scanscalar.cpp +++ b/src/scanscalar.cpp @@ -19,7 +19,8 @@ namespace YAML // and different places in the above flow. std::string ScanScalar(Stream& INPUT, ScanScalarParams& params) { - bool foundNonEmptyLine = false, pastOpeningBreak = false; + bool foundNonEmptyLine = false; + bool pastOpeningBreak = (params.fold == FOLD_FLOW); bool emptyLine = false, moreIndented = false; int foldedNewlineCount = 0; bool foldedNewlineStartedMoreIndented = false; @@ -29,6 +30,8 @@ namespace YAML while(INPUT) { // ******************************** // Phase #1: scan until line ending + + std::size_t lastNonWhitespaceChar = scalar.size(); while(!params.end.Matches(INPUT) && !Exp::Break.Matches(INPUT)) { if(!INPUT) break; @@ -48,17 +51,22 @@ namespace YAML if(params.escape == '\\' && Exp::EscBreak.Matches(INPUT)) { int n = Exp::EscBreak.Match(INPUT); INPUT.eat(n); + lastNonWhitespaceChar = scalar.size(); continue; } // escape this? if(INPUT.peek() == params.escape) { scalar += Exp::Escape(INPUT); + lastNonWhitespaceChar = scalar.size(); continue; } // otherwise, just add the damn character - scalar += INPUT.get(); + char ch = INPUT.get(); + scalar += ch; + if(ch != ' ' && ch != '\t') + lastNonWhitespaceChar = scalar.size(); } // eof? if we're looking to eat something, then we throw @@ -79,7 +87,11 @@ namespace YAML INPUT.eat(n); break; } - + + // do we remove trailing whitespace? + if(params.fold == FOLD_FLOW) + scalar.erase(lastNonWhitespaceChar); + // ******************************** // Phase #2: eat line ending n = Exp::Break.Match(INPUT); @@ -111,27 +123,36 @@ namespace YAML // was this an empty line? bool nextEmptyLine = Exp::Break.Matches(INPUT); bool nextMoreIndented = Exp::Blank.Matches(INPUT); - if(params.fold && foldedNewlineCount == 0 && nextEmptyLine) + if(params.fold == FOLD_BLOCK && foldedNewlineCount == 0 && nextEmptyLine) foldedNewlineStartedMoreIndented = moreIndented; // for block scalars, we always start with a newline, so we should ignore it (not fold or keep) if(pastOpeningBreak) { - if(params.fold) { - if(!emptyLine && !nextEmptyLine && !moreIndented && !nextMoreIndented && INPUT.column() >= params.indent) - scalar += " "; - else if(nextEmptyLine) - foldedNewlineCount++; - else + switch(params.fold) { + case DONT_FOLD: scalar += "\n"; - - if(!nextEmptyLine && foldedNewlineCount > 0) { - scalar += std::string(foldedNewlineCount - 1, '\n'); - if(foldedNewlineStartedMoreIndented || nextMoreIndented) + break; + case FOLD_BLOCK: + if(!emptyLine && !nextEmptyLine && !moreIndented && !nextMoreIndented && INPUT.column() >= params.indent) + scalar += " "; + else if(nextEmptyLine) + foldedNewlineCount++; + else scalar += "\n"; - foldedNewlineCount = 0; - } - } else { - scalar += "\n"; + + if(!nextEmptyLine && foldedNewlineCount > 0) { + scalar += std::string(foldedNewlineCount - 1, '\n'); + if(foldedNewlineStartedMoreIndented || nextMoreIndented) + scalar += "\n"; + foldedNewlineCount = 0; + } + break; + case FOLD_FLOW: + if(nextEmptyLine) + scalar += "\n"; + else if(!emptyLine && !nextEmptyLine) + scalar += " "; + break; } } diff --git a/src/scanscalar.h b/src/scanscalar.h index 319a428..6f6f559 100644 --- a/src/scanscalar.h +++ b/src/scanscalar.h @@ -12,9 +12,10 @@ namespace YAML { enum CHOMP { STRIP = -1, CLIP, KEEP }; enum ACTION { NONE, BREAK, THROW }; + enum FOLD { DONT_FOLD, FOLD_BLOCK, FOLD_FLOW }; struct ScanScalarParams { - ScanScalarParams(): eatEnd(false), indent(0), detectIndent(false), eatLeadingWhitespace(0), escape(0), fold(false), + ScanScalarParams(): eatEnd(false), indent(0), detectIndent(false), eatLeadingWhitespace(0), escape(0), fold(DONT_FOLD), trimTrailingSpaces(0), chomp(CLIP), onDocIndicator(NONE), onTabInIndentation(NONE), leadingSpaces(false) {} // input: @@ -24,7 +25,7 @@ namespace YAML bool detectIndent; // should we try to autodetect the indent? bool eatLeadingWhitespace; // should we continue eating this delicious indentation after 'indent' spaces? char escape; // what character do we escape on (i.e., slash or single quote) (0 for none) - bool fold; // do we fold line ends? + FOLD fold; // how do we fold line ends? bool trimTrailingSpaces; // do we remove all trailing spaces (at the very end) CHOMP chomp; // do we strip, clip, or keep trailing newlines (at the very end) // Note: strip means kill all, clip means keep at most one, keep means keep all diff --git a/src/scantoken.cpp b/src/scantoken.cpp index cb56225..df8e11e 100644 --- a/src/scantoken.cpp +++ b/src/scantoken.cpp @@ -287,7 +287,7 @@ namespace YAML params.end = (InFlowContext() ? Exp::EndScalarInFlow : Exp::EndScalar) || (Exp::BlankOrBreak + Exp::Comment); params.eatEnd = false; params.indent = (InFlowContext() ? 0 : GetTopIndent() + 1); - params.fold = true; + params.fold = FOLD_BLOCK; params.eatLeadingWhitespace = true; params.trimTrailingSpaces = true; params.chomp = STRIP; @@ -327,7 +327,7 @@ namespace YAML params.eatEnd = true; params.escape = (single ? '\'' : '\\'); params.indent = 0; - params.fold = true; + params.fold = FOLD_FLOW; params.eatLeadingWhitespace = true; params.trimTrailingSpaces = false; params.chomp = CLIP; @@ -365,7 +365,7 @@ namespace YAML // eat block indicator ('|' or '>') Mark mark = INPUT.mark(); char indicator = INPUT.get(); - params.fold = (indicator == Keys::FoldedScalar); + params.fold = (indicator == Keys::FoldedScalar ? FOLD_BLOCK : DONT_FOLD); // eat chomping/indentation indicators params.chomp = CLIP;