scm.cpp revision e86538a7bc028e823f16f8982e90f0c7ef5d4ece
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * IPRT Testcase / Tool - Source Code Massager.
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync * Copyright (C) 2010 Oracle Corporation
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * available from http://www.virtualbox.org. This file is free software;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * you can redistribute it and/or modify it under the terms of the GNU
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * General Public License (GPL) as published by the Free Software
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync/*******************************************************************************
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync* Header Files *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync*******************************************************************************/
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/*******************************************************************************
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync* Defined Constants And Macros *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync*******************************************************************************/
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** The name of the settings files. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/*******************************************************************************
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync* Structures and Typedefs *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync*******************************************************************************/
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** Pointer to const massager settings. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsynctypedef struct SCMSETTINGSBASE const *PCSCMSETTINGSBASE;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** End of line marker type. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** Pointer to an end of line marker type. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Line record.
2a08e12d5dcc1bb5057a9620e87ad361d41a1c1fvboxsync /** The offset of the line. */
940dbfa4936f2e3966e9e874c4886709f0c75b44vboxsync /** The line length, excluding the LF character.
940dbfa4936f2e3966e9e874c4886709f0c75b44vboxsync * @todo This could be derived from the offset of the next line if that wasn't
2a08e12d5dcc1bb5057a9620e87ad361d41a1c1fvboxsync * so tedious. */
48d60b042893290a747d3abeda71a3085d9133fdvboxsync /** The end of line marker type. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** Pointer to a line record. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Source code massager stream.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsynctypedef struct SCMSTREAM
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Pointer to the file memory. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** The current stream position. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** The current stream size. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** The size of the memory pb points to. */
c50100d1513854735d4e3593b3b385c007f6d8b6vboxsync /** Line records. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** The current line. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** The current stream size given in lines. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** The sizeof the the memory backing paLines. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Set if write-only, clear if read-only. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Set if the memory pb points to is from RTFileReadAll. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Set if fully broken into lines. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Stream status code (IPRT). */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** Pointer to a SCM stream. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** Pointer to a const SCM stream. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * SVN property.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsynctypedef struct SCMSVNPROP
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** The property. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** The value.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * When used to record updates, this can be set to NULL to trigger the
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * deletion of the property. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** Pointer to a SVN property. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** Pointer to a const SVN property. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Rewriter state.
5eca6b757429b1f1d768e16fba65c485af34319dvboxsynctypedef struct SCMRWSTATE
2a08e12d5dcc1bb5057a9620e87ad361d41a1c1fvboxsync /** The filename. */
42c1972c22e09797b4b24afbd0ec114ed076c37cvboxsync /** Set after the printing the first verbose message about a file under
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * rewrite. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** The number of SVN property changes. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Pointer to an array of SVN property changes. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** Pointer to the rewriter state. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * A rewriter.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * This works like a stream editor, reading @a pIn, modifying it and writing it
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * to @a pOut.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns true if any changes were made, false if not.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pIn The input stream.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pOut The output stream.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pSettings The settings.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsynctypedef bool (*PFNSCMREWRITER)(PSCMRWSTATE pState, PSCMSTREAM pIn, PSCMSTREAM pOut, PCSCMSETTINGSBASE pSettings);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Configuration entry.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsynctypedef struct SCMCFGENTRY
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Number of rewriters. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Pointer to an array of rewriters. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** File pattern (simple). */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Diff state.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsynctypedef struct SCMDIFFSTATE
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Whether to ignore end of line markers when diffing. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Whether to ignore trailing whitespace. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Whether to ignore leading whitespace. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Whether to print special characters in human readable form or not. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** The tab size. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Where to push the diff. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** Pointer to a diff state. */
dee2201f96a012bfb966c8de4ab006c2c90a0eefvboxsync * Source Code Massager Settings.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Only process files that are part of a SVN working copy. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Only recurse into directories containing an .svn dir. */
38b70b2dcb1783801f7580cba797a0c8af4b5326vboxsync /** Set svn:eol-style if missing or incorrect. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Set svn:executable according to type (unually this means deleting it). */
38b70b2dcb1783801f7580cba797a0c8af4b5326vboxsync /** Set svn:keyword if completely or partially missing. */
38b70b2dcb1783801f7580cba797a0c8af4b5326vboxsync /** Only consider files matcihng these patterns. This is only applied to the
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * base names. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Filter out files matching the following patterns. This is applied to base
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * names as well as the aboslute paths. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Filter out directories matching the following patterns. This is applied
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * to base names as well as the aboslute paths. All absolute paths ends with a
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * slash and dot ("/."). */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** Pointer to massager settings. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Option identifiers.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @note The first chunk, down to SCMOPT_TAB_SIZE, are alternately set &
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * clear. So, the option setting a flag (boolean) will have an even
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * number and the one clearing it will have an odd number.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @note Down to SCMOPT_LAST_SETTINGS corresponds exactly to SCMSETTINGSBASE.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * File/dir pattern + options.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** Pointer to a pattern + option pair. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** Pointer to a settings set. */
dee2201f96a012bfb966c8de4ab006c2c90a0eefvboxsync * Settings set.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * This structure is constructed from the command line arguments or any
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * .scm-settings file found in a directory we recurse into. When recusing in
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * and out of a directory, we push and pop a settings set for it.
940dbfa4936f2e3966e9e874c4886709f0c75b44vboxsync * The .scm-settings file has two kinds of setttings, first there are the
5eca6b757429b1f1d768e16fba65c485af34319dvboxsync * unqualified base settings and then there are the settings which applies to a
5eca6b757429b1f1d768e16fba65c485af34319dvboxsync * set of files or directories. The former are lines with command line options.
940dbfa4936f2e3966e9e874c4886709f0c75b44vboxsync * For the latter, the options are preceeded by a string pattern and a colon.
940dbfa4936f2e3966e9e874c4886709f0c75b44vboxsync * The pattern specifies which files (and/or directories) the options applies
5eca6b757429b1f1d768e16fba65c485af34319dvboxsync * We parse the base options into the Base member and put the others into the
5eca6b757429b1f1d768e16fba65c485af34319dvboxsync * paPairs array.
5eca6b757429b1f1d768e16fba65c485af34319dvboxsynctypedef struct SCMSETTINGS
940dbfa4936f2e3966e9e874c4886709f0c75b44vboxsync /** Pointer to the setting file below us in the stack. */
5eca6b757429b1f1d768e16fba65c485af34319dvboxsync /** Pointer to the setting file above us in the stack. */
5eca6b757429b1f1d768e16fba65c485af34319dvboxsync /** File/dir patterns and their options. */
5eca6b757429b1f1d768e16fba65c485af34319dvboxsync /** The number of entires in paPairs. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** The base settings that was read out of the file. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** Pointer to a const settings set. */
ada08ea58e7613c10d4c40669fd4fb955324bfdfvboxsync/*******************************************************************************
dee2201f96a012bfb966c8de4ab006c2c90a0eefvboxsync* Internal Functions *
ada08ea58e7613c10d4c40669fd4fb955324bfdfvboxsync*******************************************************************************/
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic bool rewrite_StripTrailingBlanks(PSCMRWSTATE pState, PSCMSTREAM pIn, PSCMSTREAM pOut, PCSCMSETTINGSBASE pSettings);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic bool rewrite_ExpandTabs(PSCMRWSTATE pState, PSCMSTREAM pIn, PSCMSTREAM pOut, PCSCMSETTINGSBASE pSettings);
5cd35366dd244ca8c8c583904fc6ff2a0c60fa0fvboxsyncstatic bool rewrite_ForceNativeEol(PSCMRWSTATE pState, PSCMSTREAM pIn, PSCMSTREAM pOut, PCSCMSETTINGSBASE pSettings);
2a08e12d5dcc1bb5057a9620e87ad361d41a1c1fvboxsyncstatic bool rewrite_ForceLF(PSCMRWSTATE pState, PSCMSTREAM pIn, PSCMSTREAM pOut, PCSCMSETTINGSBASE pSettings);
2a08e12d5dcc1bb5057a9620e87ad361d41a1c1fvboxsyncstatic bool rewrite_ForceCRLF(PSCMRWSTATE pState, PSCMSTREAM pIn, PSCMSTREAM pOut, PCSCMSETTINGSBASE pSettings);
2a08e12d5dcc1bb5057a9620e87ad361d41a1c1fvboxsyncstatic bool rewrite_AdjustTrailingLines(PSCMRWSTATE pState, PSCMSTREAM pIn, PSCMSTREAM pOut, PCSCMSETTINGSBASE pSettings);
2a08e12d5dcc1bb5057a9620e87ad361d41a1c1fvboxsyncstatic bool rewrite_SvnNoExecutable(PSCMRWSTATE pState, PSCMSTREAM pIn, PSCMSTREAM pOut, PCSCMSETTINGSBASE pSettings);
2a08e12d5dcc1bb5057a9620e87ad361d41a1c1fvboxsyncstatic bool rewrite_SvnKeywords(PSCMRWSTATE pState, PSCMSTREAM pIn, PSCMSTREAM pOut, PCSCMSETTINGSBASE pSettings);
2a08e12d5dcc1bb5057a9620e87ad361d41a1c1fvboxsyncstatic bool rewrite_Makefile_kup(PSCMRWSTATE pState, PSCMSTREAM pIn, PSCMSTREAM pOut, PCSCMSETTINGSBASE pSettings);
2a08e12d5dcc1bb5057a9620e87ad361d41a1c1fvboxsyncstatic bool rewrite_Makefile_kmk(PSCMRWSTATE pState, PSCMSTREAM pIn, PSCMSTREAM pOut, PCSCMSETTINGSBASE pSettings);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic bool rewrite_C_and_CPP(PSCMRWSTATE pState, PSCMSTREAM pIn, PSCMSTREAM pOut, PCSCMSETTINGSBASE pSettings);
48d60b042893290a747d3abeda71a3085d9133fdvboxsync/*******************************************************************************
48d60b042893290a747d3abeda71a3085d9133fdvboxsync* Global Variables *
48d60b042893290a747d3abeda71a3085d9133fdvboxsync*******************************************************************************/
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic bool g_fDryRun = true;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic bool g_fDiffSpecialChars = true;
42c1972c22e09797b4b24afbd0ec114ed076c37cvboxsyncstatic bool g_fDiffIgnoreEol = false;
42c1972c22e09797b4b24afbd0ec114ed076c37cvboxsyncstatic bool g_fDiffIgnoreLeadingWS = false;
42c1972c22e09797b4b24afbd0ec114ed076c37cvboxsyncstatic bool g_fDiffIgnoreTrailingWS = false;
42c1972c22e09797b4b24afbd0ec114ed076c37cvboxsync/** The global settings. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* .fConvertEol = */ true,
5cd35366dd244ca8c8c583904fc6ff2a0c60fa0fvboxsync /* .fConvertTabs = */ true,
43d3e60a2bcef646da0887a845e67c3a47759158vboxsync /* .fForceFinalEol = */ true,
f20f327b65009074292a4b9ad44a02b6bfb2de8avboxsync /* .fForceTrailingLine = */ false,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* .fStripTrailingBlanks = */ true,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* .fStripTrailingLines = */ true,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* .fOnlySvnFiles = */ false,
e0b9d3c357adf9b7d05f55540e86f22943fc4b23vboxsync /* .fOnlySvnDirs = */ false,
e0b9d3c357adf9b7d05f55540e86f22943fc4b23vboxsync /* .fSetSvnEol = */ false,
e0b9d3c357adf9b7d05f55540e86f22943fc4b23vboxsync /* .fSetSvnExecutable = */ false,
e0b9d3c357adf9b7d05f55540e86f22943fc4b23vboxsync /* .fSetSvnKeywords = */ false,
e0b9d3c357adf9b7d05f55540e86f22943fc4b23vboxsync /* .pszFilterOutFiles = */ (char *)"*.exe|*.com|20*-*-*.log",
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* .pszFilterOutDirs = */ (char *)".svn|.hg|.git|CVS",
f20f327b65009074292a4b9ad44a02b6bfb2de8avboxsync/** Option definitions for the base settings. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync { "--convert-eol", SCMOPT_CONVERT_EOL, RTGETOPT_REQ_NOTHING },
e0b9d3c357adf9b7d05f55540e86f22943fc4b23vboxsync { "--no-convert-eol", SCMOPT_NO_CONVERT_EOL, RTGETOPT_REQ_NOTHING },
e0b9d3c357adf9b7d05f55540e86f22943fc4b23vboxsync { "--convert-tabs", SCMOPT_CONVERT_TABS, RTGETOPT_REQ_NOTHING },
e0b9d3c357adf9b7d05f55540e86f22943fc4b23vboxsync { "--no-convert-tabs", SCMOPT_NO_CONVERT_TABS, RTGETOPT_REQ_NOTHING },
e0b9d3c357adf9b7d05f55540e86f22943fc4b23vboxsync { "--force-final-eol", SCMOPT_FORCE_FINAL_EOL, RTGETOPT_REQ_NOTHING },
e0b9d3c357adf9b7d05f55540e86f22943fc4b23vboxsync { "--no-force-final-eol", SCMOPT_NO_FORCE_FINAL_EOL, RTGETOPT_REQ_NOTHING },
e0b9d3c357adf9b7d05f55540e86f22943fc4b23vboxsync { "--force-trailing-line", SCMOPT_FORCE_TRAILING_LINE, RTGETOPT_REQ_NOTHING },
e0b9d3c357adf9b7d05f55540e86f22943fc4b23vboxsync { "--no-force-trailing-line", SCMOPT_NO_FORCE_TRAILING_LINE, RTGETOPT_REQ_NOTHING },
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync { "--strip-trailing-blanks", SCMOPT_STRIP_TRAILING_BLANKS, RTGETOPT_REQ_NOTHING },
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync { "--no-strip-trailing-blanks", SCMOPT_NO_STRIP_TRAILING_BLANKS, RTGETOPT_REQ_NOTHING },
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync { "--strip-trailing-lines", SCMOPT_STRIP_TRAILING_LINES, RTGETOPT_REQ_NOTHING },
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync { "--strip-no-trailing-lines", SCMOPT_NO_STRIP_TRAILING_LINES, RTGETOPT_REQ_NOTHING },
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync { "--only-svn-dirs", SCMOPT_ONLY_SVN_DIRS, RTGETOPT_REQ_NOTHING },
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync { "--not-only-svn-dirs", SCMOPT_NOT_ONLY_SVN_DIRS, RTGETOPT_REQ_NOTHING },
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync { "--only-svn-files", SCMOPT_ONLY_SVN_FILES, RTGETOPT_REQ_NOTHING },
dee2201f96a012bfb966c8de4ab006c2c90a0eefvboxsync { "--not-only-svn-files", SCMOPT_NOT_ONLY_SVN_FILES, RTGETOPT_REQ_NOTHING },
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync { "--set-svn-eol", SCMOPT_SET_SVN_EOL, RTGETOPT_REQ_NOTHING },
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync { "--dont-set-svn-eol", SCMOPT_DONT_SET_SVN_EOL, RTGETOPT_REQ_NOTHING },
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync { "--set-svn-executable", SCMOPT_SET_SVN_EXECUTABLE, RTGETOPT_REQ_NOTHING },
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync { "--dont-set-svn-executable", SCMOPT_DONT_SET_SVN_EXECUTABLE, RTGETOPT_REQ_NOTHING },
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync { "--set-svn-keywords", SCMOPT_SET_SVN_KEYWORDS, RTGETOPT_REQ_NOTHING },
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync { "--dont-set-svn-keywords", SCMOPT_DONT_SET_SVN_KEYWORDS, RTGETOPT_REQ_NOTHING },
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync { "--tab-size", SCMOPT_TAB_SIZE, RTGETOPT_REQ_UINT8 },
dee2201f96a012bfb966c8de4ab006c2c90a0eefvboxsync { "--filter-out-dirs", SCMOPT_FILTER_OUT_DIRS, RTGETOPT_REQ_STRING },
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync { "--filter-files", SCMOPT_FILTER_FILES, RTGETOPT_REQ_STRING },
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync { "--filter-out-files", SCMOPT_FILTER_OUT_FILES, RTGETOPT_REQ_STRING },
f20f327b65009074292a4b9ad44a02b6bfb2de8avboxsync/** Consider files matching the following patterns (base names only). */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic PFNSCMREWRITER const g_aRewritersFor_Makefile_kup[] =
1bc5a31ae6d57c2b4731a23205f3958678b60193vboxsyncstatic PFNSCMREWRITER const g_aRewritersFor_Makefile_kmk[] =
e0b9d3c357adf9b7d05f55540e86f22943fc4b23vboxsyncstatic PFNSCMREWRITER const g_aRewritersFor_C_and_CPP[] =
f20f327b65009074292a4b9ad44a02b6bfb2de8avboxsyncstatic PFNSCMREWRITER const g_aRewritersFor_H_and_HPP[] =
c50100d1513854735d4e3593b3b385c007f6d8b6vboxsyncstatic PFNSCMREWRITER const g_aRewritersFor_ShellScripts[] =
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic PFNSCMREWRITER const g_aRewritersFor_BatchFiles[] =
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync { RT_ELEMENTS(g_aRewritersFor_Makefile_kup), &g_aRewritersFor_Makefile_kup[0], "Makefile.kup" },
dee2201f96a012bfb966c8de4ab006c2c90a0eefvboxsync { RT_ELEMENTS(g_aRewritersFor_Makefile_kmk), &g_aRewritersFor_Makefile_kmk[0], "Makefile.kmk|Config.kmk" },
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync { RT_ELEMENTS(g_aRewritersFor_C_and_CPP), &g_aRewritersFor_C_and_CPP[0], "*.c|*.cpp|*.C|*.CPP|*.cxx|*.cc" },
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync { RT_ELEMENTS(g_aRewritersFor_H_and_HPP), &g_aRewritersFor_H_and_HPP[0], "*.h|*.hpp" },
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync { RT_ELEMENTS(g_aRewritersFor_RC), &g_aRewritersFor_RC[0], "*.rc" },
6565c2fb4f10f47bcb5436630d2dc35e5a4f28e2vboxsync { RT_ELEMENTS(g_aRewritersFor_ShellScripts), &g_aRewritersFor_ShellScripts[0], "*.sh|configure" },
6c83eb6b98d1dd1b1d9795c16801ee2f53d2cc31vboxsync { RT_ELEMENTS(g_aRewritersFor_BatchFiles), &g_aRewritersFor_BatchFiles[0], "*.bat|*.cmd|*.btm|*.vbs|*.ps1" },
6565c2fb4f10f47bcb5436630d2dc35e5a4f28e2vboxsync/* -=-=-=-=-=- memory streams -=-=-=-=-=- */
2da513a7caa29822c9991d7e8615658a194c0cf8vboxsync * Initializes the stream structure.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pStream The stream structure.
86b620001857a05e9e7b83b11525094c34637e23vboxsync * @param fWriteOrRead The value of the fWriteOrRead stream member.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic void scmStreamInitInternal(PSCMSTREAM pStream, bool fWriteOrRead)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Initialize an input stream.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns IPRT status code.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pStream The stream to initialize.
dee2201f96a012bfb966c8de4ab006c2c90a0eefvboxsync * @param pszFilename The file to take the stream content from.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncint ScmStreamInitForReading(PSCMSTREAM pStream, const char *pszFilename)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync scmStreamInitInternal(pStream, false /*fWriteOrRead*/);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync int rc = pStream->rc = RTFileReadAll(pszFilename, &pvFile, &cbFile);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Initialize an output stream.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns IPRT status code
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pStream The stream to initialize.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pRelatedStream Pointer to a related stream. NULL is fine.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncint ScmStreamInitForWriting(PSCMSTREAM pStream, PCSCMSTREAM pRelatedStream)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync scmStreamInitInternal(pStream, true /*fWriteOrRead*/);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* allocate stuff */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync size_t cLinesEstimate = pRelatedStream && pRelatedStream->fFullyLineated
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync ? pRelatedStream->cLines + pRelatedStream->cLines / 10
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pStream->paLines = (PSCMSTREAMLINE)RTMemAlloc(cLinesEstimate * sizeof(SCMSTREAMLINE));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Frees the resources associated with the stream.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Nothing is happens to whatever the stream was initialized from or dumped to.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pStream The stream to delete.
38b70b2dcb1783801f7580cba797a0c8af4b5326vboxsync RTFileReadAllFree(pStream->pch, pStream->cbAllocated);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Get the stream status code.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns IPRT status code.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pStream The stream.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Grows the buffer of a write stream.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns IPRT status code.
38b70b2dcb1783801f7580cba797a0c8af4b5326vboxsync * @param pStream The stream. Must be in write mode.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param cbAppending The minimum number of bytes to grow the buffer
38b70b2dcb1783801f7580cba797a0c8af4b5326vboxsyncstatic int scmStreamGrowBuffer(PSCMSTREAM pStream, size_t cbAppending)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync cbAllocated += RT_MAX(0x1000 + cbAppending, cbAllocated);
if (!pvNew)
return VINF_SUCCESS;
if (!pvNew)
return VINF_SUCCESS;
case SCMEOL_LF:
case SCMEOL_CRLF:
case SCMEOL_NONE:
return VINF_SUCCESS;
int rc;
#ifdef RT_STRICT
return rc;
rc = RTFileOpenV(&hFile, RTFILE_O_WRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_WRITE, pszFilenameFmt, va);
return rc;
return NULL;
return NULL;
return NULL;
cb--;
return pchRet;
return rc;
return VINF_SUCCESS;
if (offRelative >= 0)
offAbsolute = 0;
return rc;
return VINF_SUCCESS;
static const char *ScmStreamGetLineByNo(PSCMSTREAM pStream, size_t iLine, size_t *pcchLine, PSCMEOL penmEol)
return NULL;
return NULL;
return NULL;
pStream->off = pStream->paLines[iLine].off + pStream->paLines[iLine].cch + pStream->paLines[iLine].enmEol;
return pchRet;
return VERR_EOF;
if (!pchLine)
return cchLine == 0;
return enmEol;
return enmEol;
return rc;
return rc;
return rc;
iLine++;
return VINF_SUCCESS;
return rc;
iLine--;
if (!pchLF)
return rc;
if ( cchLine
cchLine--;
iLine++;
if (!pchLF)
return VINF_SUCCESS;
return VINF_SUCCESS;
while (cLines-- > 0)
if (!pchLine)
return rc;
return VINF_SUCCESS;
static void scmDiffPrintLines(PSCMDIFFSTATE pState, char chPrefix, PSCMSTREAM pStream, size_t iLine, size_t cLines)
while (cLines-- > 0)
while (pchTab)
switch (cchTab)
if (cchLeft)
iLine++;
if (c >= iLeft)
iLeft = c;
cLeft = 0;
if (c >= iRight)
iRight = c;
cRight = 0;
: cRight == 0
RTStrmPrintf(pState->pDiff, "%zu,%zu%c%zu,%zu\n", iLeft + 1, iLeft + cLeft, ch, iRight + 1, iRight + cRight);
if (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_ONLY_SVN_DIRS:
return VINF_SUCCESS;
case SCMOPT_NOT_ONLY_SVN_DIRS:
return VINF_SUCCESS;
case SCMOPT_ONLY_SVN_FILES:
return VINF_SUCCESS;
return VINF_SUCCESS;
case SCMOPT_SET_SVN_EOL:
return VINF_SUCCESS;
case SCMOPT_DONT_SET_SVN_EOL:
return VINF_SUCCESS;
return VINF_SUCCESS;
return VINF_SUCCESS;
case SCMOPT_SET_SVN_KEYWORDS:
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:
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)
#define SCM_WITHOUT_LIBSVN
#ifdef SCM_WITHOUT_LIBSVN
static DECLCALLBACK(int) scmSvnFindSvnBinaryCallback(char const *pchPath, size_t cchPath, void *pvUser1, void *pvUser2)
return VINF_SUCCESS;
return VERR_TRY_AGAIN;
#ifdef RT_OS_WINDOWS
if (pszPath)
static int scmSvnConstructName(PSCMRWSTATE pState, const char *pszDir, const char *pszSuff, char *pszDst)
return VINF_SUCCESS;
return rc;
size_t u = 0;
while (cch-- > 0)
*pu = u;
#ifdef SCM_WITHOUT_LIBSVN
if (!pszValue)
return VERR_NOT_FOUND;
if (ppszValue)
return VINF_SUCCESS;
#ifdef SCM_WITHOUT_LIBSVN
const char *pchLine;
|| cchKey == 0
RTMsgError("%s:%u: Unexpected data '%.*s'\n", szPath, ScmStreamTellLine(&Stream), cchLine, pchLine);
if (fMatch)
if (!pchLine)
if (!pchLine)
RTMsgError("%s:%u: Unexpected data '%.*s'\n", szPath, ScmStreamTellLine(&Stream), cchLine, pchLine);
if (fMatch)
if (!ppszValue)
char *pszValue;
return rc;
return VERR_NOT_FOUND;
if (!pszValue)
char *pszCopy;
return rc;
return VINF_SUCCESS;
if (!pvNew)
return VERR_NO_MEMORY;
return VERR_NO_MEMORY;
return VINF_SUCCESS;
if (pszValue)
return VINF_SUCCESS;
#ifdef SCM_WITHOUT_LIBSVN
return VERR_GENERAL_FAILURE;
return rc;
return VINF_SUCCESS;
return VERR_NOT_IMPLEMENTED;
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,
bool fModified = false;
const char *pchLine;
fModified = true;
if (fModified)
char *pszEol;
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_SvnNoExecutable(PSCMRWSTATE pState, PSCMSTREAM pIn, PSCMSTREAM pOut, PCSCMSETTINGSBASE pSettings)
static bool rewrite_SvnKeywords(PSCMRWSTATE pState, PSCMSTREAM pIn, PSCMSTREAM pOut, PCSCMSETTINGSBASE pSettings)
char *pszKeywords;
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(PSCMRWSTATE pState, 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;
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)
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;
int rc;
return rc;
return VINF_SUCCESS;
return rc;
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;
if (fAdvanceTwo)
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;
case SCMOPT_SET_SVN_EXECUTABLE: RTPrintf(" Default: %RTbool\n", g_Defaults.fSetSvnExecutable); 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;