/** * 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; }
/** * Puts an EOL marker to the stream. * * @returns IPRt status code. * @param pStream The stream. Must be in write mode. * @param enmEol The end-of-line marker to write. */ int ScmStreamPutEol(PSCMSTREAM pStream, SCMEOL enmEol) { if (enmEol == SCMEOL_LF) return ScmStreamWrite(pStream, "\n", 1); if (enmEol == SCMEOL_CRLF) return ScmStreamWrite(pStream, "\r\n", 2); if (enmEol == SCMEOL_NONE) return VINF_SUCCESS; AssertFailedReturn(VERR_INVALID_PARAMETER); }
/** * Expand tabs. * * @returns True if modified, false if not. * @param pIn The input stream. * @param pOut The output stream. * @param pSettings The settings. */ bool rewrite_ExpandTabs(PSCMRWSTATE pState, PSCMSTREAM pIn, PSCMSTREAM pOut, PCSCMSETTINGSBASE pSettings) { if (!pSettings->fConvertTabs) return false; size_t const cchTab = pSettings->cchTab; bool fModified = false; SCMEOL enmEol; size_t cchLine; const char *pchLine; while ((pchLine = ScmStreamGetLine(pIn, &cchLine, &enmEol)) != NULL) { int rc; const char *pchTab = (const char *)memchr(pchLine, '\t', cchLine); if (!pchTab) rc = ScmStreamPutLine(pOut, pchLine, cchLine, enmEol); else { size_t offTab = 0; const char *pchChunk = pchLine; for (;;) { size_t cchChunk = pchTab - pchChunk; offTab += cchChunk; ScmStreamWrite(pOut, pchChunk, cchChunk); size_t cchToTab = cchTab - offTab % cchTab; ScmStreamWrite(pOut, g_szTabSpaces, cchToTab); offTab += cchToTab; pchChunk = pchTab + 1; size_t cchLeft = cchLine - (pchChunk - pchLine); pchTab = (const char *)memchr(pchChunk, '\t', cchLeft); if (!pchTab) { rc = ScmStreamPutLine(pOut, pchChunk, cchLeft, enmEol); break; } } fModified = true; } if (RT_FAILURE(rc)) return false; } if (fModified) ScmVerbose(pState, 2, " * Expanded tabs\n"); return fModified; }
/** * Formats a string and writes it to the SCM stream. * * @returns The number of bytes written (>= 0). Negative value are IPRT error * status codes. * @param pStream The stream to write to. * @param pszFormat The format string. * @param va The arguments to format. */ ssize_t ScmStreamPrintfV(PSCMSTREAM pStream, const char *pszFormat, va_list va) { char *psz; ssize_t cch = RTStrAPrintfV(&psz, pszFormat, va); if (cch) { int rc = ScmStreamWrite(pStream, psz, cch); RTStrFree(psz); if (RT_FAILURE(rc)) cch = rc; } return cch; }
/** * Write a character to the stream. * * @returns IPRT status code * @param pStream The stream. Must be in write mode. * @param pchBuf What to write. * @param cchBuf How much to write. */ int ScmStreamPutCh(PSCMSTREAM pStream, char ch) { AssertReturn(pStream->fWriteOrRead, VERR_ACCESS_DENIED); if (RT_FAILURE(pStream->rc)) return pStream->rc; /* * Only deal with the simple cases here, use ScmStreamWrite for the * annoying stuff. */ size_t off = pStream->off; if ( ch == '\n' || RT_UNLIKELY(off + 1 > pStream->cbAllocated)) return ScmStreamWrite(pStream, &ch, 1); /* * Just append it. */ pStream->pch[off] = ch; pStream->off = off + 1; pStream->paLines[pStream->iLine].cch++; return VINF_SUCCESS; }