summaryrefslogtreecommitdiffstats
path: root/lib/astyle/ASEnhancer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/astyle/ASEnhancer.cpp')
-rw-r--r--lib/astyle/ASEnhancer.cpp483
1 files changed, 483 insertions, 0 deletions
diff --git a/lib/astyle/ASEnhancer.cpp b/lib/astyle/ASEnhancer.cpp
new file mode 100644
index 00000000..6fea5970
--- /dev/null
+++ b/lib/astyle/ASEnhancer.cpp
@@ -0,0 +1,483 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ * ASEnhancer.cpp
+ *
+ * This file is a part of "Artistic Style" - an indentation and
+ * reformatting tool for C, C++, C# and Java source files.
+ * http://astyle.sourceforge.net
+ *
+ * The "Artistic Style" project, including all files needed to
+ * compile it, is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this project; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ */
+
+// can trace only if NDEBUG is not defined
+#ifndef NDEBUG
+// #define TRACEswitch
+// #define TRACEcase
+// #define TRACEmisc
+#endif
+
+#include "astyle.h"
+
+#include <iostream>
+#include <fstream>
+#include <sstream>
+
+#ifdef TRACEswitch
+#define TRswitch(a,b) *traceOut << lineNumber << a << b << endl;
+#else
+#define TRswitch(a,b) ((void)0)
+#endif // TRACEswitch
+#ifdef TRACEcase
+#define TRcase(a,b) *traceOut << lineNumber << a << b << endl;
+#else
+#define TRcase(a,b) ((void)0)
+#endif // TRACEcase
+#ifdef TRACEmisc
+#define TRmisc(a) *traceOut << lineNumber << a << endl;
+#else
+#define TRmisc(a) ((void)0)
+#endif // TRACEmisc
+
+
+namespace astyle
+{
+
+// ---------------------------- functions for ASEnhancer Class -------------------------------------
+
+/**
+ * ASEnhancer constructor
+ */
+ASEnhancer::ASEnhancer()
+{
+ // variables are initialized by init()
+ traceOut = new stringstream;
+}
+
+/**
+ * Destructor of ASEnhancer
+ * Display the TRACE entries.
+ */
+ASEnhancer::~ASEnhancer()
+{
+#if defined(TRACEswitch) || defined(TRACEcase) || defined(TRACEmisc)
+ string line;
+ string msg = "TRACE Entries\n\n";
+ char countLine[50];
+ int count = 0;
+
+ while (getline(*traceOut, line))
+ {
+ msg += line + '\n';
+ count++;
+ }
+ sprintf(countLine, "\n%d Entries", count);
+ msg += countLine;
+ // write a text file to "My Documents" (Windows)
+ char filename [_MAX_PATH + _MAX_FNAME + _MAX_EXT + 1]; // full path and filename
+ strcpy(filename, getenv("USERPROFILE"));
+ strcat(filename, "\\My Documents\\tracee.txt");
+ ofstream outfile(filename);
+ outfile << msg;
+ outfile.close();
+#endif
+ delete traceOut;
+}
+
+/**
+ * initialize the ASEnhancer.
+ *
+ * init() is called each time an ASFormatter object is initialized.
+ */
+void ASEnhancer::init(int _indentLength,
+ string _indentString,
+ bool _isCStyle,
+ bool _isJavaStyle,
+ bool _isSharpStyle,
+ bool _caseIndent,
+ bool _emptyLineFill)
+{
+ // formatting variables from ASFormatter and ASBeautifier
+ indentLength = _indentLength;
+ if (_indentString.compare(0, 1, "\t") == 0)
+ useTabs = true;
+ else
+ useTabs = false;
+ isCStyle = _isCStyle;
+ isJavaStyle = _isJavaStyle;
+ isSharpStyle = _isSharpStyle;
+ caseIndent = _caseIndent;
+ emptyLineFill = _emptyLineFill;
+
+ // unindent variables
+ lineNumber = 0;
+ bracketCount = 0;
+ isInComment = false;
+ isInQuote = false;
+ switchDepth = 0;
+ lookingForCaseBracket = false;
+ unindentNextLine = false;
+
+#if defined(TRACEswitch) || defined(TRACEcase) || defined(TRACEmisc)
+ *traceOut << "New file -------------" << endl;
+#endif
+}
+
+/**
+ * additional formatting for line of source code.
+ * every line of source code in a source code file should be sent
+ * one after the other to this function.
+ * indents event tables
+ * unindents the case blocks
+ *
+ * @param line the original formatted line will be updated if necessary.
+ */
+void ASEnhancer::enhance(string &line)
+{
+ static vector<switchVariables> swVector; // stack vector of switch variables
+ static switchVariables sw; // switch variables struct
+
+ static bool nextLineIsEventTable; // begin event table is reached
+ static bool isInEventTable; // need to indent an event table
+
+ bool isSpecialChar = false;
+ size_t lineLength; // length of the line being parsed
+
+ lineNumber++;
+ lineLength = line.length();
+
+ // check for beginning of event table
+ if (nextLineIsEventTable)
+ {
+ isInEventTable = true;
+ nextLineIsEventTable = false;
+ }
+
+ if (lineLength == 0
+ && ! isInEventTable
+ && ! emptyLineFill)
+ return;
+
+ // test for unindent on attached brackets
+ if (unindentNextLine)
+ {
+ sw.unindentDepth++;
+ sw.unindentCase = true;
+ unindentNextLine = false;
+ TRcase(" unindent case ", sw.unindentDepth);
+ }
+
+ // parse characters in the current line.
+
+ for (size_t i = 0; i < lineLength; i++)
+ {
+ char ch = line[i];
+
+ // bypass whitespace
+ if (isWhiteSpaceX(ch))
+ continue;
+
+ // handle special characters (i.e. backslash+character such as \n, \t, ...)
+ if (isSpecialChar)
+ {
+ isSpecialChar = false;
+ continue;
+ }
+ if (!(isInComment) && line.compare(i, 2, "\\\\") == 0)
+ {
+ i++;
+ continue;
+ }
+ if (!(isInComment) && ch == '\\')
+ {
+ isSpecialChar = true;
+ continue;
+ }
+
+ // handle quotes (such as 'x' and "Hello Dolly")
+ if (!(isInComment) && (ch == '"' || ch == '\''))
+ if (!isInQuote)
+ {
+ quoteChar = ch;
+ isInQuote = true;
+ }
+ else if (quoteChar == ch)
+ {
+ isInQuote = false;
+ continue;
+ }
+
+ if (isInQuote)
+ continue;
+
+ // handle comments
+
+ if (!(isInComment) && line.compare(i, 2, "//") == 0)
+ {
+ // check for windows line markers
+ if (line.compare(i + 2, 1, "\xf0") > 0)
+ lineNumber--;
+ break; // finished with the line
+ }
+ else if (!(isInComment) && line.compare(i, 2, "/*") == 0)
+ {
+ isInComment = true;
+ i++;
+ continue;
+ }
+ else if ((isInComment) && line.compare(i, 2, "*/") == 0)
+ {
+ isInComment = false;
+ i++;
+ continue;
+ }
+
+ if (isInComment)
+ continue;
+
+ // if we have reached this far then we are NOT in a comment or string of special characters
+
+ if (line[i] == '{') // if open bracket
+ bracketCount++;
+
+ if (line[i] == '}') // if close bracket
+ bracketCount--;
+
+ // ---------------- process event tables --------------------------------------
+
+ // check for event table begin
+ if (findKeyword(line, i, "BEGIN_EVENT_TABLE")
+ || findKeyword(line, i, "BEGIN_MESSAGE_MAP"))
+ nextLineIsEventTable = true;
+
+ // check for event table end
+ if (findKeyword(line, i, "END_EVENT_TABLE")
+ || findKeyword(line, i, "END_MESSAGE_MAP"))
+ isInEventTable = false;
+
+ // ---------------- process switch statements ---------------------------------
+
+ if (findKeyword(line, i, "switch")) // if switch statement
+ {
+ switchDepth++; // bump switch depth
+ TRswitch(" switch ", switchDepth);
+ swVector.push_back(sw); // save current variables
+ sw.switchBracketCount = 0;
+ sw.unindentCase = false; // don't clear case until end of switch
+ i += 5; // bypass switch statement
+ continue;
+ }
+
+ // just want switch statements from this point
+
+ if (caseIndent || switchDepth == 0) // from here just want switch statements
+ continue; // get next char
+
+ if (line[i] == '{') // if open bracket
+ {
+ sw.switchBracketCount++;
+ if (lookingForCaseBracket) // if 1st after case statement
+ {
+ sw.unindentCase = true; // unindenting this case
+ sw.unindentDepth++; // bump depth
+ lookingForCaseBracket = false; // not looking now
+ TRcase(" unindent case ", sw.unindentDepth);
+ }
+ continue;
+ }
+
+ lookingForCaseBracket = false; // no opening bracket, don't indent
+
+ if (line[i] == '}') // if close bracket
+ {
+ sw.switchBracketCount--;
+ if (sw.switchBracketCount == 0) // if end of switch statement
+ {
+ TRswitch(" endsw ", switchDepth);
+ switchDepth--; // one less switch
+ sw = swVector.back(); // restore sw struct
+ swVector.pop_back(); // remove last entry from stack
+ }
+ continue;
+ }
+
+ // look for case or default header
+
+ if (findKeyword(line, i, "case") || findKeyword(line, i, "default"))
+ {
+ if (sw.unindentCase) // if unindented last case
+ {
+ sw.unindentCase = false; // stop unindenting previous case
+ sw.unindentDepth--; // reduce depth
+ }
+ for (; i < lineLength; i++) // bypass colon
+ {
+ if (line[i] == ':')
+ if ((i + 1 < lineLength) && (line[i + 1] == ':'))
+ i++; // bypass scope resolution operator
+ else
+ break;
+ }
+ i++;
+ for (; i < lineLength; i++) // bypass whitespace
+ {
+ if (!(isWhiteSpaceX(line[i])))
+ break;
+ }
+ if (i < lineLength) // check for bracket
+ {
+ if (line[i] == '{') // if bracket found
+ {
+ sw.switchBracketCount++;
+ unindentNextLine = true; // start unindenting on next line
+ continue;
+ }
+ }
+ lookingForCaseBracket = true; // bracket must be on next line
+ i--; // need to check for comments
+ continue;
+ }
+ } // end of for loop
+
+ if (isInEventTable) // if need to indent
+ indentLine(line, 1); // do it
+
+ if (sw.unindentDepth > 0) // if need to unindent
+ unindentLine(line, sw.unindentDepth); // do it
+}
+
+/**
+ * indent a line by a given number of tabsets
+ * by inserting leading whitespace to the line argument.
+ *
+ * @param line a pointer to the line to indent.
+ * @param unindent the number of tabsets to insert.
+ * @return the number of characters inserted.
+ */
+int ASEnhancer::indentLine(string &line, const int indent) const
+{
+ if (line.length() == 0
+ && ! emptyLineFill)
+ return 0;
+
+ size_t charsToInsert; // number of chars to insert
+
+ if (useTabs) // if formatted with tabs
+ {
+ charsToInsert = indent; // tabs to insert
+ line.insert((size_t) 0, charsToInsert, '\t'); // insert the tabs
+ }
+ else
+ {
+ charsToInsert = indent * indentLength; // compute chars to insert
+ line.insert((size_t)0, charsToInsert, ' '); // insert the spaces
+ }
+
+ return charsToInsert;
+}
+
+/**
+ * unindent a line by a given number of tabsets
+ * by erasing the leading whitespace from the line argument.
+ *
+ * @param line a pointer to the line to unindent.
+ * @param unindent the number of tabsets to erase.
+ * @return the number of characters erased.
+ */
+int ASEnhancer::unindentLine(string &line, const int unindent) const
+{
+ size_t whitespace = line.find_first_not_of(" \t");
+
+ if (whitespace == string::npos) // if line is blank
+ whitespace = line.length(); // must remove padding, if any
+
+ if (whitespace == 0)
+ return 0;
+
+ size_t charsToErase; // number of chars to erase
+
+ if (useTabs) // if formatted with tabs
+ {
+ charsToErase = unindent; // tabs to erase
+ if (charsToErase <= whitespace) // if there is enough whitespace
+ line.erase(0, charsToErase); // erase the tabs
+ else
+ charsToErase = 0;
+ }
+ else
+ {
+ charsToErase = unindent * indentLength; // compute chars to erase
+ if (charsToErase <= whitespace) // if there is enough whitespace
+ line.erase(0, charsToErase); // erase the spaces
+ else
+ charsToErase = 0;
+ }
+
+ return charsToErase;
+}
+
+/**
+ * check if a specific line position contains a keyword.
+ *
+ * @return true if the word was found. false if the word was not found.
+ */
+bool ASEnhancer::findKeyword(const string &line, int i, const char *keyword) const
+{
+ if (line.compare(i, strlen(keyword), keyword) == 0)
+ {
+ // check that this is a header and not a part of a longer word
+ // (e.g. not at its begining, not at its middle...)
+
+ int lineLength = line.length();
+ int wordEnd = i + strlen(keyword);
+ char startCh = keyword[0]; // first char of header
+ char endCh = 0; // char just after header
+ char prevCh = 0; // char just before header
+
+ if (wordEnd < lineLength)
+ {
+ endCh = line[wordEnd];
+ }
+ if (i > 0)
+ {
+ prevCh = line[i-1];
+ }
+
+ if (prevCh != 0
+ && isLegalNameCharX(startCh)
+ && isLegalNameCharX(prevCh))
+ {
+ return false;
+ }
+ else if (wordEnd >= lineLength
+ || !isLegalNameCharX(startCh)
+ || !isLegalNameCharX(endCh))
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ return false;
+}
+
+} // end namespace astyle