Changeset 26477 in vbox
- Timestamp:
- Feb 13, 2010 3:40:00 AM (15 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/bldprogs/scm.cpp
r26359 r26477 48 48 49 49 /******************************************************************************* 50 * Internal Functions*50 * Defined Constants And Macros * 51 51 *******************************************************************************/ 52 /** The name of the settings files. */ 53 #define SCM_SETTINGS_FILENAME ".scm-settings" 54 55 56 /******************************************************************************* 57 * Structures and Typedefs * 58 *******************************************************************************/ 59 /** Pointer to const massager settings. */ 60 typedef struct SCMSETTINGSBASE const *PCSCMSETTINGSBASE; 61 52 62 /** End of line marker type. */ 53 63 typedef enum SCMEOL … … 122 132 * 123 133 * @returns true if any changes were made, false if not. 124 * @param pIn The input stream. 125 * @param pOut The output stream. 126 */ 127 typedef bool (*PFNSCMREWRITER)(PSCMSTREAM pIn, PSCMSTREAM pOut); 134 * @param pIn The input stream. 135 * @param pOut The output stream. 136 * @param pSettings The settings. 137 */ 138 typedef bool (*PFNSCMREWRITER)(PSCMSTREAM pIn, PSCMSTREAM pOut, PCSCMSETTINGSBASE pSettings); 128 139 129 140 … … 163 174 /** Whether to print special characters in human readable form or not. */ 164 175 bool fSpecialChars; 176 /** The tab size. */ 177 size_t cchTab; 165 178 /** Where to push the diff. */ 166 179 PRTSTREAM pDiff; … … 169 182 typedef SCMDIFFSTATE *PSCMDIFFSTATE; 170 183 184 /** 185 * Source Code Massager Settings. 186 */ 187 typedef struct SCMSETTINGSBASE 188 { 189 bool fConvertEol; 190 bool fConvertTabs; 191 bool fForceFinalEol; 192 bool fForceTrailingLine; 193 bool fStripTrailingBlanks; 194 bool fStripTrailingLines; 195 unsigned cchTab; 196 } SCMSETTINGSBASE; 197 /** Pointer to massager settings. */ 198 typedef SCMSETTINGSBASE *PSCMSETTINGSBASE; 199 200 /** 201 * Option identifiers. 202 * 203 * @note The first chunk, down to SCMOPT_TAB_SIZE, are alternately set & 204 * clear. So, the option setting a flag (boolean) will have an even 205 * number and the one clearing it will have an odd number. 206 * @note Down to SCMOPT_LAST_SETTINGS corresponds exactly to SCMSETTINGSBASE. 207 */ 208 typedef enum SCMOPT 209 { 210 SCMOPT_CONVERT_EOL = 10000, 211 SCMOPT_NO_CONVERT_EOL, 212 SCMOPT_CONVERT_TABS, 213 SCMOPT_NO_CONVERT_TABS, 214 SCMOPT_FORCE_FINAL_EOL, 215 SCMOPT_NO_FORCE_FINAL_EOL, 216 SCMOPT_FORCE_TRAILING_LINE, 217 SCMOPT_NO_FORCE_TRAILING_LINE, 218 SCMOPT_STRIP_TRAILING_BLANKS, 219 SCMOPT_NO_STRIP_TRAILING_BLANKS, 220 SCMOPT_STRIP_TRAILING_LINES, 221 SCMOPT_NO_STRIP_TRAILING_LINES, 222 SCMOPT_TAB_SIZE, 223 SCMOPT_LAST_SETTINGS = SCMOPT_TAB_SIZE, 224 // 225 SCMOPT_DIFF_IGNORE_EOL, 226 SCMOPT_DIFF_NO_IGNORE_EOL, 227 SCMOPT_DIFF_IGNORE_SPACE, 228 SCMOPT_DIFF_NO_IGNORE_SPACE, 229 SCMOPT_DIFF_IGNORE_LEADING_SPACE, 230 SCMOPT_DIFF_NO_IGNORE_LEADING_SPACE, 231 SCMOPT_DIFF_IGNORE_TRAILING_SPACE, 232 SCMOPT_DIFF_NO_IGNORE_TRAILING_SPACE, 233 SCMOPT_DIFF_SPECIAL_CHARS, 234 SCMOPT_DIFF_NO_SPECIAL_CHARS, 235 SCMOPT_END 236 } SCMOPT; 237 238 239 /** 240 * File/dir pattern + options. 241 */ 242 typedef struct SCMPATRNOPTPAIR 243 { 244 char *pszPattern; 245 char *pszOptions; 246 } SCMPATRNOPTPAIR; 247 /** Pointer to a pattern + option pair. */ 248 typedef SCMPATRNOPTPAIR *PSCMPATRNOPTPAIR; 249 250 251 /** Pointer to a settings set. */ 252 typedef struct SCMSETTINGS *PSCMSETTINGS; 253 /** 254 * Settings set. 255 * 256 * This structure is constructed from the command line arguments or any 257 * .scm-settings file found in a directory we recurse into. When recusing in 258 * and out of a directory, we push and pop a settings set for it. 259 * 260 * The .scm-settings file has two kinds of setttings, first there are the 261 * unqualified base settings and then there are the settings which applies to a 262 * set of files or directories. The former are lines with command line options. 263 * For the latter, the options are preceeded by a string pattern and a colon. 264 * The pattern specifies which files (and/or directories) the options applies 265 * to. 266 * 267 * We parse the base options into the Base member and put the others into the 268 * paPairs array. 269 */ 270 typedef struct SCMSETTINGS 271 { 272 /** Pointer to the setting file below us in the stack. */ 273 PSCMSETTINGS pDown; 274 /** Pointer to the setting file above us in the stack. */ 275 PSCMSETTINGS pUp; 276 /** File/dir patterns and their options. */ 277 PSCMPATRNOPTPAIR paPairs; 278 /** The number of entires in paPairs. */ 279 uint32_t cPairs; 280 /** The base settings that was read out of the file. */ 281 SCMSETTINGSBASE Base; 282 } SCMSETTINGS; 283 /** Pointer to a const settings set. */ 284 typedef SCMSETTINGS const *PCSCMSETTINGS; 285 286 171 287 172 288 /******************************************************************************* 173 289 * Internal Functions * 174 290 *******************************************************************************/ 175 static bool rewrite_StripTrailingBlanks(PSCMSTREAM pIn, PSCMSTREAM pOut );176 static bool rewrite_ExpandTabs(PSCMSTREAM pIn, PSCMSTREAM pOut );177 static bool rewrite_ForceNativeEol(PSCMSTREAM pIn, PSCMSTREAM pOut );178 static bool rewrite_ForceLF(PSCMSTREAM pIn, PSCMSTREAM pOut );179 static bool rewrite_ForceCRLF(PSCMSTREAM pIn, PSCMSTREAM pOut );180 static bool rewrite_AdjustTrailingLines(PSCMSTREAM pIn, PSCMSTREAM pOut );181 static bool rewrite_Makefile_kup(PSCMSTREAM pIn, PSCMSTREAM pOut );182 static bool rewrite_Makefile_kmk(PSCMSTREAM pIn, PSCMSTREAM pOut );183 static bool rewrite_C_and_CPP(PSCMSTREAM pIn, PSCMSTREAM pOut );291 static bool rewrite_StripTrailingBlanks(PSCMSTREAM pIn, PSCMSTREAM pOut, PCSCMSETTINGSBASE pSettings); 292 static bool rewrite_ExpandTabs(PSCMSTREAM pIn, PSCMSTREAM pOut, PCSCMSETTINGSBASE pSettings); 293 static bool rewrite_ForceNativeEol(PSCMSTREAM pIn, PSCMSTREAM pOut, PCSCMSETTINGSBASE pSettings); 294 static bool rewrite_ForceLF(PSCMSTREAM pIn, PSCMSTREAM pOut, PCSCMSETTINGSBASE pSettings); 295 static bool rewrite_ForceCRLF(PSCMSTREAM pIn, PSCMSTREAM pOut, PCSCMSETTINGSBASE pSettings); 296 static bool rewrite_AdjustTrailingLines(PSCMSTREAM pIn, PSCMSTREAM pOut, PCSCMSETTINGSBASE pSettings); 297 static bool rewrite_Makefile_kup(PSCMSTREAM pIn, PSCMSTREAM pOut, PCSCMSETTINGSBASE pSettings); 298 static bool rewrite_Makefile_kmk(PSCMSTREAM pIn, PSCMSTREAM pOut, PCSCMSETTINGSBASE pSettings); 299 static bool rewrite_C_and_CPP(PSCMSTREAM pIn, PSCMSTREAM pOut, PCSCMSETTINGSBASE pSettings); 184 300 185 301 … … 189 305 static const char g_szProgName[] = "scm"; 190 306 static const char *g_pszChangedSuff = ""; 307 static const char g_szTabSpaces[16+1] = " "; 191 308 static bool g_fDryRun = true; 192 static bool g_fStripTrailingBlanks = true;193 static bool g_fStripTrailingLines = true;194 static bool g_fForceFinalEol = true;195 static bool g_fForceTrailingLine = false;196 static bool g_fConvertTabs = true;197 static unsigned g_cchTab = 8;198 static const char g_szTabSpaces[16+1] = " ";199 static bool g_fConvertEol = true;200 309 static bool g_fDiffSpecialChars = true; 201 310 static bool g_fDiffIgnoreEol = false; … … 203 312 static bool g_fDiffIgnoreTrailingWS = false; 204 313 static int g_iVerbosity = 2;//99; //0; 205 static const char *g_pszFileFilter = "*"; 314 315 /** The global settings. */ 316 static SCMSETTINGSBASE const g_Defaults = 317 { 318 /* .fStripTrailingBlanks = */ true, 319 /* .fStripTrailingLines = */ true, 320 /* .fForceFinalEol = */ true, 321 /* .fForceTrailingLine = */ false, 322 /* .fConvertTabs = */ true, 323 /* .cchTab = */ 8, 324 /* .fConvertEol = */ true 325 }; 326 327 /** Option definitions for the base settings. */ 328 static RTGETOPTDEF g_aScmOpts[] = 329 { 330 { "--convert-eol", SCMOPT_CONVERT_EOL, RTGETOPT_REQ_NOTHING }, 331 { "--no-convert-eol", SCMOPT_NO_CONVERT_EOL, RTGETOPT_REQ_NOTHING }, 332 { "--convert-tabs", SCMOPT_CONVERT_TABS, RTGETOPT_REQ_NOTHING }, 333 { "--no-convert-tabs", SCMOPT_NO_CONVERT_TABS, RTGETOPT_REQ_NOTHING }, 334 { "--force-final-eol", SCMOPT_FORCE_FINAL_EOL, RTGETOPT_REQ_NOTHING }, 335 { "--no-force-final-eol", SCMOPT_NO_FORCE_FINAL_EOL, RTGETOPT_REQ_NOTHING }, 336 { "--force-trailing-line", SCMOPT_FORCE_TRAILING_LINE, RTGETOPT_REQ_NOTHING }, 337 { "--no-force-trailing-line", SCMOPT_NO_FORCE_TRAILING_LINE, RTGETOPT_REQ_NOTHING }, 338 { "--strip-trailing-blanks", SCMOPT_STRIP_TRAILING_BLANKS, RTGETOPT_REQ_NOTHING }, 339 { "--no-strip-trailing-blanks", SCMOPT_NO_STRIP_TRAILING_BLANKS, RTGETOPT_REQ_NOTHING }, 340 { "--strip-trailing-lines", SCMOPT_STRIP_TRAILING_LINES, RTGETOPT_REQ_NOTHING }, 341 { "--strip-no-trailing-lines", SCMOPT_NO_STRIP_TRAILING_LINES, RTGETOPT_REQ_NOTHING }, 342 { "--tab-size", SCMOPT_TAB_SIZE, RTGETOPT_REQ_UINT8 }, 343 }; 344 345 /** Consider files matching the following patterns (base names only). */ 346 static const char *g_pszFileFilter = NULL; 347 /** Filter out files matching the following patterns. This is applied to the 348 * base names as well as the absolute paths. */ 206 349 static const char *g_pszFileFilterOut = 207 350 "*.exe|" … … 214 357 "/dummy/." 215 358 ; 359 /** Consider directories matching the following patterns (base names only) */ 216 360 static const char *g_pszDirFilter = NULL; 361 /** Filter out directories matching the following patterns. This is applied 362 * to base names as well as the aboslute paths. All absolute paths ends with a 363 * slash and dot ("/."). */ 217 364 static const char *g_pszDirFilterOut = 218 365 // generic 219 366 ".svn|" 367 ".hg|" 368 ".git|" 220 369 "CVS|" 221 370 // root … … 1185 1334 offVir += pchTab - pchStart; 1186 1335 1187 size_t cchTab = g_cchTab - offVir % g_cchTab;1336 size_t cchTab = pState->cchTab - offVir % pState->cchTab; 1188 1337 switch (cchTab) 1189 1338 { … … 1486 1635 * @param fSpecialChars Whether to print special chars in a human 1487 1636 * readable form or not. 1637 * @param cchTab The tab size. 1488 1638 * @param pDiff Where to write the diff. 1489 1639 */ 1490 1640 size_t ScmDiffStreams(const char *pszFilename, PSCMSTREAM pLeft, PSCMSTREAM pRight, bool fIgnoreEol, 1491 bool fIgnoreLeadingWhite, bool fIgnoreTrailingWhite, bool fSpecialChars, PRTSTREAM pDiff) 1641 bool fIgnoreLeadingWhite, bool fIgnoreTrailingWhite, bool fSpecialChars, 1642 size_t cchTab, PRTSTREAM pDiff) 1492 1643 { 1493 1644 #ifdef RT_STRICT … … 1508 1659 State.fIgnoreTrailingWhite = fIgnoreTrailingWhite; 1509 1660 State.fSpecialChars = fSpecialChars; 1661 State.cchTab = cchTab; 1510 1662 State.pDiff = pDiff; 1511 1663 … … 1555 1707 1556 1708 1709 /* -=-=-=-=-=- settings -=-=-=-=-=- */ 1710 1711 /** 1712 * Init a settings structure with settings from @a pSrc. 1713 * 1714 * @returns IPRT status code 1715 * @param pSettings The settings. 1716 * @param pSrc The source settings. 1717 */ 1718 static int scmSettingsBaseInitAndCopy(PSCMSETTINGSBASE pSettings, PCSCMSETTINGSBASE pSrc) 1719 { 1720 *pSettings = *pSrc; 1721 /* No dynamically allocated stuff yet. */ 1722 return VINF_SUCCESS; 1723 } 1724 1725 /** 1726 * Init a settings structure. 1727 * 1728 * @returns IPRT status code 1729 * @param pSettings The settings. 1730 */ 1731 static int scmSettingsBaseInit(PSCMSETTINGSBASE pSettings) 1732 { 1733 return scmSettingsBaseInitAndCopy(pSettings, &g_Defaults); 1734 } 1735 1736 /** 1737 * Deletes the settings, i.e. free any dynamically allocated content. 1738 * 1739 * @param pSettings The settings. 1740 */ 1741 static void scmSettingsBaseDelete(PSCMSETTINGSBASE pSettings) 1742 { 1743 if (pSettings) 1744 { 1745 Assert(pSettings->cchTab != ~(unsigned)0); 1746 pSettings->cchTab = ~(unsigned)0; 1747 /* No dynamically allocated stuff yet. */ 1748 } 1749 } 1750 1751 /** 1752 * Processes a RTGetOpt result. 1753 * 1754 * @retval VINF_SUCCESS if handled. 1755 * @retval VERR_OUT_OF_RANGE if the option value was out of range. 1756 * @retval VERR_GETOPT_UNKNOWN_OPTION if the option was not recognized. 1757 * 1758 * @param pSettings The settings to change. 1759 * @param rc The RTGetOpt return value. 1760 * @param pValueUnion The RTGetOpt value union. 1761 */ 1762 static int scmSettingsBaseHandleOpt(PSCMSETTINGSBASE pSettings, int rc, PRTGETOPTUNION pValueUnion) 1763 { 1764 switch (rc) 1765 { 1766 case SCMOPT_CONVERT_EOL: 1767 pSettings->fConvertEol = true; 1768 return VINF_SUCCESS; 1769 case SCMOPT_NO_CONVERT_EOL: 1770 pSettings->fConvertEol = false; 1771 return VINF_SUCCESS; 1772 1773 case SCMOPT_CONVERT_TABS: 1774 pSettings->fConvertTabs = true; 1775 return VINF_SUCCESS; 1776 case SCMOPT_NO_CONVERT_TABS: 1777 pSettings->fConvertTabs = false; 1778 return VINF_SUCCESS; 1779 1780 case SCMOPT_FORCE_FINAL_EOL: 1781 pSettings->fForceFinalEol = true; 1782 return VINF_SUCCESS; 1783 case SCMOPT_NO_FORCE_FINAL_EOL: 1784 pSettings->fForceFinalEol = false; 1785 return VINF_SUCCESS; 1786 1787 case SCMOPT_FORCE_TRAILING_LINE: 1788 pSettings->fForceTrailingLine = true; 1789 return VINF_SUCCESS; 1790 case SCMOPT_NO_FORCE_TRAILING_LINE: 1791 pSettings->fForceTrailingLine = false; 1792 return VINF_SUCCESS; 1793 1794 case SCMOPT_STRIP_TRAILING_BLANKS: 1795 pSettings->fStripTrailingBlanks = true; 1796 return VINF_SUCCESS; 1797 case SCMOPT_NO_STRIP_TRAILING_BLANKS: 1798 pSettings->fStripTrailingBlanks = false; 1799 return VINF_SUCCESS; 1800 1801 case SCMOPT_STRIP_TRAILING_LINES: 1802 pSettings->fStripTrailingLines = true; 1803 return VINF_SUCCESS; 1804 case SCMOPT_NO_STRIP_TRAILING_LINES: 1805 pSettings->fStripTrailingLines = false; 1806 return VINF_SUCCESS; 1807 1808 case SCMOPT_TAB_SIZE: 1809 if ( pValueUnion->u8 < 1 1810 || pValueUnion->u8 >= RT_ELEMENTS(g_szTabSpaces)) 1811 { 1812 RTMsgError("Invalid tab size: %u - must be in {1..%u}\n", 1813 pValueUnion->u8, RT_ELEMENTS(g_szTabSpaces) - 1); 1814 return VERR_OUT_OF_RANGE; 1815 } 1816 pSettings->cchTab = pValueUnion->u8; 1817 return VINF_SUCCESS; 1818 1819 default: 1820 return VERR_GETOPT_UNKNOWN_OPTION; 1821 } 1822 } 1823 1824 /** 1825 * Parses an option string. 1826 * 1827 * @returns IPRT status code. 1828 * @param pBase The base settings structure to apply the options 1829 * to. 1830 * @param pszOptions The options to parse. 1831 */ 1832 static int scmSettingsBaseParseString(PSCMSETTINGSBASE pBase, const char *pszLine) 1833 { 1834 int cArgs; 1835 char **papszArgs; 1836 int rc = RTGetOptArgvFromString(&papszArgs, &cArgs, pszLine, NULL); 1837 if (RT_SUCCESS(rc)) 1838 { 1839 RTGETOPTUNION ValueUnion; 1840 RTGETOPTSTATE GetOptState; 1841 rc = RTGetOptInit(&GetOptState, cArgs, papszArgs, &g_aScmOpts[0], RT_ELEMENTS(g_aScmOpts), 0, 0 /*fFlags*/); 1842 if (RT_SUCCESS(rc)) 1843 { 1844 while ((rc = RTGetOpt(&GetOptState, &ValueUnion)) != 0) 1845 { 1846 rc = scmSettingsBaseHandleOpt(pBase, rc, &ValueUnion); 1847 if (RT_FAILURE(rc)) 1848 break; 1849 } 1850 } 1851 RTGetOptArgvFree(papszArgs); 1852 } 1853 1854 return rc; 1855 } 1856 1857 /** 1858 * Parses an unterminated option string. 1859 * 1860 * @returns IPRT status code. 1861 * @param pBase The base settings structure to apply the options 1862 * to. 1863 * @param pchLine The line. 1864 * @param cchLine The line length. 1865 */ 1866 static int scmSettingsBaseParseStringN(PSCMSETTINGSBASE pBase, const char *pchLine, size_t cchLine) 1867 { 1868 char *pszLine = RTStrDupN(pchLine, cchLine); 1869 if (!pszLine) 1870 return VERR_NO_MEMORY; 1871 int rc = scmSettingsBaseParseString(pBase, pszLine); 1872 RTStrFree(pszLine); 1873 return rc; 1874 } 1875 1876 /** 1877 * Verifies the options string. 1878 * 1879 * @returns IPRT status code. 1880 * @param pszOptions The options to verify . 1881 */ 1882 static int scmSettingsBaseVerifyString(const char *pszOptions) 1883 { 1884 SCMSETTINGSBASE Base; 1885 int rc = scmSettingsBaseInit(&Base); 1886 if (RT_SUCCESS(rc)) 1887 { 1888 rc = scmSettingsBaseParseString(&Base, pszOptions); 1889 scmSettingsBaseDelete(&Base); 1890 } 1891 return rc; 1892 } 1893 1894 /** 1895 * Loads settings found in editor and SCM settings directives within the 1896 * document (@a pStream). 1897 * 1898 * @returns IPRT status code. 1899 * @param pBase The settings base to load settings into. 1900 * @param pStream The stream to scan for settings directives. 1901 */ 1902 static int scmSettingsBaseLoadFromDocument(PSCMSETTINGSBASE pBase, PSCMSTREAM pStream) 1903 { 1904 /** @todo Editor and SCM settings directives in documents. */ 1905 return VINF_SUCCESS; 1906 } 1907 1908 /** 1909 * Creates a new settings file struct, cloning @a pSettings. 1910 * 1911 * @returns IPRT status code. 1912 * @param ppSettings Where to return the new struct. 1913 * @param pSettingsBase The settings to inherit from. 1914 */ 1915 static int scmSettingsCreate(PSCMSETTINGS *ppSettings, PCSCMSETTINGSBASE pSettingsBase) 1916 { 1917 PSCMSETTINGS pSettings = (PSCMSETTINGS)RTMemAlloc(sizeof(*pSettings)); 1918 if (!pSettings) 1919 return VERR_NO_MEMORY; 1920 int rc = scmSettingsBaseInitAndCopy(&pSettings->Base, pSettingsBase); 1921 if (RT_SUCCESS(rc)) 1922 { 1923 pSettings->pDown = NULL; 1924 pSettings->pUp = NULL; 1925 pSettings->paPairs = NULL; 1926 pSettings->cPairs = 0; 1927 *ppSettings = pSettings; 1928 return VINF_SUCCESS; 1929 } 1930 RTMemFree(pSettings); 1931 return rc; 1932 } 1933 1934 /** 1935 * Destroys a settings structure. 1936 * 1937 * @param pSettings The settgins structure to destroy. NULL is OK. 1938 */ 1939 static void scmSettingsDestroy(PSCMSETTINGS pSettings) 1940 { 1941 if (pSettings) 1942 { 1943 scmSettingsBaseDelete(&pSettings->Base); 1944 for (size_t i = 0; i < pSettings->cPairs; i++) 1945 { 1946 RTStrFree(pSettings->paPairs[i].pszPattern); 1947 RTStrFree(pSettings->paPairs[i].pszOptions); 1948 pSettings->paPairs[i].pszPattern = NULL; 1949 pSettings->paPairs[i].pszOptions = NULL; 1950 } 1951 RTMemFree(pSettings->paPairs); 1952 pSettings->paPairs = NULL; 1953 RTMemFree(pSettings); 1954 } 1955 } 1956 1957 /** 1958 * Adds a pattern/options pair to the settings structure. 1959 * 1960 * @returns IPRT status code. 1961 * @param pSettings The settings. 1962 * @param pchLine The line containing the unparsed pair. 1963 * @param cchLine The length of the line. 1964 */ 1965 static int scmSettingsAddPair(PSCMSETTINGS pSettings, const char *pchLine, size_t cchLine) 1966 { 1967 /* 1968 * Split the string. 1969 */ 1970 const char *pchOptions = (const char *)memchr(pchLine, ':', cchLine); 1971 if (!pchOptions) 1972 return VERR_INVALID_PARAMETER; 1973 size_t cchPattern = pchOptions - pchLine - 1; 1974 size_t cchOptions = cchLine - cchPattern - 1 - 1; 1975 pchOptions++; 1976 1977 /* strip spaces everywhere */ 1978 while (cchPattern > 0 && RT_C_IS_SPACE(pchLine[cchPattern - 1])) 1979 cchPattern--; 1980 while (cchPattern > 0 && RT_C_IS_SPACE(*pchLine)) 1981 cchPattern--, pchLine++; 1982 1983 while (cchOptions > 0 && RT_C_IS_SPACE(pchOptions[cchOptions - 1])) 1984 cchOptions--; 1985 while (cchOptions > 0 && RT_C_IS_SPACE(*pchOptions)) 1986 cchOptions--, cchOptions++; 1987 1988 /* Quietly ignore empty patterns and empty options. */ 1989 if (!cchOptions || !cchPattern) 1990 return VINF_SUCCESS; 1991 1992 /* 1993 * Add the pair and verify the option string. 1994 */ 1995 uint32_t iPair = pSettings->cPairs; 1996 if ((iPair % 32) == 0) 1997 { 1998 void *pvNew = RTMemRealloc(pSettings->paPairs, (iPair + 32) * sizeof(pSettings->paPairs[0])); 1999 if (!pvNew) 2000 return VERR_NO_MEMORY; 2001 pSettings->paPairs = (PSCMPATRNOPTPAIR)pvNew; 2002 } 2003 2004 pSettings->paPairs[iPair].pszPattern = RTStrDupN(pchLine, cchPattern); 2005 pSettings->paPairs[iPair].pszOptions = RTStrDupN(pchOptions, cchOptions); 2006 int rc; 2007 if ( pSettings->paPairs[iPair].pszPattern 2008 && pSettings->paPairs[iPair].pszOptions) 2009 rc = scmSettingsBaseVerifyString(pSettings->paPairs[iPair].pszOptions); 2010 else 2011 rc = VERR_NO_MEMORY; 2012 if (RT_SUCCESS(rc)) 2013 pSettings->cPairs = iPair + 1; 2014 else 2015 { 2016 RTStrFree(pSettings->paPairs[iPair].pszPattern); 2017 RTStrFree(pSettings->paPairs[iPair].pszOptions); 2018 } 2019 return rc; 2020 } 2021 2022 /** 2023 * Loads in the settings from @a pszFilename. 2024 * 2025 * @returns IPRT status code. 2026 * @param pSettings Where to load the settings file. 2027 * @param pszFilename The file to load. 2028 */ 2029 static int scmSettingsLoadFile(PSCMSETTINGS pSettings, const char *pszFilename) 2030 { 2031 SCMSTREAM Stream; 2032 int rc = ScmStreamInitForReading(&Stream, pszFilename); 2033 if (RT_FAILURE(rc)) 2034 { 2035 RTMsgError("%s: ScmStreamInitForReading -> %Rrc\n", pszFilename, rc); 2036 return rc; 2037 } 2038 2039 SCMEOL enmEol; 2040 const char *pchLine; 2041 size_t cchLine; 2042 while ((pchLine = ScmStreamGetLine(&Stream, &cchLine, &enmEol)) != NULL) 2043 { 2044 /* Ignore leading spaces. */ 2045 while (cchLine > 0 && RT_C_IS_SPACE(*pchLine)) 2046 pchLine++, cchLine--; 2047 2048 /* Ignore empty lines and comment lines. */ 2049 if (cchLine < 1 || *pchLine == '#') 2050 continue; 2051 2052 /* What kind of line is it? */ 2053 const char *pchColon = (const char *)memchr(pchLine, ':', cchLine); 2054 if (pchColon) 2055 rc = scmSettingsAddPair(pSettings, pchLine, cchLine); 2056 else 2057 rc = scmSettingsBaseParseStringN(&pSettings->Base, pchLine, cchLine); 2058 if (RT_FAILURE(rc)) 2059 { 2060 RTMsgError("%s:%d: %Rrc\n", pszFilename, ScmStreamTellLine(&Stream), rc); 2061 break; 2062 } 2063 } 2064 2065 if (RT_SUCCESS(rc)) 2066 { 2067 rc = ScmStreamGetStatus(&Stream); 2068 if (RT_FAILURE(rc)) 2069 RTMsgError("%s: ScmStreamGetStatus- > %Rrc\n", pszFilename, rc); 2070 } 2071 2072 ScmStreamDelete(&Stream); 2073 return rc; 2074 } 2075 2076 /** 2077 * Parse the specified settings file creating a new settings struct from it. 2078 * 2079 * @returns IPRT status code 2080 * @param ppSettings Where to return the new settings. 2081 * @param pszFilename The file to parse. 2082 * @param pSettingsBase The base settings we inherit from. 2083 */ 2084 static int scmSettingsCreateFromFile(PSCMSETTINGS *ppSettings, const char *pszFilename, PCSCMSETTINGSBASE pSettingsBase) 2085 { 2086 PSCMSETTINGS pSettings; 2087 int rc = scmSettingsCreate(&pSettings, pSettingsBase); 2088 if (RT_SUCCESS(rc)) 2089 { 2090 rc = scmSettingsLoadFile(pSettings, pszFilename); 2091 if (RT_SUCCESS(rc)) 2092 { 2093 *ppSettings = pSettings; 2094 return VINF_SUCCESS; 2095 } 2096 2097 scmSettingsDestroy(pSettings); 2098 } 2099 *ppSettings = NULL; 2100 return rc; 2101 } 2102 2103 2104 /** 2105 * Create an initial settings structure when starting processing a new file or 2106 * directory. 2107 * 2108 * This will look for .scm-settings files from the root and down to the 2109 * specified directory, combining them into the returned settings structure. 2110 * 2111 * @returns IPRT status code. 2112 * @param ppSettings Where to return the pointer to the top stack 2113 * object. 2114 * @param pBaseSettings The base settings we inherit from (globals 2115 * typically). 2116 * @param pszPath The absolute path to the new directory or file. 2117 */ 2118 static int scmSettingsCreateForPath(PSCMSETTINGS *ppSettings, PCSCMSETTINGSBASE pBaseSettings, const char *pszPath) 2119 { 2120 /* 2121 * We'll be working with a stack copy of the path. 2122 */ 2123 char szFile[RTPATH_MAX]; 2124 size_t cchDir = strlen(pszPath); 2125 if (cchDir >= sizeof(szFile) - sizeof(SCM_SETTINGS_FILENAME)) 2126 return VERR_FILENAME_TOO_LONG; 2127 2128 /* 2129 * Create the bottom-most settings. 2130 */ 2131 PSCMSETTINGS pSettings; 2132 int rc = scmSettingsCreate(&pSettings, pBaseSettings); 2133 if (RT_FAILURE(rc)) 2134 return rc; 2135 2136 /* 2137 * Enumerate the path components from the root and down. Load any setting 2138 * files we find. 2139 */ 2140 size_t cComponents = RTPathCountComponents(pszPath); 2141 for (size_t i = 1; i < cComponents; i++) 2142 { 2143 rc = RTPathCopyComponents(szFile, sizeof(szFile), pszPath, i); 2144 if (RT_SUCCESS(rc)) 2145 rc = RTPathAppend(szFile, sizeof(szFile), SCM_SETTINGS_FILENAME); 2146 if (RT_FAILURE(rc)) 2147 break; 2148 if (RTFileExists(szFile)) 2149 { 2150 rc = scmSettingsLoadFile(pSettings, szFile); 2151 if (RT_FAILURE(rc)) 2152 break; 2153 } 2154 } 2155 2156 if (RT_SUCCESS(rc)) 2157 *ppSettings = pSettings; 2158 else 2159 scmSettingsDestroy(pSettings); 2160 return rc; 2161 } 2162 2163 /** 2164 * Pushes a new settings set onto the stack. 2165 * 2166 * @param ppSettingsStack The pointer to the pointer to the top stack 2167 * element. This will be used as input and output. 2168 * @param pSettings The settings to push onto the stack. 2169 */ 2170 static void scmSettingsStackPush(PSCMSETTINGS *ppSettingsStack, PSCMSETTINGS pSettings) 2171 { 2172 PSCMSETTINGS pOld = *ppSettingsStack; 2173 pSettings->pDown = pOld; 2174 pSettings->pUp = NULL; 2175 if (pOld) 2176 pOld->pUp = pSettings; 2177 *ppSettingsStack = pSettings; 2178 } 2179 2180 /** 2181 * Pushes the settings of the specified directory onto the stack. 2182 * 2183 * We will load any .scm-settings in the directory. A stack entry is added even 2184 * if no settings file was found. 2185 * 2186 * @returns IPRT status code. 2187 * @param ppSettingsStack The pointer to the pointer to the top stack 2188 * element. This will be used as input and output. 2189 * @param pszDir The directory to do this for. 2190 */ 2191 static int scmSettingsStackPushDir(PSCMSETTINGS *ppSettingsStack, const char *pszDir) 2192 { 2193 char szFile[RTPATH_MAX]; 2194 int rc = RTPathJoin(szFile, sizeof(szFile), pszDir, SCM_SETTINGS_FILENAME); 2195 if (RT_SUCCESS(rc)) 2196 { 2197 PSCMSETTINGS pSettings; 2198 rc = scmSettingsCreate(&pSettings, &(*ppSettingsStack)->Base); 2199 if (RT_SUCCESS(rc)) 2200 { 2201 if (RTFileExists(szFile)) 2202 rc = scmSettingsLoadFile(pSettings, szFile); 2203 if (RT_SUCCESS(rc)) 2204 { 2205 scmSettingsStackPush(ppSettingsStack, pSettings); 2206 return VINF_SUCCESS; 2207 } 2208 2209 scmSettingsDestroy(pSettings); 2210 } 2211 } 2212 return rc; 2213 } 2214 2215 2216 /** 2217 * Pops a settings set off the stack. 2218 * 2219 * @returns The popped setttings. 2220 * @param ppSettingsStack The pointer to the pointer to the top stack 2221 * element. This will be used as input and output. 2222 */ 2223 static PSCMSETTINGS scmSettingsStackPop(PSCMSETTINGS *ppSettingsStack) 2224 { 2225 PSCMSETTINGS pRet = *ppSettingsStack; 2226 PSCMSETTINGS pNew = pRet ? pRet->pDown : NULL; 2227 *ppSettingsStack = pNew; 2228 if (pNew) 2229 pNew->pUp = NULL; 2230 if (pRet) 2231 { 2232 pRet->pUp = NULL; 2233 pRet->pDown = NULL; 2234 } 2235 return pRet; 2236 } 2237 2238 /** 2239 * Pops and destroys the top entry of the stack. 2240 * 2241 * @param ppSettingsStack The pointer to the pointer to the top stack 2242 * element. This will be used as input and output. 2243 */ 2244 static void scmSettingsStackPopAndDestroy(PSCMSETTINGS *ppSettingsStack) 2245 { 2246 scmSettingsDestroy(scmSettingsStackPop(ppSettingsStack)); 2247 } 2248 2249 /** 2250 * Constructs the base settings for the specified file name. 2251 * 2252 * @returns IPRT status code. 2253 * @param pSettingsStack The top element on the settings stack. 2254 * @param pszFilename The file name. 2255 * @param pszBasename The base name (pointer within @a pszFilename). 2256 * @param cchBasename The length of the base name. (For passing to 2257 * RTStrSimplePatternMultiMatch.) 2258 * @param pBase Base settings to initialize. 2259 */ 2260 static int scmSettingsStackMakeFileBase(PCSCMSETTINGS pSettingsStack, const char *pszFilename, 2261 const char *pszBasename, size_t cchBasename, PSCMSETTINGSBASE pBase) 2262 { 2263 int rc = scmSettingsBaseInitAndCopy(pBase, &pSettingsStack->Base); 2264 if (RT_SUCCESS(rc)) 2265 { 2266 /* find the bottom entry in the stack. */ 2267 PCSCMSETTINGS pCur = pSettingsStack; 2268 while (pCur->pDown) 2269 pCur = pCur->pDown; 2270 2271 /* Work our way up thru the stack and look for matching pairs. */ 2272 while (pCur) 2273 { 2274 size_t const cPairs = pCur->cPairs; 2275 if (cPairs) 2276 { 2277 for (size_t i = 0; i < cPairs; i++) 2278 if ( RTStrSimplePatternMultiMatch(pCur->paPairs[i].pszPattern, RTSTR_MAX, 2279 pszBasename, cchBasename, NULL) 2280 || RTStrSimplePatternMultiMatch(pCur->paPairs[i].pszPattern, RTSTR_MAX, 2281 pszFilename, RTSTR_MAX, NULL)) 2282 { 2283 rc = scmSettingsBaseParseString(pBase, pCur->paPairs[i].pszOptions); 2284 if (RT_FAILURE(rc)) 2285 break; 2286 } 2287 if (RT_FAILURE(rc)) 2288 break; 2289 } 2290 2291 /* advance */ 2292 pCur = pCur->pUp; 2293 } 2294 } 2295 if (RT_FAILURE(rc)) 2296 scmSettingsBaseDelete(pBase); 2297 return rc; 2298 } 2299 1557 2300 1558 2301 /* -=-=-=-=-=- misc -=-=-=-=-=- */ … … 1588 2331 * @param pIn The input stream. 1589 2332 * @param pOut The output stream. 1590 */ 1591 static bool rewrite_StripTrailingBlanks(PSCMSTREAM pIn, PSCMSTREAM pOut) 1592 { 1593 if (!g_fStripTrailingBlanks) 2333 * @param pSettings The settings. 2334 */ 2335 static bool rewrite_StripTrailingBlanks(PSCMSTREAM pIn, PSCMSTREAM pOut, PCSCMSETTINGSBASE pSettings) 2336 { 2337 if (!pSettings->fStripTrailingBlanks) 1594 2338 return false; 1595 2339 … … 1626 2370 * @param pIn The input stream. 1627 2371 * @param pOut The output stream. 1628 */ 1629 static bool rewrite_ExpandTabs(PSCMSTREAM pIn, PSCMSTREAM pOut) 1630 { 1631 if (!g_fConvertTabs) 2372 * @param pSettings The settings. 2373 */ 2374 static bool rewrite_ExpandTabs(PSCMSTREAM pIn, PSCMSTREAM pOut, PCSCMSETTINGSBASE pSettings) 2375 { 2376 if (!pSettings->fConvertTabs) 1632 2377 return false; 1633 2378 1634 bool fModified = false; 1635 SCMEOL enmEol; 1636 size_t cchLine; 1637 const char *pchLine; 2379 size_t const cchTab = pSettings->cchTab; 2380 bool fModified = false; 2381 SCMEOL enmEol; 2382 size_t cchLine; 2383 const char *pchLine; 1638 2384 while ((pchLine = ScmStreamGetLine(pIn, &cchLine, &enmEol)) != NULL) 1639 2385 { … … 1652 2398 ScmStreamWrite(pOut, pchChunk, cchChunk); 1653 2399 1654 size_t cchToTab = g_cchTab - offTab % g_cchTab;2400 size_t cchToTab = cchTab - offTab % cchTab; 1655 2401 ScmStreamWrite(pOut, g_szTabSpaces, cchToTab); 1656 2402 offTab += cchToTab; … … 1682 2428 * @param pIn The input stream. 1683 2429 * @param pOut The output stream. 2430 * @param pSettings The settings. 1684 2431 * @param enmDesiredEol The desired end of line indicator type. 1685 2432 */ 1686 static bool rewrite_ForceEol(PSCMSTREAM pIn, PSCMSTREAM pOut, SCMEOL enmDesiredEol)1687 { 1688 if (! g_fConvertEol)2433 static bool rewrite_ForceEol(PSCMSTREAM pIn, PSCMSTREAM pOut, PCSCMSETTINGSBASE pSettings, SCMEOL enmDesiredEol) 2434 { 2435 if (!pSettings->fConvertEol) 1689 2436 return false; 1690 2437 … … 1716 2463 * @param pIn The input stream. 1717 2464 * @param pOut The output stream. 1718 */ 1719 static bool rewrite_ForceNativeEol(PSCMSTREAM pIn, PSCMSTREAM pOut) 2465 * @param pSettings The settings. 2466 */ 2467 static bool rewrite_ForceNativeEol(PSCMSTREAM pIn, PSCMSTREAM pOut, PCSCMSETTINGSBASE pSettings) 1720 2468 { 1721 2469 #if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2) 1722 return rewrite_ForceEol(pIn, pOut, SCMEOL_CRLF);2470 return rewrite_ForceEol(pIn, pOut, pSettings, SCMEOL_CRLF); 1723 2471 #else 1724 return rewrite_ForceEol(pIn, pOut, SCMEOL_LF);2472 return rewrite_ForceEol(pIn, pOut, pSettings, SCMEOL_LF); 1725 2473 #endif 1726 2474 } … … 1732 2480 * @param pIn The input stream. 1733 2481 * @param pOut The output stream. 1734 */ 1735 static bool rewrite_ForceLF(PSCMSTREAM pIn, PSCMSTREAM pOut) 1736 { 1737 return rewrite_ForceEol(pIn, pOut, SCMEOL_LF); 2482 * @param pSettings The settings. 2483 */ 2484 static bool rewrite_ForceLF(PSCMSTREAM pIn, PSCMSTREAM pOut, PCSCMSETTINGSBASE pSettings) 2485 { 2486 return rewrite_ForceEol(pIn, pOut, pSettings, SCMEOL_LF); 1738 2487 } 1739 2488 … … 1744 2493 * @param pIn The input stream. 1745 2494 * @param pOut The output stream. 1746 */ 1747 static bool rewrite_ForceCRLF(PSCMSTREAM pIn, PSCMSTREAM pOut) 1748 { 1749 return rewrite_ForceEol(pIn, pOut, SCMEOL_CRLF); 2495 * @param pSettings The settings. 2496 */ 2497 static bool rewrite_ForceCRLF(PSCMSTREAM pIn, PSCMSTREAM pOut, PCSCMSETTINGSBASE pSettings) 2498 { 2499 return rewrite_ForceEol(pIn, pOut, pSettings, SCMEOL_CRLF); 1750 2500 } 1751 2501 … … 1757 2507 * @param pIn The input stream. 1758 2508 * @param pOut The output stream. 2509 * @param pSettings The settings. 1759 2510 * 1760 2511 * @remarks ASSUMES trailing white space has been removed already. 1761 2512 */ 1762 static bool rewrite_AdjustTrailingLines(PSCMSTREAM pIn, PSCMSTREAM pOut) 1763 { 1764 if (!g_fStripTrailingLines && !g_fForceTrailingLine && !g_fForceFinalEol) 2513 static bool rewrite_AdjustTrailingLines(PSCMSTREAM pIn, PSCMSTREAM pOut, PCSCMSETTINGSBASE pSettings) 2514 { 2515 if ( !pSettings->fStripTrailingLines 2516 && !pSettings->fForceTrailingLine 2517 && !pSettings->fForceFinalEol) 1765 2518 return false; 1766 2519 … … 1774 2527 size_t cLinesNew = cLines; 1775 2528 1776 if ( g_fStripTrailingLines2529 if ( pSettings->fStripTrailingLines 1777 2530 && ScmStreamIsWhiteLine(pIn, cLinesNew - 1)) 1778 2531 { … … 1782 2535 } 1783 2536 1784 if ( g_fForceTrailingLine2537 if ( pSettings->fForceTrailingLine 1785 2538 && !ScmStreamIsWhiteLine(pIn, cLinesNew - 1)) 1786 2539 cLinesNew++; 1787 2540 1788 bool fFixMissingEol = g_fForceFinalEol2541 bool fFixMissingEol = pSettings->fForceFinalEol 1789 2542 && ScmStreamGetEolByLine(pIn, cLinesNew - 1) == SCMEOL_NONE; 1790 2543 … … 1804 2557 ScmStreamPutLine(pOut, "", 0, ScmStreamGetEol(pIn)); 1805 2558 } 2559 /* Fix missing EOL if required. */ 1806 2560 else if (fFixMissingEol) 1807 2561 { … … 1822 2576 * @param pIn The input stream. 1823 2577 * @param pOut The output stream. 1824 */ 1825 static bool rewrite_Makefile_kup(PSCMSTREAM pIn, PSCMSTREAM pOut) 2578 * @param pSettings The settings. 2579 */ 2580 static bool rewrite_Makefile_kup(PSCMSTREAM pIn, PSCMSTREAM pOut, PCSCMSETTINGSBASE pSettings) 1826 2581 { 1827 2582 /* These files should be zero bytes. */ … … 1838 2593 * @param pIn The input stream. 1839 2594 * @param pOut The output stream. 2595 * @param pSettings The settings. 1840 2596 * 1841 2597 * @todo … … 1845 2601 * - line continuation slashes should only be preceeded by one space. 1846 2602 */ 1847 static bool rewrite_Makefile_kmk(PSCMSTREAM pIn, PSCMSTREAM pOut )2603 static bool rewrite_Makefile_kmk(PSCMSTREAM pIn, PSCMSTREAM pOut, PCSCMSETTINGSBASE pSettings) 1848 2604 { 1849 2605 return false; … … 1856 2612 * @param pIn The input stream. 1857 2613 * @param pOut The output stream. 2614 * @param pSettings The settings. 1858 2615 * 1859 2616 * @todo … … 1879 2636 * - space between functions. 1880 2637 */ 1881 static bool rewrite_C_and_CPP(PSCMSTREAM pIn, PSCMSTREAM pOut) 1882 { 2638 static bool rewrite_C_and_CPP(PSCMSTREAM pIn, PSCMSTREAM pOut, PCSCMSETTINGSBASE pSettings) 2639 { 2640 1883 2641 return false; 1884 2642 } … … 1894 2652 * @param cchBasename The length of the base name. (For passing to 1895 2653 * RTStrSimplePatternMultiMatch.) 1896 */ 1897 static int scmProcessFile(const char *pszFilename, const char *pszBasename, size_t cchBasename) 2654 * @param pBaseSettings The base settings to use. It's OK to modify 2655 * these. 2656 */ 2657 static int scmProcessFileInner(const char *pszFilename, const char *pszBasename, size_t cchBasename, 2658 PSCMSETTINGSBASE pBaseSettings) 1898 2659 { 1899 2660 /* … … 1946 2707 1947 2708 /* 1948 * Create two more streams for output and push the text thru all the 1949 * rewriters, switching the two streams around when something is 1950 * actually rewritten. Stream1 remains unchanged. 2709 * Gather SCM and editor settings from the stream. 1951 2710 */ 1952 SCMSTREAM Stream2; 1953 rc = ScmStreamInitForWriting(&Stream2, &Stream1); 2711 rc = scmSettingsBaseLoadFromDocument(pBaseSettings, &Stream1); 1954 2712 if (RT_SUCCESS(rc)) 1955 2713 { 1956 SCMSTREAM Stream3; 1957 rc = ScmStreamInitForWriting(&Stream3, &Stream1); 2714 ScmStreamRewindForReading(&Stream1); 2715 2716 /* 2717 * Create two more streams for output and push the text thru all the 2718 * rewriters, switching the two streams around when something is 2719 * actually rewritten. Stream1 remains unchanged. 2720 */ 2721 SCMSTREAM Stream2; 2722 rc = ScmStreamInitForWriting(&Stream2, &Stream1); 1958 2723 if (RT_SUCCESS(rc)) 1959 2724 { 1960 bool fModified = false; 1961 PSCMSTREAM pIn = &Stream1; 1962 PSCMSTREAM pOut = &Stream2; 1963 for (size_t iRw = 0; iRw < pCfg->cRewriters; iRw++) 2725 SCMSTREAM Stream3; 2726 rc = ScmStreamInitForWriting(&Stream3, &Stream1); 2727 if (RT_SUCCESS(rc)) 1964 2728 { 1965 bool fRc = pCfg->papfnRewriter[iRw](pIn, pOut); 1966 if (fRc) 2729 bool fModified = false; 2730 PSCMSTREAM pIn = &Stream1; 2731 PSCMSTREAM pOut = &Stream2; 2732 for (size_t iRw = 0; iRw < pCfg->cRewriters; iRw++) 1967 2733 { 1968 PSCMSTREAM pTmp = pOut; 1969 pOut = pIn == &Stream1 ? &Stream3 : pIn; 1970 pIn = pTmp; 1971 fModified = true; 2734 bool fRc = pCfg->papfnRewriter[iRw](pIn, pOut, pBaseSettings); 2735 if (fRc) 2736 { 2737 PSCMSTREAM pTmp = pOut; 2738 pOut = pIn == &Stream1 ? &Stream3 : pIn; 2739 pIn = pTmp; 2740 fModified = true; 2741 } 2742 ScmStreamRewindForReading(pIn); 2743 ScmStreamRewindForWriting(pOut); 1972 2744 } 1973 ScmStreamRewindForReading(pIn); 1974 ScmStreamRewindForWriting(pOut); 1975 } 1976 1977 /* 1978 * If rewritten, write it back to disk. 1979 */ 1980 if (fModified) 1981 { 1982 if (!g_fDryRun) 2745 2746 /* 2747 * If rewritten, write it back to disk. 2748 */ 2749 if (fModified) 1983 2750 { 1984 ScmVerbose(1, "Writing modified file to \"%s%s\"\n", pszFilename, g_pszChangedSuff); 1985 rc = ScmStreamWriteToFile(pIn, "%s%s", pszFilename, g_pszChangedSuff); 1986 if (RT_FAILURE(rc)) 1987 RTMsgError("Error writing '%s%s': %Rrc\n", pszFilename, g_pszChangedSuff, rc); 2751 if (!g_fDryRun) 2752 { 2753 ScmVerbose(1, "Writing modified file to \"%s%s\"\n", pszFilename, g_pszChangedSuff); 2754 rc = ScmStreamWriteToFile(pIn, "%s%s", pszFilename, g_pszChangedSuff); 2755 if (RT_FAILURE(rc)) 2756 RTMsgError("Error writing '%s%s': %Rrc\n", pszFilename, g_pszChangedSuff, rc); 2757 } 2758 else 2759 { 2760 ScmVerbose(1, "Would have modified file \"%s\"\n", pszFilename); 2761 ScmDiffStreams(pszFilename, &Stream1, pIn, g_fDiffIgnoreEol, g_fDiffIgnoreLeadingWS, 2762 g_fDiffIgnoreTrailingWS, g_fDiffSpecialChars, pBaseSettings->cchTab, g_pStdOut); 2763 } 1988 2764 } 1989 2765 else 1990 { 1991 ScmVerbose(1, "Would have modified file \"%s\"\n", pszFilename); 1992 ScmDiffStreams(pszFilename, &Stream1, pIn, g_fDiffIgnoreEol, g_fDiffIgnoreLeadingWS, 1993 g_fDiffIgnoreTrailingWS, g_fDiffSpecialChars, g_pStdOut); 1994 } 2766 ScmVerbose(2, "Unchanged \"%s\"\n", pszFilename); 2767 2768 ScmStreamDelete(&Stream3); 1995 2769 } 1996 2770 else 1997 ScmVerbose(2, "Unchanged \"%s\"\n", pszFilename); 1998 1999 ScmStreamDelete(&Stream3); 2771 RTMsgError("Failed to init stream for writing: %Rrc\n", rc); 2772 ScmStreamDelete(&Stream2); 2000 2773 } 2001 2774 else 2002 2775 RTMsgError("Failed to init stream for writing: %Rrc\n", rc); 2003 ScmStreamDelete(&Stream2);2004 2776 } 2005 2777 else 2006 RTMsgError(" Failed to init stream for writing: %Rrc\n", rc);2778 RTMsgError("scmSettingsBaseLoadFromDocument: %Rrc\n", rc); 2007 2779 } 2008 2780 else … … 2012 2784 return rc; 2013 2785 } 2786 2787 /** 2788 * Processes a file. 2789 * 2790 * This is just a wrapper for scmProcessFileInner for avoid wasting stack in the 2791 * directory recursion method. 2792 * 2793 * @returns IPRT status code. 2794 * @param pszFilename The file name. 2795 * @param pszBasename The base name (pointer within @a pszFilename). 2796 * @param cchBasename The length of the base name. (For passing to 2797 * RTStrSimplePatternMultiMatch.) 2798 * @param pSettingsStack The settings stack (pointer to the top element). 2799 */ 2800 static int scmProcessFile(const char *pszFilename, const char *pszBasename, size_t cchBasename, 2801 PSCMSETTINGS pSettingsStack) 2802 { 2803 SCMSETTINGSBASE Base; 2804 int rc = scmSettingsStackMakeFileBase(pSettingsStack, pszFilename, pszBasename, cchBasename, &Base); 2805 if (RT_SUCCESS(rc)) 2806 { 2807 rc = scmProcessFileInner(pszFilename, pszBasename, cchBasename, &Base); 2808 scmSettingsBaseDelete(&Base); 2809 } 2810 return rc; 2811 } 2812 2014 2813 2015 2814 /** … … 2043 2842 * @param pEntry Directory entry buffer. This is also passed 2044 2843 * along when recursing to save stack space. 2844 * @param pSettingsStack The settings stack (pointer to the top element). 2045 2845 * @param iRecursion The recursion depth. This is used to restrict 2046 2846 * the recursions. 2047 2847 */ 2048 static int scmProcessDirTreeRecursion(char *pszBuf, size_t cchDir, PRTDIRENTRY pEntry, unsigned iRecursion) 2848 static int scmProcessDirTreeRecursion(char *pszBuf, size_t cchDir, PRTDIRENTRY pEntry, 2849 PSCMSETTINGS pSettingsStack, unsigned iRecursion) 2049 2850 { 2050 2851 Assert(cchDir > 1 && pszBuf[cchDir - 1] == '.'); … … 2101 2902 /* Process the file or directory, skip the rest. */ 2102 2903 if (enmType == RTDIRENTRYTYPE_FILE) 2103 rc = scmProcessFile(pszBuf, pEntry->szName, pEntry->cbName );2904 rc = scmProcessFile(pszBuf, pEntry->szName, pEntry->cbName, pSettingsStack); 2104 2905 else if (enmType == RTDIRENTRYTYPE_DIRECTORY) 2105 2906 { … … 2125 2926 ) 2126 2927 { 2127 rc = scmProcessDirTreeRecursion(pszBuf, cchSubDir, pEntry, iRecursion + 1); 2928 rc = scmSettingsStackPushDir(&pSettingsStack, pszBuf); 2929 if (RT_SUCCESS(rc)) 2930 { 2931 rc = scmProcessDirTreeRecursion(pszBuf, cchSubDir, pEntry, pSettingsStack, iRecursion + 1); 2932 scmSettingsStackPopAndDestroy(&pSettingsStack); 2933 } 2128 2934 } 2129 2935 } … … 2143 2949 * a RTPATH_MAX sized buffer. 2144 2950 */ 2145 static int scmProcessDirTree(char *pszDir )2951 static int scmProcessDirTree(char *pszDir, PSCMSETTINGS pSettingsStack) 2146 2952 { 2147 2953 /* … … 2152 2958 { 2153 2959 RTDIRENTRY Entry; 2154 rc = scmProcessDirTreeRecursion(pszDir, strlen(pszDir), &Entry, 0);2960 rc = scmProcessDirTreeRecursion(pszDir, strlen(pszDir), &Entry, pSettingsStack, 0); 2155 2961 } 2156 2962 else … … 2164 2970 * 2165 2971 * @returns IPRT status code 2166 * @param pszSomething What we found in the commad line arguments. 2167 */ 2168 static int scmProcessSomething(const char *pszSomething) 2972 * @param pszSomething What we found in the commad line arguments. 2973 * @param pSettingsStack The settings stack (pointer to the top element). 2974 */ 2975 static int scmProcessSomething(const char *pszSomething, PSCMSETTINGS pSettingsStack) 2169 2976 { 2170 2977 char szBuf[RTPATH_MAX]; … … 2172 2979 if (RT_SUCCESS(rc)) 2173 2980 { 2174 if (RTFileExists(szBuf)) 2981 PSCMSETTINGS pSettings; 2982 rc = scmSettingsCreateForPath(&pSettings, &pSettingsStack->Base, szBuf); 2983 if (RT_SUCCESS(rc)) 2175 2984 { 2176 const char *pszBasename = RTPathFilename(szBuf); 2177 if (pszBasename) 2985 scmSettingsStackPush(&pSettingsStack, pSettings); 2986 2987 if (RTFileExists(szBuf)) 2178 2988 { 2179 size_t cchBasename = strlen(pszBasename); 2180 rc = scmProcessFile(szBuf, pszBasename, cchBasename); 2989 const char *pszBasename = RTPathFilename(szBuf); 2990 if (pszBasename) 2991 { 2992 size_t cchBasename = strlen(pszBasename); 2993 rc = scmProcessFile(szBuf, pszBasename, cchBasename, pSettingsStack); 2994 } 2995 else 2996 { 2997 RTMsgError("RTPathFilename: NULL\n"); 2998 rc = VERR_IS_A_DIRECTORY; 2999 } 2181 3000 } 2182 3001 else 2183 { 2184 RTMsgError("RTPathFilename: NULL\n"); 2185 rc = VERR_IS_A_DIRECTORY; 2186 } 3002 rc = scmProcessDirTree(szBuf, pSettingsStack); 3003 3004 PSCMSETTINGS pPopped = scmSettingsStackPop(&pSettingsStack); 3005 Assert(pPopped == pSettings); 3006 scmSettingsDestroy(pSettings); 2187 3007 } 2188 3008 else 2189 rc = scmProcessDirTree(szBuf);3009 RTMsgError("scmSettingsInitStack: %Rrc\n", rc); 2190 3010 } 2191 3011 else … … 2201 3021 2202 3022 /* 3023 * Init the settings. 3024 */ 3025 PSCMSETTINGS pSettings; 3026 rc = scmSettingsCreate(&pSettings, &g_Defaults); 3027 if (RT_FAILURE(rc)) 3028 { 3029 RTMsgError("scmSettingsCreate: %Rrc\n", rc); 3030 return 1; 3031 } 3032 3033 /* 2203 3034 * Parse arguments and process input in order (because this is the only 2204 3035 * thing that works at the moment). 2205 3036 */ 2206 enum SCMOPT 2207 { 2208 SCMOPT_DIFF_IGNORE_EOL = 10000, 2209 SCMOPT_DIFF_NO_IGNORE_EOL, 2210 SCMOPT_DIFF_IGNORE_SPACE, 2211 SCMOPT_DIFF_NO_IGNORE_SPACE, 2212 SCMOPT_DIFF_IGNORE_LEADING_SPACE, 2213 SCMOPT_DIFF_NO_IGNORE_LEADING_SPACE, 2214 SCMOPT_DIFF_IGNORE_TRAILING_SPACE, 2215 SCMOPT_DIFF_NO_IGNORE_TRAILING_SPACE, 2216 SCMOPT_DIFF_SPECIAL_CHARS, 2217 SCMOPT_DIFF_NO_SPECIAL_CHARS, 2218 SCMOPT_STRIP_TRAILING_LINES, 2219 SCMOPT_NO_STRIP_TRAILING_LINES, 2220 SCMOPT_FORCE_FINAL_EOL, 2221 SCMOPT_NO_FORCE_FINAL_EOL, 2222 SCMOPT_FORCE_TRAILING_LINE, 2223 SCMOPT_NO_FORCE_TRAILING_LINE, 2224 SCMOPT_LAST 2225 }; 2226 static const RTGETOPTDEF s_aOpts[] = 2227 { 2228 { "--strip-trailing-blanks", 'b', RTGETOPT_REQ_NOTHING }, 2229 { "--no-strip-trailing-blanks", 'B', RTGETOPT_REQ_NOTHING }, 2230 { "--convert-tabs", 'c', RTGETOPT_REQ_NOTHING }, 2231 { "--no-convert-tabs", 'C', RTGETOPT_REQ_NOTHING }, 3037 static RTGETOPTDEF s_aOpts[16 + RT_ELEMENTS(g_aScmOpts)] = 3038 { 3039 { "--dry-run", 'd', RTGETOPT_REQ_NOTHING }, 3040 { "--real-run", 'D', RTGETOPT_REQ_NOTHING }, 3041 { "--file-filter", 'f', RTGETOPT_REQ_STRING }, 3042 { "--help", 'h', RTGETOPT_REQ_NOTHING }, 3043 { "--quiet", 'q', RTGETOPT_REQ_NOTHING }, 3044 { "--verbose", 'v', RTGETOPT_REQ_NOTHING }, 3045 { "--version", 'V', RTGETOPT_REQ_NOTHING }, 2232 3046 { "--diff-ignore-eol", SCMOPT_DIFF_IGNORE_EOL, RTGETOPT_REQ_NOTHING }, 2233 3047 { "--diff-no-ignore-eol", SCMOPT_DIFF_NO_IGNORE_EOL, RTGETOPT_REQ_NOTHING }, … … 2240 3054 { "--diff-special-chars", SCMOPT_DIFF_SPECIAL_CHARS, RTGETOPT_REQ_NOTHING }, 2241 3055 { "--diff-no-special-chars", SCMOPT_DIFF_NO_SPECIAL_CHARS, RTGETOPT_REQ_NOTHING }, 2242 { "--dry-run", 'd', RTGETOPT_REQ_NOTHING },2243 { "--real-run", 'D', RTGETOPT_REQ_NOTHING },2244 { "--strip-trailing-lines", SCMOPT_STRIP_TRAILING_LINES, RTGETOPT_REQ_NOTHING },2245 { "--strip-no-trailing-lines", SCMOPT_NO_STRIP_TRAILING_LINES, RTGETOPT_REQ_NOTHING },2246 { "--force-final-eol", SCMOPT_FORCE_FINAL_EOL, RTGETOPT_REQ_NOTHING },2247 { "--no-force-final-eol", SCMOPT_NO_FORCE_FINAL_EOL, RTGETOPT_REQ_NOTHING },2248 { "--force-trailing-line", SCMOPT_FORCE_TRAILING_LINE, RTGETOPT_REQ_NOTHING },2249 { "--no-force-trailing-line", SCMOPT_NO_FORCE_TRAILING_LINE, RTGETOPT_REQ_NOTHING },2250 { "--convert-eol", 'e', RTGETOPT_REQ_NOTHING },2251 { "--no-convert-eol", 'E', RTGETOPT_REQ_NOTHING },2252 { "--file-filter", 'f', RTGETOPT_REQ_STRING },2253 { "--help", 'h', RTGETOPT_REQ_NOTHING },2254 { "--quiet", 'q', RTGETOPT_REQ_NOTHING },2255 { "--tab-size", 't', RTGETOPT_REQ_UINT8 },2256 { "--verbose", 'v', RTGETOPT_REQ_NOTHING },2257 3056 }; 3057 memcpy(&s_aOpts[RT_ELEMENTS(s_aOpts) - RT_ELEMENTS(g_aScmOpts)], &g_aScmOpts[0], sizeof(g_aScmOpts)); 2258 3058 2259 3059 RTGETOPTUNION ValueUnion; … … 2267 3067 switch (rc) 2268 3068 { 2269 case 'b':2270 g_fStripTrailingBlanks = true;2271 break;2272 2273 case 'B':2274 g_fStripTrailingBlanks = false;2275 break;2276 2277 case 'c':2278 g_fConvertTabs = true;2279 break;2280 2281 case 'C':2282 g_fConvertTabs = false;2283 break;2284 2285 3069 case 'd': 2286 3070 g_fDryRun = true; … … 2289 3073 case 'D': 2290 3074 g_fDryRun = false; 2291 break;2292 2293 case 'e':2294 g_fConvertEol = true;2295 break;2296 2297 case 'E':2298 g_fConvertEol = false;2299 3075 break; 2300 3076 … … 2322 3098 break; 2323 3099 2324 case 't':2325 if ( ValueUnion.u8 < 12326 || ValueUnion.u8 >= RT_ELEMENTS(g_szTabSpaces))2327 {2328 RTMsgError("Invalid tab size: %u - must be in {1..%u}\n",2329 ValueUnion.u8, RT_ELEMENTS(g_szTabSpaces) - 1);2330 return 2;2331 }2332 g_cchTab = ValueUnion.u8;2333 break;2334 2335 3100 case 'v': 2336 3101 g_iVerbosity++; 2337 3102 break; 3103 3104 case 'V': 3105 { 3106 /* The following is assuming that svn does it's job here. */ 3107 static const char s_szRev[] = "$Revision$"; 3108 const char *psz = RTStrStripL(strchr(s_szRev, ' ')); 3109 RTPrintf("r%.*s\n", strchr(psz, ' ') - psz, psz); 3110 return 0; 3111 } 2338 3112 2339 3113 case SCMOPT_DIFF_IGNORE_EOL: … … 2370 3144 case SCMOPT_DIFF_NO_SPECIAL_CHARS: 2371 3145 g_fDiffSpecialChars = false; 2372 break;2373 2374 case SCMOPT_STRIP_TRAILING_LINES:2375 g_fStripTrailingLines = true;2376 break;2377 case SCMOPT_NO_STRIP_TRAILING_LINES:2378 g_fStripTrailingLines = false;2379 break;2380 2381 case SCMOPT_FORCE_FINAL_EOL:2382 g_fForceFinalEol = true;2383 break;2384 case SCMOPT_NO_FORCE_FINAL_EOL:2385 g_fForceFinalEol = false;2386 break;2387 2388 case SCMOPT_FORCE_TRAILING_LINE:2389 g_fForceTrailingLine = true;2390 break;2391 case SCMOPT_NO_FORCE_TRAILING_LINE:2392 g_fForceTrailingLine = false;2393 3146 break; 2394 3147 … … 2412 3165 cProcessed++; 2413 3166 } 2414 rc = scmProcessSomething(ValueUnion.psz );3167 rc = scmProcessSomething(ValueUnion.psz, pSettings); 2415 3168 if (RT_FAILURE(rc)) 2416 3169 return rc; … … 2419 3172 2420 3173 default: 3174 { 3175 int rc2 = scmSettingsBaseHandleOpt(&pSettings->Base, rc, &ValueUnion); 3176 if (RT_SUCCESS(rc2)) 3177 break; 3178 if (rc2 != VERR_GETOPT_UNKNOWN_OPTION) 3179 return 2; 2421 3180 return RTGetOptPrintError(rc, &ValueUnion); 3181 } 2422 3182 } 2423 3183 } 2424 3184 3185 scmSettingsDestroy(pSettings); 2425 3186 return 0; 2426 3187 }
Note:
See TracChangeset
for help on using the changeset viewer.