scm.cpp revision b2c35a7024c4c308b429c81b203b3bcbd44ee60c
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * IPRT Testcase / Tool - Source Code Massager.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * Copyright (C) 2010 Sun Microsystems, Inc.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * available from http://www.virtualbox.org. This file is free software;
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * you can redistribute it and/or modify it under the terms of the GNU
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * General Public License (GPL) as published by the Free Software
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * The contents of this file may alternatively be used under the terms
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * of the Common Development and Distribution License Version 1.0
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * VirtualBox OSE distribution, in which case the provisions of the
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * CDDL are applicable instead of those of the GPL.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * You may elect to license modified versions of this file under the
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * terms and conditions of either the GPL or the CDDL or both.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * additional information or have any questions.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync/*******************************************************************************
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync* Header Files *
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync*******************************************************************************/
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync/*******************************************************************************
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync* Defined Constants And Macros *
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync*******************************************************************************/
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync/** The name of the settings files. */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync/*******************************************************************************
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync* Structures and Typedefs *
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync*******************************************************************************/
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync/** Pointer to const massager settings. */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsynctypedef struct SCMSETTINGSBASE const *PCSCMSETTINGSBASE;
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync/** End of line marker type. */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync/** Pointer to an end of line marker type. */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * Line record.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync /** The offset of the line. */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync /** The line length, excluding the LF character.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @todo This could be derived from the offset of the next line if that wasn't
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * so tedious. */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync /** The end of line marker type. */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync/** Pointer to a line record. */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * Source code massager stream.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsynctypedef struct SCMSTREAM
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync /** Pointer to the file memory. */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync /** The current stream position. */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync /** The current stream size. */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync /** The size of the memory pb points to. */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync /** Line records. */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync /** The current line. */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync /** The current stream size given in lines. */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync /** The sizeof the the memory backing paLines. */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync /** Set if write-only, clear if read-only. */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync /** Set if the memory pb points to is from RTFileReadAll. */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync /** Set if fully broken into lines. */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync /** Stream status code (IPRT). */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync/** Pointer to a SCM stream. */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync/** Pointer to a const SCM stream. */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * Rewriter state.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsynctypedef struct SCMRWSTATE
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync /** The filename. */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync /** Set after the printing the first verbose message about a file under
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * rewrite. */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync/** Pointer to the rewriter state. */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * A rewriter.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * This works like a stream editor, reading @a pIn, modifying it and writing it
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * to @a pOut.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @returns true if any changes were made, false if not.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param pIn The input stream.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param pOut The output stream.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param pSettings The settings.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsynctypedef bool (*PFNSCMREWRITER)(PSCMRWSTATE pState, PSCMSTREAM pIn, PSCMSTREAM pOut, PCSCMSETTINGSBASE pSettings);
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * Configuration entry.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsynctypedef struct SCMCFGENTRY
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync /** Number of rewriters. */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync /** Pointer to an array of rewriters. */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync /** File pattern (simple). */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * Diff state.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsynctypedef struct SCMDIFFSTATE
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync /** Whether to ignore end of line markers when diffing. */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync /** Whether to ignore trailing whitespace. */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync /** Whether to ignore leading whitespace. */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync /** Whether to print special characters in human readable form or not. */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync /** The tab size. */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync /** Where to push the diff. */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync/** Pointer to a diff state. */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * Source Code Massager Settings.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync /** Only consider files matcihng these patterns. This is only applied to the
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * base names. */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync /** Filter out files matching the following patterns. This is applied to base
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * names as well as the aboslute paths. */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync /** Filter out directories matching the following patterns. This is applied
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * to base names as well as the aboslute paths. All absolute paths ends with a
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * slash and dot ("/."). */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync/** Pointer to massager settings. */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * Option identifiers.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @note The first chunk, down to SCMOPT_TAB_SIZE, are alternately set &
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * clear. So, the option setting a flag (boolean) will have an even
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * number and the one clearing it will have an odd number.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @note Down to SCMOPT_LAST_SETTINGS corresponds exactly to SCMSETTINGSBASE.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * File/dir pattern + options.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync/** Pointer to a pattern + option pair. */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync/** Pointer to a settings set. */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * Settings set.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * This structure is constructed from the command line arguments or any
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * .scm-settings file found in a directory we recurse into. When recusing in
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * and out of a directory, we push and pop a settings set for it.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * The .scm-settings file has two kinds of setttings, first there are the
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * unqualified base settings and then there are the settings which applies to a
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * set of files or directories. The former are lines with command line options.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * For the latter, the options are preceeded by a string pattern and a colon.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * The pattern specifies which files (and/or directories) the options applies
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * We parse the base options into the Base member and put the others into the
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * paPairs array.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsynctypedef struct SCMSETTINGS
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync /** Pointer to the setting file below us in the stack. */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync /** Pointer to the setting file above us in the stack. */
b2e90826ea719b22452d1ff7b977d4f40995b428vboxsync /** File/dir patterns and their options. */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync /** The number of entires in paPairs. */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync /** The base settings that was read out of the file. */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync/** Pointer to a const settings set. */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync/*******************************************************************************
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync* Internal Functions *
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync*******************************************************************************/
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsyncstatic bool rewrite_StripTrailingBlanks(PSCMRWSTATE pState, PSCMSTREAM pIn, PSCMSTREAM pOut, PCSCMSETTINGSBASE pSettings);
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsyncstatic bool rewrite_ExpandTabs(PSCMRWSTATE pState, PSCMSTREAM pIn, PSCMSTREAM pOut, PCSCMSETTINGSBASE pSettings);
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsyncstatic bool rewrite_ForceNativeEol(PSCMRWSTATE pState, PSCMSTREAM pIn, PSCMSTREAM pOut, PCSCMSETTINGSBASE pSettings);
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsyncstatic bool rewrite_ForceLF(PSCMRWSTATE pState, PSCMSTREAM pIn, PSCMSTREAM pOut, PCSCMSETTINGSBASE pSettings);
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsyncstatic bool rewrite_ForceCRLF(PSCMRWSTATE pState, PSCMSTREAM pIn, PSCMSTREAM pOut, PCSCMSETTINGSBASE pSettings);
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsyncstatic bool rewrite_AdjustTrailingLines(PSCMRWSTATE pState, PSCMSTREAM pIn, PSCMSTREAM pOut, PCSCMSETTINGSBASE pSettings);
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsyncstatic bool rewrite_Makefile_kup(PSCMRWSTATE pState, PSCMSTREAM pIn, PSCMSTREAM pOut, PCSCMSETTINGSBASE pSettings);
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsyncstatic bool rewrite_Makefile_kmk(PSCMRWSTATE pState, PSCMSTREAM pIn, PSCMSTREAM pOut, PCSCMSETTINGSBASE pSettings);
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsyncstatic bool rewrite_C_and_CPP(PSCMRWSTATE pState, PSCMSTREAM pIn, PSCMSTREAM pOut, PCSCMSETTINGSBASE pSettings);
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync/*******************************************************************************
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync* Global Variables *
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync*******************************************************************************/
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsyncstatic bool g_fDryRun = true;
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsyncstatic bool g_fDiffSpecialChars = true;
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsyncstatic bool g_fDiffIgnoreEol = false;
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsyncstatic bool g_fDiffIgnoreLeadingWS = false;
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsyncstatic bool g_fDiffIgnoreTrailingWS = false;
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync/** The global settings. */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync /* .fConvertEol = */ true,
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync /* .fConvertTabs = */ true,
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync /* .fForceFinalEol = */ true,
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync /* .fForceTrailingLine = */ false,
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync /* .fStripTrailingBlanks = */ true,
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync /* .fStripTrailingLines = */ true,
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync /* .pszFilterOutFiles = */ (char *)"*.exe|*.com|20*-*-*.log",
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync /* .pszFilterOutDirs = */ (char *)".svn|.hg|.git|CVS",
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync/** Option definitions for the base settings. */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync { "--convert-eol", SCMOPT_CONVERT_EOL, RTGETOPT_REQ_NOTHING },
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync { "--no-convert-eol", SCMOPT_NO_CONVERT_EOL, RTGETOPT_REQ_NOTHING },
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync { "--convert-tabs", SCMOPT_CONVERT_TABS, RTGETOPT_REQ_NOTHING },
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync { "--no-convert-tabs", SCMOPT_NO_CONVERT_TABS, RTGETOPT_REQ_NOTHING },
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync { "--force-final-eol", SCMOPT_FORCE_FINAL_EOL, RTGETOPT_REQ_NOTHING },
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync { "--no-force-final-eol", SCMOPT_NO_FORCE_FINAL_EOL, RTGETOPT_REQ_NOTHING },
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync { "--force-trailing-line", SCMOPT_FORCE_TRAILING_LINE, RTGETOPT_REQ_NOTHING },
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync { "--no-force-trailing-line", SCMOPT_NO_FORCE_TRAILING_LINE, RTGETOPT_REQ_NOTHING },
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync { "--strip-trailing-blanks", SCMOPT_STRIP_TRAILING_BLANKS, RTGETOPT_REQ_NOTHING },
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync { "--no-strip-trailing-blanks", SCMOPT_NO_STRIP_TRAILING_BLANKS, RTGETOPT_REQ_NOTHING },
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync { "--strip-trailing-lines", SCMOPT_STRIP_TRAILING_LINES, RTGETOPT_REQ_NOTHING },
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync { "--strip-no-trailing-lines", SCMOPT_NO_STRIP_TRAILING_LINES, RTGETOPT_REQ_NOTHING },
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync { "--tab-size", SCMOPT_TAB_SIZE, RTGETOPT_REQ_UINT8 },
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync { "--filter-out-dirs", SCMOPT_FILTER_OUT_DIRS, RTGETOPT_REQ_STRING },
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync { "--filter-files", SCMOPT_FILTER_FILES, RTGETOPT_REQ_STRING },
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync { "--filter-out-files", SCMOPT_FILTER_OUT_FILES, RTGETOPT_REQ_STRING },
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync/** Consider files matching the following patterns (base names only). */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsyncstatic PFNSCMREWRITER const g_aRewritersFor_Makefile_kup[] =
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsyncstatic PFNSCMREWRITER const g_aRewritersFor_Makefile_kmk[] =
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsyncstatic PFNSCMREWRITER const g_aRewritersFor_C_and_CPP[] =
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsyncstatic PFNSCMREWRITER const g_aRewritersFor_ShellScripts[] =
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsyncstatic PFNSCMREWRITER const g_aRewritersFor_BatchFiles[] =
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync { RT_ELEMENTS(g_aRewritersFor_Makefile_kup), &g_aRewritersFor_Makefile_kup[0], "Makefile.kup" },
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync { RT_ELEMENTS(g_aRewritersFor_Makefile_kmk), &g_aRewritersFor_Makefile_kmk[0], "Makefile.kmk" },
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync { RT_ELEMENTS(g_aRewritersFor_C_and_CPP), &g_aRewritersFor_C_and_CPP[0], "*.c|*.h|*.cpp|*.hpp|*.C|*.CPP|*.cxx|*.cc" },
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync { RT_ELEMENTS(g_aRewritersFor_ShellScripts), &g_aRewritersFor_ShellScripts[0], "*.sh|configure" },
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync { RT_ELEMENTS(g_aRewritersFor_BatchFiles), &g_aRewritersFor_BatchFiles[0], "*.bat|*.cmd|*.btm|*.vbs|*.ps1" },
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync/* -=-=-=-=-=- memory streams -=-=-=-=-=- */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * Initializes the stream structure.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param pStream The stream structure.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param fWriteOrRead The value of the fWriteOrRead stream member.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsyncstatic void scmStreamInitInternal(PSCMSTREAM pStream, bool fWriteOrRead)
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * Initialize an input stream.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @returns IPRT status code.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param pStream The stream to initialize.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param pszFilename The file to take the stream content from.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsyncint ScmStreamInitForReading(PSCMSTREAM pStream, const char *pszFilename)
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync scmStreamInitInternal(pStream, false /*fWriteOrRead*/);
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync int rc = pStream->rc = RTFileReadAll(pszFilename, &pvFile, &cbFile);
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * Initialize an output stream.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @returns IPRT status code
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param pStream The stream to initialize.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param pRelatedStream Pointer to a related stream. NULL is fine.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsyncint ScmStreamInitForWriting(PSCMSTREAM pStream, PCSCMSTREAM pRelatedStream)
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync scmStreamInitInternal(pStream, true /*fWriteOrRead*/);
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync /* allocate stuff */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync size_t cLinesEstimate = pRelatedStream && pRelatedStream->fFullyLineated
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync ? pRelatedStream->cLines + pRelatedStream->cLines / 10
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync pStream->paLines = (PSCMSTREAMLINE)RTMemAlloc(cLinesEstimate * sizeof(SCMSTREAMLINE));
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * Frees the resources associated with the stream.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * Nothing is happens to whatever the stream was initialized from or dumped to.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param pStream The stream to delete.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync RTFileReadAllFree(pStream->pch, pStream->cbAllocated);
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * Get the stream status code.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @returns IPRT status code.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param pStream The stream.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * Grows the buffer of a write stream.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @returns IPRT status code.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param pStream The stream. Must be in write mode.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param cbAppending The minimum number of bytes to grow the buffer
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsyncstatic int scmStreamGrowBuffer(PSCMSTREAM pStream, size_t cbAppending)
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync cbAllocated += RT_MAX(0x1000 + cbAppending, cbAllocated);
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync pvNew = RTMemDupEx(pStream->pch, pStream->off, cbAllocated - pStream->off);
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync RTFileReadAllFree(pStream->pch, pStream->cbAllocated);
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * Grows the line array of a stream.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @returns IPRT status code.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param pStream The stream.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param iMinLine Minimum line number.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsyncstatic int scmStreamGrowLines(PSCMSTREAM pStream, size_t iMinLine)
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync cLinesAllocated += RT_MAX(512 + iMinLine, cLinesAllocated);
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync void *pvNew = RTMemRealloc(pStream->paLines, cLinesAllocated * sizeof(SCMSTREAMLINE));
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * Rewinds the stream and sets the mode to read.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param pStream The stream.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * Rewinds the stream and sets the mode to write.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param pStream The stream.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * Checks if it's a text stream.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * Not 100% proof.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @returns true if it probably is a text file, false if not.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param pStream The stream. Write or read, doesn't matter.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync return false;
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync return false;
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync return true;
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * Performs an integrity check of the stream.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @returns IPRT status code.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param pStream The stream.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * Perform sanity checks.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync for (size_t iLine = 0; iLine < pStream->cLines; iLine++)
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync size_t offEol = pStream->paLines[iLine].off + pStream->paLines[iLine].cch;
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync AssertReturn(offEol + pStream->paLines[iLine].enmEol <= cbFile, VERR_INTERNAL_ERROR_2);
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync AssertReturn(pStream->pch[offEol] == '\n', VERR_INTERNAL_ERROR_3);
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync AssertReturn(pStream->pch[offEol] == '\r', VERR_INTERNAL_ERROR_3);
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync AssertReturn(pStream->pch[offEol + 1] == '\n', VERR_INTERNAL_ERROR_3);
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync AssertReturn(iLine + 1 >= pStream->cLines, VERR_INTERNAL_ERROR_4);
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync AssertReturn(iLine + 1 >= pStream->cLines, VERR_INTERNAL_ERROR_5);
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * Writes the stream to a file.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @returns IPRT status code
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param pStream The stream.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param pszFilenameFmt The filename format string.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param ... Format arguments.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsyncint ScmStreamWriteToFile(PSCMSTREAM pStream, const char *pszFilenameFmt, ...)
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * Check that what we're going to write makes sense first.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * Do the actual writing.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync rc = RTFileOpenV(&hFile, RTFILE_O_WRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_WRITE, pszFilenameFmt, va);
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync rc = RTFileWrite(hFile, pStream->pch, pStream->cb, NULL);
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * Worker for ScmStreamGetLine that builds the line number index while parsing
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * the stream.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @returns Same as SCMStreamGetLine.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param pStream The stream. Must be in read mode.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param pcchLine Where to return the line length.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param penmEol Where to return the kind of end of line marker.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsyncstatic const char *scmStreamGetLineInternal(PSCMSTREAM pStream, size_t *pcchLine, PSCMEOL penmEol)
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync if (RT_UNLIKELY(iLine >= pStream->cLinesAllocated))
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync const char *pch = (const char *)memchr(pchRet, '\n', cb);
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync pStream->paLines[iLine].enmEol = *penmEol = SCMEOL_LF;
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync pStream->paLines[iLine].enmEol = *penmEol = SCMEOL_CRLF;
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync pStream->paLines[iLine].enmEol = *penmEol = SCMEOL_NONE;
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * Internal worker that lineates a stream.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @returns IPRT status code.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param pStream The stream. Caller must check that it is in
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * read mode.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync /* Save the stream position. */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync /* Get each line. */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync while (scmStreamGetLineInternal(pStream, &cchLine, &enmEol))
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync /* nothing */;
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync Assert(RT_FAILURE(pStream->rc) || pStream->fFullyLineated);
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync /* Restore the position */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * Get the current stream position as a line number.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @returns The current line (0-based).
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param pStream The stream.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * Gets the number of lines in the stream.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @returns The number of lines.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param pStream The stream.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * Seeks to a given line in the tream.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @returns IPRT status code.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param pStream The stream. Must be in read mode.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param iLine The line to seek to. If this is beyond the end
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * of the stream, the position is set to the end.
b2e90826ea719b22452d1ff7b977d4f40995b428vboxsyncint ScmStreamSeekByLine(PSCMSTREAM pStream, size_t iLine)
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync AssertReturn(!pStream->fWriteOrRead, VERR_ACCESS_DENIED);
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync /* Must be fully lineated of course. */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync /* Ok, do the job. */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * Get a numbered line from the stream (changes the position).
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * A line is always delimited by a LF character or the end of the stream. The
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * delimiter is not included in returned line length, but instead returned via
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * the @a penmEol indicator.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @returns Pointer to the first character in the line, not NULL terminated.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * NULL if the end of the stream has been reached or some problem
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param pStream The stream. Must be in read mode.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param iLine The line to get (0-based).
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param pcchLine The length.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param penmEol Where to return the end of line type indicator.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsyncstatic const char *ScmStreamGetLineByNo(PSCMSTREAM pStream, size_t iLine, size_t *pcchLine, PSCMEOL penmEol)
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync /* Make sure it's fully lineated so we can use the index. */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync /* End of stream? */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync /* Get the data. */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync const char *pchRet = &pStream->pch[pStream->paLines[iLine].off];
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync /* update the stream position. */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync pStream->off = pStream->paLines[iLine].cch + pStream->paLines[iLine].enmEol;
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * Get a line from the stream.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * A line is always delimited by a LF character or the end of the stream. The
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * delimiter is not included in returned line length, but instead returned via
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * the @a penmEol indicator.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @returns Pointer to the first character in the line, not NULL terminated.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * NULL if the end of the stream has been reached or some problem
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param pStream The stream. Must be in read mode.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param pcchLine The length.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param penmEol Where to return the end of line type indicator.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsyncstatic const char *ScmStreamGetLine(PSCMSTREAM pStream, size_t *pcchLine, PSCMEOL penmEol)
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync return scmStreamGetLineInternal(pStream, pcchLine, penmEol);
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync return ScmStreamGetLineByNo(pStream, pStream->iLine, pcchLine, penmEol);
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * Checks if the given line is empty or full of white space.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @returns true if white space only, false if not (or if non-existant).
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param pStream The stream. Must be in read mode.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param iLine The line in question.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsyncstatic bool ScmStreamIsWhiteLine(PSCMSTREAM pStream, size_t iLine)
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync const char *pchLine = ScmStreamGetLineByNo(pStream, iLine, &cchLine, &enmEol);
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync return false;
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync return cchLine == 0;
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * Try figure out the end of line style of the give stream.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @returns Most likely end of line style.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param pStream The stream.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync const char *pchLF = (const char *)memchr(pStream->pch, '\n', pStream->cb);
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync if (pchLF && pchLF != pStream->pch && pchLF[-1] == '\r')
b2e90826ea719b22452d1ff7b977d4f40995b428vboxsync * Get the end of line indicator type for a line.
b2e90826ea719b22452d1ff7b977d4f40995b428vboxsync * @returns The EOL indicator. If the line isn't found, the default EOL
b2e90826ea719b22452d1ff7b977d4f40995b428vboxsync * indicator is return.
b2e90826ea719b22452d1ff7b977d4f40995b428vboxsync * @param pStream The stream.
b2e90826ea719b22452d1ff7b977d4f40995b428vboxsync * @param iLine The line (0-base).
b2e90826ea719b22452d1ff7b977d4f40995b428vboxsyncSCMEOL ScmStreamGetEolByLine(PSCMSTREAM pStream, size_t iLine)
b2e90826ea719b22452d1ff7b977d4f40995b428vboxsync * Appends a line to the stream.
b2e90826ea719b22452d1ff7b977d4f40995b428vboxsync * @returns IPRT status code.
b2e90826ea719b22452d1ff7b977d4f40995b428vboxsync * @param pStream The stream. Must be in write mode.
b2e90826ea719b22452d1ff7b977d4f40995b428vboxsync * @param pchLine Pointer to the line.
b2e90826ea719b22452d1ff7b977d4f40995b428vboxsync * @param cchLine Line length.
b2e90826ea719b22452d1ff7b977d4f40995b428vboxsync * @param enmEol Which end of line indicator to use.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsyncint ScmStreamPutLine(PSCMSTREAM pStream, const char *pchLine, size_t cchLine, SCMEOL enmEol)
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync AssertReturn(pStream->fWriteOrRead, VERR_ACCESS_DENIED);
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * Make sure the previous line has a new-line indicator.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync && pStream->paLines[iLine - 1].enmEol == SCMEOL_NONE))
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync AssertReturn(pStream->paLines[iLine].cch == 0, VERR_INTERNAL_ERROR_3);
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync SCMEOL enmEol2 = enmEol != SCMEOL_NONE ? enmEol : ScmStreamGetEol(pStream);
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync if (RT_UNLIKELY(off + cchLine + enmEol + enmEol2 > pStream->cbAllocated))
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync int rc = scmStreamGrowBuffer(pStream, cchLine + enmEol + enmEol2);
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * Ensure we've got sufficient buffer space.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync if (RT_UNLIKELY(off + cchLine + enmEol > pStream->cbAllocated))
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync int rc = scmStreamGrowBuffer(pStream, cchLine + enmEol);
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * Add a line record.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync if (RT_UNLIKELY(iLine + 1 >= pStream->cLinesAllocated))
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync pStream->paLines[iLine].cch = off - pStream->paLines[iLine].off + cchLine;
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * Copy the line
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * Start a new line.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * Writes to the stream.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @returns IPRT status code
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param pStream The stream. Must be in write mode.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param pchBuf What to write.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param cchBuf How much to write.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsyncint ScmStreamWrite(PSCMSTREAM pStream, const char *pchBuf, size_t cchBuf)
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync AssertReturn(pStream->fWriteOrRead, VERR_ACCESS_DENIED);
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * Ensure we've got sufficient buffer space.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync if (RT_UNLIKELY(off + cchBuf > pStream->cbAllocated))
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * Deal with the odd case where we've already pushed a line with SCMEOL_NONE.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync && pStream->paLines[iLine - 1].enmEol == SCMEOL_NONE))
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * Deal with lines.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync const char *pchLF = (const char *)memchr(pchBuf, '\n', cchBuf);
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync if (RT_UNLIKELY(iLine + 1 >= pStream->cLinesAllocated))
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync pStream->paLines[iLine].cch = off - pStream->paLines[iLine].off;
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync || pStream->pch[pStream->paLines[iLine].off + pStream->paLines[iLine].cch - 1] != '\r')
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync pchLF = (const char *)memchr(pchLF + 1, '\n', cchLeft);
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * Copy the data and update position and size.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * Write a character to the stream.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @returns IPRT status code
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param pStream The stream. Must be in write mode.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param pchBuf What to write.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param cchBuf How much to write.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync AssertReturn(pStream->fWriteOrRead, VERR_ACCESS_DENIED);
b2e90826ea719b22452d1ff7b977d4f40995b428vboxsync * Only deal with the simple cases here, use ScmStreamWrite for the
b2e90826ea719b22452d1ff7b977d4f40995b428vboxsync * annyoing stuff.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * Just append it.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * Copies @a cLines from the @a pSrc stream onto the @a pDst stream.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * The stream positions will be used and changed in both streams.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @returns IPRT status code.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param pDst The destionation stream. Must be in write mode.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param cLines The number of lines. (0 is accepted.)
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param pSrc The source stream. Must be in read mode.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsyncint ScmStreamCopyLines(PSCMSTREAM pDst, PSCMSTREAM pSrc, size_t cLines)
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync AssertReturn(pDst->fWriteOrRead, VERR_ACCESS_DENIED);
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync AssertReturn(!pSrc->fWriteOrRead, VERR_ACCESS_DENIED);
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync while (cLines-- > 0)
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync const char *pchLine = ScmStreamGetLine(pSrc, &cchLine, &enmEol);
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync return pDst->rc = (RT_FAILURE(pSrc->rc) ? pSrc->rc : VERR_EOF);
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync int rc = ScmStreamPutLine(pDst, pchLine, cchLine, enmEol);
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync/* -=-=-=-=-=- diff -=-=-=-=-=- */
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * Prints a range of lines with a prefix.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param pState The diff state.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param chPrefix The prefix.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param pStream The stream to get the lines from.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param iLine The first line.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param cLines The number of lines.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsyncstatic void scmDiffPrintLines(PSCMDIFFSTATE pState, char chPrefix, PSCMSTREAM pStream, size_t iLine, size_t cLines)
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync while (cLines-- > 0)
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync const char *pchLine = ScmStreamGetLineByNo(pStream, iLine, &cchLine, &enmEol);
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync const char *pchTab = (const char *)memchr(pchLine, '\t', cchLine);
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync RTStrmWrite(pState->pDiff, pchStart, pchTab - pchStart);
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync size_t cchTab = pState->cchTab - offVir % pState->cchTab;
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync case 4: RTStrmPutStr(pState->pDiff, "[TA]"); break;
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync case 5: RTStrmPutStr(pState->pDiff, "[TAB]"); break;
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync default: RTStrmPrintf(pState->pDiff, "[TAB%.*s]", cchTab - 5, g_szTabSpaces); break;
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync pchTab = (const char *)memchr(pchStart, '\t', cchLine - (pchStart - pchLine));
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * Reports a difference and propells the streams to the lines following the
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @returns New pState->cDiff value (just to return something).
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param pState The diff state. The cDiffs member will be
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * incremented.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param cMatches The resync length.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param iLeft Where the difference starts on the left side.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param cLeft How long it is on this side. ~(size_t)0 is used
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * to indicate that it goes all the way to the end.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param iRight Where the difference starts on the right side.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * @param cRight How long it is.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsyncstatic size_t scmDiffReport(PSCMDIFFSTATE pState, size_t cMatches,
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * Adjust the input.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * Print header if it's the first difference
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync RTStrmPrintf(pState->pDiff, "diff %s %s\n", pState->pszFilename, pState->pszFilename);
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * Emit the change description.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync RTStrmPrintf(pState->pDiff, "%zu,%zu%c%zu,%zu\n", iLeft + 1, iLeft + cLeft, ch, iRight + 1, iRight + cRight);
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync RTStrmPrintf(pState->pDiff, "%zu,%zu%c%zu\n", iLeft + 1, iLeft + cLeft, ch, iRight + 1);
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync RTStrmPrintf(pState->pDiff, "%zu%c%zu,%zu\n", iLeft + 1, ch, iRight + 1, iRight + cRight);
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync RTStrmPrintf(pState->pDiff, "%zu%c%zu\n", iLeft + 1, ch, iRight + 1);
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync * And the lines.
30a23dfc653298a09d77d3045cf873b1bd6ddecfvboxsync scmDiffPrintLines(pState, '<', pState->pLeft, iLeft, cLeft);
if (cRight)
cchLeft--;
cchRight--;
const char *pchRight = ScmStreamGetLineByNo(pState->pRight, iRight + iLine, &cchRight, &enmEolRight);
* ones, including iStartLeft/Right.
if (!pchLine)
if (!pchLine)
size_t ScmDiffStreams(const char *pszFilename, PSCMSTREAM pLeft, PSCMSTREAM pRight, bool fIgnoreEol,
#ifdef RT_STRICT
const char *pchLeft;
const char *pchRight;
if (pchLeft)
else if (pchRight)
return VINF_SUCCESS;
return rc;
if (pSettings)
switch (rc)
case SCMOPT_CONVERT_EOL:
return VINF_SUCCESS;
case SCMOPT_NO_CONVERT_EOL:
return VINF_SUCCESS;
case SCMOPT_CONVERT_TABS:
return VINF_SUCCESS;
case SCMOPT_NO_CONVERT_TABS:
return VINF_SUCCESS;
case SCMOPT_FORCE_FINAL_EOL:
return VINF_SUCCESS;
return VINF_SUCCESS;
return VINF_SUCCESS;
return VINF_SUCCESS;
return VINF_SUCCESS;
return VINF_SUCCESS;
return VINF_SUCCESS;
return VINF_SUCCESS;
case SCMOPT_TAB_SIZE:
return VERR_OUT_OF_RANGE;
return VINF_SUCCESS;
case SCMOPT_FILTER_OUT_DIRS:
case SCMOPT_FILTER_FILES:
case SCMOPT_FILTER_OUT_FILES:
char **ppsz;
switch (rc)
pszSrc++;
cchSrc--;
if (!cchSrc)
return VINF_SUCCESS;
return VERR_GETOPT_UNKNOWN_OPTION;
int cArgs;
char **papszArgs;
rc = RTGetOptInit(&GetOptState, cArgs, papszArgs, &g_aScmOpts[0], RT_ELEMENTS(g_aScmOpts), 0, 0 /*fFlags*/);
return rc;
if (!pszLine)
return VERR_NO_MEMORY;
return rc;
return rc;
return VINF_SUCCESS;
if (!pSettings)
return VERR_NO_MEMORY;
return VINF_SUCCESS;
return rc;
if (pSettings)
if (!pchOptions)
return VERR_INVALID_PARAMETER;
pchOptions++;
cchPattern--;
cchOptions--;
return VINF_SUCCESS;
if (!pvNew)
return VERR_NO_MEMORY;
int rc;
return rc;
return rc;
const char *pchLine;
if (pchColon)
return rc;
static int scmSettingsCreateFromFile(PSCMSETTINGS *ppSettings, const char *pszFilename, PCSCMSETTINGSBASE pSettingsBase)
return VINF_SUCCESS;
return rc;
static int scmSettingsCreateForPath(PSCMSETTINGS *ppSettings, PCSCMSETTINGSBASE pBaseSettings, const char *pszPath)
return VERR_FILENAME_TOO_LONG;
return rc;
return rc;
if (pOld)
return VINF_SUCCESS;
return rc;
if (pNew)
if (pRet)
return pRet;
while (pCur)
if (cPairs)
return rc;
if (pszFormat)
static bool rewrite_StripTrailingBlanks(PSCMRWSTATE pState, PSCMSTREAM pIn, PSCMSTREAM pOut, PCSCMSETTINGSBASE pSettings)
bool fModified = false;
const char *pchLine;
int rc;
if ( cchLine == 0
cchLine--;
cchLine--;
fModified = true;
if (fModified)
return fModified;
static bool rewrite_ExpandTabs(PSCMRWSTATE pState, PSCMSTREAM pIn, PSCMSTREAM pOut, PCSCMSETTINGSBASE pSettings)
bool fModified = false;
const char *pchLine;
int rc;
if (!pchTab)
if (!pchTab)
fModified = true;
if (fModified)
return fModified;
static bool rewrite_ForceEol(PSCMRWSTATE pState, PSCMSTREAM pIn, PSCMSTREAM pOut, PCSCMSETTINGSBASE pSettings, SCMEOL enmDesiredEol)
bool fModified = false;
const char *pchLine;
fModified = true;
if (fModified)
return fModified;
static bool rewrite_ForceNativeEol(PSCMRWSTATE pState, PSCMSTREAM pIn, PSCMSTREAM pOut, PCSCMSETTINGSBASE pSettings)
static bool rewrite_ForceLF(PSCMRWSTATE pState, PSCMSTREAM pIn, PSCMSTREAM pOut, PCSCMSETTINGSBASE pSettings)
static bool rewrite_ForceCRLF(PSCMRWSTATE pState, PSCMSTREAM pIn, PSCMSTREAM pOut, PCSCMSETTINGSBASE pSettings)
static bool rewrite_AdjustTrailingLines(PSCMRWSTATE pState, PSCMSTREAM pIn, PSCMSTREAM pOut, PCSCMSETTINGSBASE pSettings)
cLinesNew--;
cLinesNew++;
if ( !fFixMissingEol
else if (fFixMissingEol)
static bool rewrite_Makefile_kup(PSCMRWSTATE pState, PSCMSTREAM pIn, PSCMSTREAM pOut, PCSCMSETTINGSBASE pSettings)
static bool rewrite_Makefile_kmk(PSCMRWSTATE pState, PSCMSTREAM pIn, PSCMSTREAM pOut, PCSCMSETTINGSBASE pSettings)
static bool rewrite_C_and_CPP(PSCMRWSTATE pState, PSCMSTREAM pIn, PSCMSTREAM pOut, PCSCMSETTINGSBASE pSettings)
static int scmProcessFileInner(const char *pszFilename, const char *pszBasename, size_t cchBasename,
&& !RTStrSimplePatternMultiMatch(pBaseSettings->pszFilterFiles, RTSTR_MAX, pszBasename, cchBasename, NULL))
return VINF_SUCCESS;
&& ( RTStrSimplePatternMultiMatch(pBaseSettings->pszFilterOutFiles, RTSTR_MAX, pszBasename, cchBasename, NULL)
|| RTStrSimplePatternMultiMatch(pBaseSettings->pszFilterOutFiles, RTSTR_MAX, pszFilename, RTSTR_MAX, NULL)) )
return VINF_SUCCESS;
if (RTStrSimplePatternMultiMatch(g_aConfigs[iCfg].pszFilePattern, RTSTR_MAX, pszBasename, cchBasename, NULL))
if (!pCfg)
return VINF_SUCCESS;
return rc;
bool fModified = false;
if (fRc)
fModified = true;
if (fModified)
if (!g_fDryRun)
return rc;
int rc = scmSettingsStackMakeFileBase(pSettingsStack, pszFilename, pszBasename, cchBasename, &Base);
return rc;
return RTDIRENTRYTYPE_UNKNOWN;
return RTDIRENTRYTYPE_DIRECTORY;
return RTDIRENTRYTYPE_FILE;
return RTDIRENTRYTYPE_UNKNOWN;
return rc;
return rc;
if (pszBasename)
return rc;
memcpy(&s_aOpts[RT_ELEMENTS(s_aOpts) - RT_ELEMENTS(g_aScmOpts)], &g_aScmOpts[0], sizeof(g_aScmOpts));
rc = RTGetOptInit(&GetOptState, argc, argv, &s_aOpts[0], RT_ELEMENTS(s_aOpts), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST);
switch (rc)
g_fDryRun = true;
g_fDryRun = false;
bool fAdvanceTwo = false;
case SCMOPT_FORCE_TRAILING_LINE: RTPrintf(" Default: %RTbool\n", g_Defaults.fForceTrailingLine); break;
case SCMOPT_STRIP_TRAILING_BLANKS: RTPrintf(" Default: %RTbool\n", g_Defaults.fStripTrailingBlanks); break;
case SCMOPT_STRIP_TRAILING_LINES: RTPrintf(" Default: %RTbool\n", g_Defaults.fStripTrailingLines); break;
i += fAdvanceTwo;
g_iVerbosity = 0;
g_iVerbosity++;
case SCMOPT_DIFF_IGNORE_EOL:
g_fDiffIgnoreEol = true;
g_fDiffIgnoreEol = false;
case SCMOPT_DIFF_IGNORE_SPACE:
g_fDiffIgnoreLeadingWS = true;
g_fDiffIgnoreLeadingWS = false;
g_fDiffIgnoreTrailingWS = true;
g_fDiffIgnoreTrailingWS = false;
g_fDiffSpecialChars = true;
g_fDiffSpecialChars = false;
case VINF_GETOPT_NOT_OPTION:
if (!g_fDryRun)
if (!cProcessed)
cProcessed++;
return rc;