/** * Strip trailing blank lines and/or make sure there is exactly one blank line * at the end of the file. * * @returns true if modifications were made, false if not. * @param pIn The input stream. * @param pOut The output stream. * @param pSettings The settings. * * @remarks ASSUMES trailing white space has been removed already. */ bool rewrite_AdjustTrailingLines(PSCMRWSTATE pState, PSCMSTREAM pIn, PSCMSTREAM pOut, PCSCMSETTINGSBASE pSettings) { if ( !pSettings->fStripTrailingLines && !pSettings->fForceTrailingLine && !pSettings->fForceFinalEol) return false; size_t const cLines = ScmStreamCountLines(pIn); /* Empty files remains empty. */ if (cLines <= 1) return false; /* Figure out if we need to adjust the number of lines or not. */ size_t cLinesNew = cLines; if ( pSettings->fStripTrailingLines && ScmStreamIsWhiteLine(pIn, cLinesNew - 1)) { while ( cLinesNew > 1 && ScmStreamIsWhiteLine(pIn, cLinesNew - 2)) cLinesNew--; } if ( pSettings->fForceTrailingLine && !ScmStreamIsWhiteLine(pIn, cLinesNew - 1)) cLinesNew++; bool fFixMissingEol = pSettings->fForceFinalEol && ScmStreamGetEolByLine(pIn, cLinesNew - 1) == SCMEOL_NONE; if ( !fFixMissingEol && cLines == cLinesNew) return false; /* Copy the number of lines we've arrived at. */ ScmStreamRewindForReading(pIn); size_t cCopied = RT_MIN(cLinesNew, cLines); ScmStreamCopyLines(pOut, pIn, cCopied); if (cCopied != cLinesNew) { while (cCopied++ < cLinesNew) ScmStreamPutLine(pOut, "", 0, ScmStreamGetEol(pIn)); } /* Fix missing EOL if required. */ else if (fFixMissingEol) { if (ScmStreamGetEol(pIn) == SCMEOL_LF) ScmStreamWrite(pOut, "\n", 1); else ScmStreamWrite(pOut, "\r\n", 2); } ScmVerbose(pState, 2, " * Adjusted trailing blank lines\n"); return true; }
/** * Appends a line to the stream. * * @returns IPRT status code. * @param pStream The stream. Must be in write mode. * @param pchLine Pointer to the line. * @param cchLine Line length. * @param enmEol Which end of line indicator to use. */ int ScmStreamPutLine(PSCMSTREAM pStream, const char *pchLine, size_t cchLine, SCMEOL enmEol) { AssertReturn(pStream->fWriteOrRead, VERR_ACCESS_DENIED); if (RT_FAILURE(pStream->rc)) return pStream->rc; /* * Make sure the previous line has a new-line indicator. */ size_t off = pStream->off; size_t iLine = pStream->iLine; if (RT_UNLIKELY( iLine != 0 && pStream->paLines[iLine - 1].enmEol == SCMEOL_NONE)) { AssertReturn(pStream->paLines[iLine].cch == 0, VERR_INTERNAL_ERROR_3); SCMEOL enmEol2 = enmEol != SCMEOL_NONE ? enmEol : ScmStreamGetEol(pStream); if (RT_UNLIKELY(off + cchLine + enmEol + enmEol2 > pStream->cbAllocated)) { int rc = scmStreamGrowBuffer(pStream, cchLine + enmEol + enmEol2); if (RT_FAILURE(rc)) return rc; } if (enmEol2 == SCMEOL_LF) pStream->pch[off++] = '\n'; else { pStream->pch[off++] = '\r'; pStream->pch[off++] = '\n'; } pStream->paLines[iLine - 1].enmEol = enmEol2; pStream->paLines[iLine].off = off; pStream->off = off; pStream->cb = off; } /* * Ensure we've got sufficient buffer space. */ if (RT_UNLIKELY(off + cchLine + enmEol > pStream->cbAllocated)) { int rc = scmStreamGrowBuffer(pStream, cchLine + enmEol); if (RT_FAILURE(rc)) return rc; } /* * Add a line record. */ if (RT_UNLIKELY(iLine + 1 >= pStream->cLinesAllocated)) { int rc = scmStreamGrowLines(pStream, iLine); if (RT_FAILURE(rc)) return rc; } pStream->paLines[iLine].cch = off - pStream->paLines[iLine].off + cchLine; pStream->paLines[iLine].enmEol = enmEol; iLine++; pStream->cLines = iLine; pStream->iLine = iLine; /* * Copy the line */ memcpy(&pStream->pch[off], pchLine, cchLine); off += cchLine; if (enmEol == SCMEOL_LF) pStream->pch[off++] = '\n'; else if (enmEol == SCMEOL_CRLF) { pStream->pch[off++] = '\r'; pStream->pch[off++] = '\n'; } pStream->off = off; pStream->cb = off; /* * Start a new line. */ pStream->paLines[iLine].off = off; pStream->paLines[iLine].cch = 0; pStream->paLines[iLine].enmEol = SCMEOL_NONE; return VINF_SUCCESS; }