PageRenderTime 41ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/uppdev/plugin/astyle/ASEnhancer.cpp

http://upp-mirror.googlecode.com/
C++ | 489 lines | 328 code | 60 blank | 101 comment | 98 complexity | 0f3d42e6f8194b08e6fef4a2ba81517e MD5 | raw file
Possible License(s): LGPL-2.1, GPL-2.0, BSD-2-Clause, BSD-3-Clause, LGPL-3.0, GPL-3.0
  1. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2. *
  3. * ASEnhancer.cpp
  4. *
  5. * This file is a part of "Artistic Style" - an indentation and
  6. * reformatting tool for C, C++, C# and Java source files.
  7. * http://astyle.sourceforge.net
  8. *
  9. * The "Artistic Style" project, including all files needed to
  10. * compile it, is free software; you can redistribute it and/or
  11. * modify it under the terms of the GNU Lesser General Public
  12. * License as published by the Free Software Foundation; either
  13. * version 2.1 of the License, or (at your option) any later
  14. * version.
  15. *
  16. * This program is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. * GNU Lesser General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU Lesser General Public
  22. * License along with this project; if not, write to the
  23. * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  24. * Boston, MA 02110-1301, USA.
  25. *
  26. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  27. */
  28. /*
  29. 2008-01-26 Patches by Massimo Del Fedele :
  30. - modified sources to use Ultimate++ containers instead std:: ones
  31. - fixed memory leaks based on bug report 1804791 submitted by Eran Ifrah
  32. - modified to work with unicode
  33. */
  34. // can trace only if NDEBUG is not defined
  35. #ifndef NDEBUG
  36. // #define TRACEswitch
  37. // #define TRACEcase
  38. // #define TRACEmisc
  39. #endif
  40. #include "astyle.h"
  41. #include <iostream>
  42. #include <fstream>
  43. #include <sstream>
  44. #ifdef TRACEswitch
  45. #define TRswitch(a,b) *traceOut << lineNumber << a << b << endl;
  46. #else
  47. #define TRswitch(a,b) ((void)0)
  48. #endif // TRACEswitch
  49. #ifdef TRACEcase
  50. #define TRcase(a,b) *traceOut << lineNumber << a << b << endl;
  51. #else
  52. #define TRcase(a,b) ((void)0)
  53. #endif // TRACEcase
  54. #ifdef TRACEmisc
  55. #define TRmisc(a) *traceOut << lineNumber << a << endl;
  56. #else
  57. #define TRmisc(a) ((void)0)
  58. #endif // TRACEmisc
  59. namespace astyle
  60. {
  61. // ---------------------------- functions for ASEnhancer Class -------------------------------------
  62. /**
  63. * ASEnhancer constructor
  64. */
  65. ASEnhancer::ASEnhancer()
  66. {
  67. // variables are initialized by init()
  68. traceOut = new StringStream;
  69. }
  70. /**
  71. * Destructor of ASEnhancer
  72. * Display the TRACE entries.
  73. */
  74. ASEnhancer::~ASEnhancer()
  75. {
  76. #if defined(TRACEswitch) || defined(TRACEcase) || defined(TRACEmisc)
  77. WString line;
  78. WString msg = "TRACE Entries\n\n";
  79. char countLine[50];
  80. int count = 0;
  81. while (getline(*traceOut, line))
  82. {
  83. msg += line + '\n';
  84. count++;
  85. }
  86. sprintf(countLine, "\n%d Entries", count);
  87. msg += countLine;
  88. // write a text file to "My Documents" (Windows)
  89. char filename [_MAX_PATH + _MAX_FNAME + _MAX_EXT + 1]; // full path and filename
  90. strcpy(filename, getenv("USERPROFILE"));
  91. strcat(filename, "\\My Documents\\tracee.txt");
  92. ofstream outfile(filename);
  93. outfile << msg;
  94. outfile.close();
  95. #endif
  96. delete traceOut;
  97. }
  98. /**
  99. * initialize the ASEnhancer.
  100. *
  101. * init() is called each time an ASFormatter object is initialized.
  102. */
  103. void ASEnhancer::init(int _indentLength,
  104. WString _indentString,
  105. bool _isCStyle,
  106. bool _isJavaStyle,
  107. bool _isSharpStyle,
  108. bool _caseIndent,
  109. bool _emptyLineFill)
  110. {
  111. // formatting variables from ASFormatter and ASBeautifier
  112. indentLength = _indentLength;
  113. if (_indentString[0] == '\t')
  114. useTabs = true;
  115. else
  116. useTabs = false;
  117. isCStyle = _isCStyle;
  118. isJavaStyle = _isJavaStyle;
  119. isSharpStyle = _isSharpStyle;
  120. caseIndent = _caseIndent;
  121. emptyLineFill = _emptyLineFill;
  122. // unindent variables
  123. lineNumber = 0;
  124. bracketCount = 0;
  125. isInComment = false;
  126. isInQuote = false;
  127. switchDepth = 0;
  128. lookingForCaseBracket = false;
  129. unindentNextLine = false;
  130. #if defined(TRACEswitch) || defined(TRACEcase) || defined(TRACEmisc)
  131. *traceOut << "New file -------------" << endl;
  132. #endif
  133. }
  134. /**
  135. * additional formatting for line of source code.
  136. * every line of source code in a source code file should be sent
  137. * one after the other to this function.
  138. * indents event tables
  139. * unindents the case blocks
  140. *
  141. * @param line the original formatted line will be updated if necessary.
  142. */
  143. void ASEnhancer::enhance(WString &line)
  144. {
  145. static Array<switchVariables> swVector; // stack Vector of switch variables
  146. static switchVariables sw; // switch variables struct
  147. static bool nextLineIsEventTable; // begin event table is reached
  148. static bool isInEventTable; // need to indent an event table
  149. bool isSpecialChar = false;
  150. int lineLength; // length of the line being parsed
  151. lineNumber++;
  152. lineLength = line.GetCount();
  153. // check for beginning of event table
  154. if (nextLineIsEventTable)
  155. {
  156. isInEventTable = true;
  157. nextLineIsEventTable = false;
  158. }
  159. if (lineLength == 0
  160. && ! isInEventTable
  161. && ! emptyLineFill)
  162. return;
  163. // test for unindent on attached brackets
  164. if (unindentNextLine)
  165. {
  166. sw.unindentDepth++;
  167. sw.unindentCase = true;
  168. unindentNextLine = false;
  169. TRcase(" unindent case ", sw.unindentDepth);
  170. }
  171. // parse characters in the current line.
  172. for (int i = 0; i < lineLength; i++)
  173. {
  174. char ch = line[i];
  175. // bypass whitespace
  176. if (isWhiteSpaceX(ch))
  177. continue;
  178. // handle special characters (i.e. backslash+character such as \n, \t, ...)
  179. if (isSpecialChar)
  180. {
  181. isSpecialChar = false;
  182. continue;
  183. }
  184. if (!(isInComment) && line.Mid(i, 2) == WString("\\\\"))
  185. {
  186. i++;
  187. continue;
  188. }
  189. if (!(isInComment) && ch == '\\')
  190. {
  191. isSpecialChar = true;
  192. continue;
  193. }
  194. // handle quotes (such as 'x' and "Hello Dolly")
  195. if (!(isInComment) && (ch == '"' || ch == '\''))
  196. if (!isInQuote)
  197. {
  198. quoteChar = ch;
  199. isInQuote = true;
  200. }
  201. else if (quoteChar == ch)
  202. {
  203. isInQuote = false;
  204. continue;
  205. }
  206. if (isInQuote)
  207. continue;
  208. // handle comments
  209. if (!(isInComment) && line.Mid(i, 2) == WString("//"))
  210. {
  211. // check for windows line markers
  212. //@@ CHECK !!!! if (line.Mid(i + 2, 1) > WString("\xf0"))
  213. if (line.Mid(i + 2, 1) > WString("\xf0") && line.Mid(i + 2, 1) > WString("\xff"))
  214. lineNumber--;
  215. break; // finished with the line
  216. }
  217. else if (!(isInComment) && line.Mid(i, 2) == WString("/*"))
  218. {
  219. isInComment = true;
  220. i++;
  221. continue;
  222. }
  223. else if ((isInComment) && line.Mid(i, 2) == WString("*/"))
  224. {
  225. isInComment = false;
  226. i++;
  227. continue;
  228. }
  229. if (isInComment)
  230. continue;
  231. // if we have reached this far then we are NOT in a comment or String of special characters
  232. if (line[i] == '{') // if open bracket
  233. bracketCount++;
  234. if (line[i] == '}') // if close bracket
  235. bracketCount--;
  236. // ---------------- process event tables --------------------------------------
  237. // check for event table begin
  238. if (findKeyword(line, i, "BEGIN_EVENT_TABLE")
  239. || findKeyword(line, i, "BEGIN_MESSAGE_MAP"))
  240. nextLineIsEventTable = true;
  241. // check for event table end
  242. if (findKeyword(line, i, "END_EVENT_TABLE")
  243. || findKeyword(line, i, "END_MESSAGE_MAP"))
  244. isInEventTable = false;
  245. // ---------------- process switch statements ---------------------------------
  246. if (findKeyword(line, i, "switch")) // if switch statement
  247. {
  248. switchDepth++; // bump switch depth
  249. TRswitch(" switch ", switchDepth);
  250. swVector.push_back(sw); // save current variables
  251. sw.switchBracketCount = 0;
  252. sw.unindentCase = false; // don't clear case until end of switch
  253. i += 5; // bypass switch statement
  254. continue;
  255. }
  256. // just want switch statements from this point
  257. if (caseIndent || switchDepth == 0) // from here just want switch statements
  258. continue; // get next char
  259. if (line[i] == '{') // if open bracket
  260. {
  261. sw.switchBracketCount++;
  262. if (lookingForCaseBracket) // if 1st after case statement
  263. {
  264. sw.unindentCase = true; // unindenting this case
  265. sw.unindentDepth++; // bump depth
  266. lookingForCaseBracket = false; // not looking now
  267. TRcase(" unindent case ", sw.unindentDepth);
  268. }
  269. continue;
  270. }
  271. lookingForCaseBracket = false; // no opening bracket, don't indent
  272. if (line[i] == '}') // if close bracket
  273. {
  274. sw.switchBracketCount--;
  275. if (sw.switchBracketCount == 0) // if end of switch statement
  276. {
  277. TRswitch(" endsw ", switchDepth);
  278. switchDepth--; // one less switch
  279. sw = swVector.back(); // restore sw struct
  280. swVector.pop_back(); // remove last entry from stack
  281. }
  282. continue;
  283. }
  284. // look for case or default header
  285. if (findKeyword(line, i, "case") || findKeyword(line, i, "default"))
  286. {
  287. if (sw.unindentCase) // if unindented last case
  288. {
  289. sw.unindentCase = false; // stop unindenting previous case
  290. sw.unindentDepth--; // reduce depth
  291. }
  292. for (; i < lineLength; i++) // bypass colon
  293. {
  294. if (line[i] == ':')
  295. if ((i + 1 < lineLength) && (line[i + 1] == ':'))
  296. i++; // bypass scope resolution operator
  297. else
  298. break;
  299. }
  300. i++;
  301. for (; i < lineLength; i++) // bypass whitespace
  302. {
  303. if (!(isWhiteSpaceX(line[i])))
  304. break;
  305. }
  306. if (i < lineLength) // check for bracket
  307. {
  308. if (line[i] == '{') // if bracket found
  309. {
  310. sw.switchBracketCount++;
  311. unindentNextLine = true; // start unindenting on next line
  312. continue;
  313. }
  314. }
  315. lookingForCaseBracket = true; // bracket must be on next line
  316. i--; // need to check for comments
  317. continue;
  318. }
  319. } // end of for loop
  320. if (isInEventTable) // if need to indent
  321. indentLine(line, 1); // do it
  322. if (sw.unindentDepth > 0) // if need to unindent
  323. unindentLine(line, sw.unindentDepth); // do it
  324. }
  325. /**
  326. * indent a line by a given number of tabsets
  327. * by inserting leading whitespace to the line argument.
  328. *
  329. * @param line a pointer to the line to indent.
  330. * @param unindent the number of tabsets to insert.
  331. * @return the number of characters inserted.
  332. */
  333. int ASEnhancer::indentLine(WString &line, const int indent) const
  334. {
  335. if (line.GetCount() == 0
  336. && ! emptyLineFill)
  337. return 0;
  338. int charsToInsert; // number of chars to insert
  339. if (useTabs) // if formatted with tabs
  340. {
  341. charsToInsert = indent; // tabs to insert
  342. line.Insert(0, WString('\t', charsToInsert)); // insert the tabs
  343. }
  344. else
  345. {
  346. charsToInsert = indent * indentLength; // compute chars to insert
  347. line.Insert(0, WString('\t', charsToInsert)); // insert the tabs
  348. }
  349. return charsToInsert;
  350. }
  351. /**
  352. * unindent a line by a given number of tabsets
  353. * by erasing the leading whitespace from the line argument.
  354. *
  355. * @param line a pointer to the line to unindent.
  356. * @param unindent the number of tabsets to erase.
  357. * @return the number of characters erased.
  358. */
  359. int ASEnhancer::unindentLine(WString &line, const int unindent) const
  360. {
  361. int whitespace = ASString_Find_First_Not_Of(line, " \t");
  362. if (whitespace == -1) // if line is blank
  363. whitespace = line.GetCount(); // must remove padding, if any
  364. if (whitespace == 0)
  365. return 0;
  366. int charsToErase; // number of chars to erase
  367. if (useTabs) // if formatted with tabs
  368. {
  369. charsToErase = unindent; // tabs to erase
  370. if (charsToErase <= whitespace) // if there is enough whitespace
  371. line.Remove(0, charsToErase); // erase the tabs
  372. else
  373. charsToErase = 0;
  374. }
  375. else
  376. {
  377. charsToErase = unindent * indentLength; // compute chars to erase
  378. if (charsToErase <= whitespace) // if there is enough whitespace
  379. line.Remove(0, charsToErase); // erase the spaces
  380. else
  381. charsToErase = 0;
  382. }
  383. return charsToErase;
  384. }
  385. /**
  386. * check if a specific line position contains a keyword.
  387. *
  388. * @return true if the word was found. false if the word was not found.
  389. */
  390. bool ASEnhancer::findKeyword(const WString &line, int i, const char *keyword) const
  391. {
  392. if (line.Mid(i, strlen(keyword)) == WString(keyword))
  393. {
  394. // check that this is a header and not a part of a longer word
  395. // (e.g. not at its begining, not at its middle...)
  396. int lineLength = line.GetCount();
  397. int wordEnd = i + strlen(keyword);
  398. char startCh = keyword[0]; // first char of header
  399. char endCh = 0; // char just after header
  400. char prevCh = 0; // char just before header
  401. if (wordEnd < lineLength)
  402. {
  403. endCh = line[wordEnd];
  404. }
  405. if (i > 0)
  406. {
  407. prevCh = line[i-1];
  408. }
  409. if (prevCh != 0
  410. && isLegalNameCharX(startCh)
  411. && isLegalNameCharX(prevCh))
  412. {
  413. return false;
  414. }
  415. else if (wordEnd >= lineLength
  416. || !isLegalNameCharX(startCh)
  417. || !isLegalNameCharX(endCh))
  418. {
  419. return true;
  420. }
  421. else
  422. {
  423. return false;
  424. }
  425. }
  426. return false;
  427. }
  428. } // end namespace astyle