diff options
Diffstat (limited to 'lib/astyle/ASEnhancer.cpp')
-rw-r--r-- | lib/astyle/ASEnhancer.cpp | 483 |
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 |