diff options
author | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
---|---|---|
committer | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
commit | 114a878c64ce6f8223cfd22d76a20eb16d177e5e (patch) | |
tree | acaf47eb0fa12142d3896416a69e74cbf5a72242 /lib/astyle | |
download | tdevelop-114a878c64ce6f8223cfd22d76a20eb16d177e5e.tar.gz tdevelop-114a878c64ce6f8223cfd22d76a20eb16d177e5e.zip |
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdevelop@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'lib/astyle')
-rw-r--r-- | lib/astyle/ASBeautifier.cpp | 1933 | ||||
-rw-r--r-- | lib/astyle/ASEnhancer.cpp | 483 | ||||
-rw-r--r-- | lib/astyle/ASFormatter.cpp | 2197 | ||||
-rw-r--r-- | lib/astyle/ASResource.cpp | 389 | ||||
-rw-r--r-- | lib/astyle/Makefile.am | 4 | ||||
-rw-r--r-- | lib/astyle/astyle.h | 497 | ||||
-rw-r--r-- | lib/astyle/compiler_defines.h | 49 |
7 files changed, 5552 insertions, 0 deletions
diff --git a/lib/astyle/ASBeautifier.cpp b/lib/astyle/ASBeautifier.cpp new file mode 100644 index 00000000..432d58a9 --- /dev/null +++ b/lib/astyle/ASBeautifier.cpp @@ -0,0 +1,1933 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * + * ASBeautifier.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. + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + */ + +#include "astyle.h" + +#include <algorithm> +#include <iostream> + + +#define INIT_CONTAINER(container, value) {if ( (container) != NULL ) delete (container); (container) = (value); } +#define DELETE_CONTAINER(container) {if ( (container) != NULL ) delete (container); } + + +namespace astyle +{ +vector<const string*> ASBeautifier::headers; +vector<const string*> ASBeautifier::nonParenHeaders; +vector<const string*> ASBeautifier::preBlockStatements; +vector<const string*> ASBeautifier::assignmentOperators; +vector<const string*> ASBeautifier::nonAssignmentOperators; + + +/* + * initialize the static vars + */ +void ASBeautifier::initStatic() +{ + static int beautifierFileType = 9; // initialized with an invalid type + + if (fileType == beautifierFileType) // don't build unless necessary + return; + + beautifierFileType = fileType; + + headers.clear(); + nonParenHeaders.clear(); + assignmentOperators.clear(); + nonAssignmentOperators.clear(); + preBlockStatements.clear(); + + ASResource::buildHeaders(headers, fileType, true); + ASResource::buildNonParenHeaders(nonParenHeaders, fileType, true); + ASResource::buildAssignmentOperators(assignmentOperators); + ASResource::buildNonAssignmentOperators(nonAssignmentOperators); + ASResource::buildPreBlockStatements(preBlockStatements); + +// cout << "beaut" << endl; +} + +/** + * ASBeautifier's constructor + */ +ASBeautifier::ASBeautifier() +{ + waitingBeautifierStack = NULL; + activeBeautifierStack = NULL; + waitingBeautifierStackLengthStack = NULL; + activeBeautifierStackLengthStack = NULL; + + headerStack = NULL; + tempStacks = NULL; + blockParenDepthStack = NULL; + blockStatementStack = NULL; + parenStatementStack = NULL; + bracketBlockStateStack = NULL; + inStatementIndentStack = NULL; + inStatementIndentStackSizeStack = NULL; + parenIndentStack = NULL; + sourceIterator = NULL; + + isMinimalConditinalIndentSet = false; + shouldForceTabIndentation = false; + + setSpaceIndentation(4); + setMaxInStatementIndentLength(40); + setClassIndent(false); + setSwitchIndent(false); + setCaseIndent(false); + setBlockIndent(false); + setBracketIndent(false); + setNamespaceIndent(false); + setLabelIndent(false); + setEmptyLineFill(false); + fileType = C_TYPE; + setCStyle(); + setPreprocessorIndent(false); +} + +/** + * ASBeautifier's copy constructor + */ +ASBeautifier::ASBeautifier(const ASBeautifier &other) +{ + waitingBeautifierStack = NULL; + activeBeautifierStack = NULL; + waitingBeautifierStackLengthStack = NULL; + activeBeautifierStackLengthStack = NULL; + + headerStack = new vector<const string*>; + *headerStack = *other.headerStack; + + tempStacks = new vector<vector<const string*>*>; + vector<vector<const string*>*>::iterator iter; + for (iter = other.tempStacks->begin(); + iter != other.tempStacks->end(); + ++iter) + { + vector<const string*> *newVec = new vector<const string*>; + *newVec = **iter; + tempStacks->push_back(newVec); + } + blockParenDepthStack = new vector<int>; + *blockParenDepthStack = *other.blockParenDepthStack; + + blockStatementStack = new vector<bool>; + *blockStatementStack = *other.blockStatementStack; + + parenStatementStack = new vector<bool>; + *parenStatementStack = *other.parenStatementStack; + + bracketBlockStateStack = new vector<bool>; + *bracketBlockStateStack = *other.bracketBlockStateStack; + + inStatementIndentStack = new vector<int>; + *inStatementIndentStack = *other.inStatementIndentStack; + + inStatementIndentStackSizeStack = new vector<int>; + *inStatementIndentStackSizeStack = *other.inStatementIndentStackSizeStack; + + parenIndentStack = new vector<int>; + *parenIndentStack = *other.parenIndentStack; + + sourceIterator = other.sourceIterator; + + // protected variables + fileType = other.fileType; + isCStyle = other.isCStyle; + isJavaStyle = other.isJavaStyle; + isSharpStyle = other.isSharpStyle; + + // variables set by ASFormatter + // must also be updated in preprocessor + inLineNumber = other.inLineNumber; + outLineNumber = other.outLineNumber; + lineCommentNoBeautify = other.lineCommentNoBeautify; + isNonInStatementArray = other.isNonInStatementArray; + + // private variables + indentString = other.indentString; + currentHeader = other.currentHeader; + previousLastLineHeader = other.previousLastLineHeader; + immediatelyPreviousAssignmentOp = other.immediatelyPreviousAssignmentOp; + probationHeader = other.probationHeader; + isInQuote = other.isInQuote; + isInComment = other.isInComment; + isInCase = other.isInCase; + isInQuestion = other.isInQuestion; + isInStatement = other.isInStatement; + isInHeader = other.isInHeader; + isInOperator = other.isInOperator; + isInTemplate = other.isInTemplate; + isInDefine = other.isInDefine; + isInDefineDefinition = other.isInDefineDefinition; + classIndent = other.classIndent; + isInClassHeader = other.isInClassHeader; + isInClassHeaderTab = other.isInClassHeaderTab; + switchIndent = other.switchIndent; + caseIndent = other.caseIndent; + namespaceIndent = other.namespaceIndent; + bracketIndent = other.bracketIndent; + blockIndent = other.blockIndent; + labelIndent = other.labelIndent; + preprocessorIndent = other.preprocessorIndent; + isInConditional = other.isInConditional; + isMinimalConditinalIndentSet = other.isMinimalConditinalIndentSet; + shouldForceTabIndentation = other.shouldForceTabIndentation; + emptyLineFill = other.emptyLineFill; + backslashEndsPrevLine = other.backslashEndsPrevLine; + blockCommentNoIndent = other.blockCommentNoIndent; + blockCommentNoBeautify = other.blockCommentNoBeautify; + previousLineProbationTab = other.previousLineProbationTab; + minConditionalIndent = other.minConditionalIndent; + parenDepth = other.parenDepth; + indentLength = other.indentLength; + blockTabCount = other.blockTabCount; + leadingWhiteSpaces = other.leadingWhiteSpaces; + maxInStatementIndent = other.maxInStatementIndent; + templateDepth = other.templateDepth; + prevFinalLineSpaceTabCount = other.prevFinalLineSpaceTabCount; + prevFinalLineTabCount = other.prevFinalLineTabCount; + defineTabCount = other.defineTabCount; + quoteChar = other.quoteChar; + prevNonSpaceCh = other.prevNonSpaceCh; + currentNonSpaceCh = other.currentNonSpaceCh; + currentNonLegalCh = other.currentNonLegalCh; + prevNonLegalCh = other.prevNonLegalCh; +} + +/** + * ASBeautifier's destructor + */ +ASBeautifier::~ASBeautifier() +{ + DELETE_CONTAINER(headerStack); + DELETE_CONTAINER(tempStacks); + DELETE_CONTAINER(blockParenDepthStack); + DELETE_CONTAINER(blockStatementStack); + DELETE_CONTAINER(parenStatementStack); + DELETE_CONTAINER(bracketBlockStateStack); + DELETE_CONTAINER(inStatementIndentStack); + DELETE_CONTAINER(inStatementIndentStackSizeStack); + DELETE_CONTAINER(parenIndentStack); +} + +/** + * initialize the ASBeautifier. + * + * init() should be called every time a ABeautifier object is to start + * beautifying a NEW source file. + * init() recieves a pointer to a DYNAMICALLY CREATED ASSourceIterator object + * that will be used to iterate through the source code. This object will be + * deleted during the ASBeautifier's destruction, and thus should not be + * deleted elsewhere. + * + * @param iter a pointer to the DYNAMICALLY CREATED ASSourceIterator object. + */ +void ASBeautifier::init(ASSourceIterator *iter) +{ + sourceIterator = iter; + init(); +} + +/** + * initialize the ASBeautifier. + */ +void ASBeautifier::init() +{ + initStatic(); + + INIT_CONTAINER(waitingBeautifierStack, new vector<ASBeautifier*>); + INIT_CONTAINER(activeBeautifierStack, new vector<ASBeautifier*>); + + INIT_CONTAINER(waitingBeautifierStackLengthStack, new vector<int>); + INIT_CONTAINER(activeBeautifierStackLengthStack, new vector<int>); + + INIT_CONTAINER(headerStack, new vector<const string*>); + INIT_CONTAINER(tempStacks, new vector<vector<const string*>*>); + tempStacks->push_back(new vector<const string*>); + + INIT_CONTAINER(blockParenDepthStack, new vector<int>); + INIT_CONTAINER(blockStatementStack, new vector<bool>); + INIT_CONTAINER(parenStatementStack, new vector<bool>); + + INIT_CONTAINER(bracketBlockStateStack, new vector<bool>); + bracketBlockStateStack->push_back(true); + + INIT_CONTAINER(inStatementIndentStack, new vector<int>); + INIT_CONTAINER(inStatementIndentStackSizeStack, new vector<int>); + inStatementIndentStackSizeStack->push_back(0); + INIT_CONTAINER(parenIndentStack, new vector<int>); + + immediatelyPreviousAssignmentOp = NULL; + previousLastLineHeader = NULL; + currentHeader = NULL; + + isInQuote = false; + isInComment = false; + isInStatement = false; + isInCase = false; + isInQuestion = false; + isInClassHeader = false; + isInClassHeaderTab = false; + isInHeader = false; + isInOperator = false; + isInTemplate = false; + isInConditional = false; + templateDepth = 0; + parenDepth = 0; + blockTabCount = 0; + leadingWhiteSpaces = 0; + prevNonSpaceCh = '{'; + currentNonSpaceCh = '{'; + prevNonLegalCh = '{'; + currentNonLegalCh = '{'; + quoteChar = ' '; + prevFinalLineSpaceTabCount = 0; + prevFinalLineTabCount = 0; + probationHeader = NULL; + backslashEndsPrevLine = false; + isInDefine = false; + isInDefineDefinition = false; + defineTabCount = 0; + lineCommentNoBeautify = false; + blockCommentNoIndent = false; + blockCommentNoBeautify = false; + previousLineProbationTab = false; + isNonInStatementArray = false; + inLineNumber = -1; // for debugging + outLineNumber = 0; // for debugging +} + +/** + * set indentation style to C/C++. + */ +void ASBeautifier::setCStyle() +{ + fileType = C_TYPE; + isCStyle = true; + isJavaStyle = false; + isSharpStyle = false; +} + +/** + * set indentation style to Java. + */ +void ASBeautifier::setJavaStyle() +{ + fileType = JAVA_TYPE; + isJavaStyle = true; + isCStyle = false; + isSharpStyle = false; +} + +/** + * set indentation style to C#. + */ +void ASBeautifier::setSharpStyle() +{ + fileType = SHARP_TYPE; + isSharpStyle = true; + isCStyle = false; + isJavaStyle = false; +} + +/** + * indent using one tab per indentation + */ +void ASBeautifier::setTabIndentation(int length, bool forceTabs) +{ + indentString = "\t"; + indentLength = length; + shouldForceTabIndentation = forceTabs; + + if (!isMinimalConditinalIndentSet) + minConditionalIndent = indentLength * 2; +} + +/** + * indent using a number of spaces per indentation. + * + * @param length number of spaces per indent. + */ +void ASBeautifier::setSpaceIndentation(int length) +{ + indentString = string(length, ' '); + indentLength = length; + + if (!isMinimalConditinalIndentSet) + minConditionalIndent = indentLength * 2; +} + +/** + * set the maximum indentation between two lines in a multi-line statement. + * + * @param max maximum indentation length. + */ +void ASBeautifier::setMaxInStatementIndentLength(int max) +{ + maxInStatementIndent = max; +} + +/** + * set the minimum indentation between two lines in a multi-line condition. + * + * @param min minimal indentation length. + */ +void ASBeautifier::setMinConditionalIndentLength(int min) +{ + minConditionalIndent = min; + isMinimalConditinalIndentSet = true; +} + +/** + * set the state of the bracket indentation option. If true, brackets will + * be indented one additional indent. + * + * @param state state of option. + */ +void ASBeautifier::setBracketIndent(bool state) +{ + bracketIndent = state; +} + +/** + * set the state of the block indentation option. If true, entire blocks + * will be indented one additional indent, similar to the GNU indent style. + * + * @param state state of option. + */ +void ASBeautifier::setBlockIndent(bool state) +{ + if (state) + setBracketIndent(false); // so that we don't have both bracket and block indent + blockIndent = state; +} + +/** + * set the state of the class indentation option. If true, C++ class + * definitions will be indented one additional indent. + * + * @param state state of option. + */ +void ASBeautifier::setClassIndent(bool state) +{ + classIndent = state; +} + +/** + * set the state of the switch indentation option. If true, blocks of 'switch' + * statements will be indented one additional indent. + * + * @param state state of option. + */ +void ASBeautifier::setSwitchIndent(bool state) +{ + switchIndent = state; +} + +/** + * set the state of the case indentation option. If true, lines of 'case' + * statements will be indented one additional indent. + * + * @param state state of option. + */ +void ASBeautifier::setCaseIndent(bool state) +{ + caseIndent = state; +} + +/** + * set the state of the namespace indentation option. + * If true, blocks of 'namespace' statements will be indented one + * additional indent. Otherwise, NO indentation will be added. + * + * @param state state of option. + */ +void ASBeautifier::setNamespaceIndent(bool state) +{ + namespaceIndent = state; +} + +/** + * set the state of the label indentation option. + * If true, labels will be indented one indent LESS than the + * current indentation level. + * If false, labels will be flushed to the left with NO + * indent at all. + * + * @param state state of option. + */ +void ASBeautifier::setLabelIndent(bool state) +{ + labelIndent = state; +} + +/** + * set the state of the preprocessor indentation option. + * If true, multiline #define statements will be indented. + * + * @param state state of option. + */ +void ASBeautifier::setPreprocessorIndent(bool state) +{ + preprocessorIndent = state; +} + +/** + * set the state of the empty line fill option. + * If true, empty lines will be filled with the whitespace. + * of their previous lines. + * If false, these lines will remain empty. + * + * @param state state of option. + */ +void ASBeautifier::setEmptyLineFill(bool state) +{ + emptyLineFill = state; +} + +/** + * get the number of spaces per indent + * + * @return value of indentLength option. +*/ +int ASBeautifier::getIndentLength(void) +{ + return indentLength; +} + +/** + * get the char used for indentation, space or tab + * + * @return the char used for indentation. + */ +string ASBeautifier::getIndentString(void) +{ + return indentString; +} + +/** + * get the state of the case indentation option. If true, lines of 'case' + * statements will be indented one additional indent. + * + * @return state of caseIndent option. + */ +bool ASBeautifier::getCaseIndent(void) +{ + return caseIndent; +} + +/** + * get C style identifier. + * If true, a C source is being indented. + * + * @return state of isCStyle option. + */ +bool ASBeautifier::getCStyle(void) +{ + return isCStyle; +} + +/** + * get Java style identifier. + * If true, a Java source is being indented. + * + * @return state of isJavaStyle option. + */ +bool ASBeautifier::getJavaStyle(void) +{ + return isJavaStyle; +} + +/** + * get C# style identifier. + * If true, a C# source is being indented. + * + * @return state of isSharpStyle option. + */ +bool ASBeautifier::getSharpStyle(void) +{ + return isSharpStyle; +} + +/** + * get the state of the empty line fill option. + * If true, empty lines will be filled with the whitespace. + * of their previous lines. + * If false, these lines will remain empty. + * + * @return state of emptyLineFill option. + */ +bool ASBeautifier::getEmptyLineFill(void) +{ + return emptyLineFill; +} + +/** + * check if there are any indented lines ready to be read by nextLine() + * + * @return are there any indented lines ready? + */ +bool ASBeautifier::hasMoreLines() const +{ + return sourceIterator->hasMoreLines(); +} + +/** + * get the next indented line. + * + * @return indented line. + */ +string ASBeautifier::nextLine() +{ + return beautify(sourceIterator->nextLine()); +} + +/** + * beautify a line of source code. + * every line of source code in a source code file should be sent + * one after the other to the beautify method. + * + * @return the indented line. + * @param originalLine the original unindented line. + */ +string ASBeautifier::beautify(const string &originalLine) +{ + string line; + bool isInLineComment = false; + bool lineStartsInComment = false; + bool isInClass = false; + bool isInSwitch = false; + bool isImmediatelyAfterConst = false; + bool isSpecialChar = false; + char ch = ' '; + char prevCh; + string outBuffer; // the newly idented line is bufferd here + int tabCount = 0; + const string *lastLineHeader = NULL; + bool closingBracketReached = false; + int spaceTabCount = 0; + char tempCh; + size_t headerStackSize = headerStack->size(); + bool shouldIndentBrackettedLine = true; + int lineOpeningBlocksNum = 0; + int lineClosingBlocksNum = 0; + bool previousLineProbation = (probationHeader != NULL); + int i; + + currentHeader = NULL; + lineStartsInComment = isInComment; + blockCommentNoBeautify = blockCommentNoIndent; + previousLineProbationTab = false; + outLineNumber++; + + // handle and remove white spaces around the line: + // If not in comment, first find out size of white space before line, + // so that possible comments starting in the line continue in + // relation to the preliminary white-space. + if (!isInComment) + { + int strlen = originalLine.length(); + leadingWhiteSpaces = 0; + + for (int j = 0; j < strlen && isWhiteSpace(originalLine[j]); j++) + { + if (originalLine[j] == '\t') + leadingWhiteSpaces += indentLength; + else + leadingWhiteSpaces++; + } + line = trim(originalLine); + } + else + { + // convert leading tabs to spaces + string spaceTabs(indentLength, ' '); + string newLine = originalLine; + int strlen = newLine.length(); + + for (int j=0; j < leadingWhiteSpaces && j < strlen; j++) + { + if (newLine[j] == '\t') + { + newLine.replace(j, 1, spaceTabs); + strlen = newLine.length(); + } + } + + // trim the comment leaving the new leading whitespace + int trimSize = 0; + strlen = newLine.length(); + + while (trimSize < strlen + && trimSize < leadingWhiteSpaces + && isWhiteSpace(newLine[trimSize])) + trimSize++; + + + while (trimSize < strlen && isWhiteSpace(newLine[strlen-1])) + strlen--; + + line = newLine.substr(trimSize, strlen); + size_t trimEnd = line.find_last_not_of(" \t"); + if (trimEnd != string::npos) + { + int spacesToDelete = line.length() - 1 - trimEnd; + if (spacesToDelete > 0) + line.erase(trimEnd + 1, spacesToDelete); + } + } + + + if (line.length() == 0) + { + if (backslashEndsPrevLine) // must continue to clear variables + line = ' '; + else if (emptyLineFill) + return preLineWS(prevFinalLineSpaceTabCount, prevFinalLineTabCount); + else + return line; + } + + // handle preprocessor commands + + if (isCStyle && !isInComment && (line[0] == '#' || backslashEndsPrevLine)) + { + if (line[0] == '#') + { + string preproc = trim(string(line.c_str() + 1)); + + // When finding a multi-lined #define statement, the original beautifier + // 1. sets its isInDefineDefinition flag + // 2. clones a new beautifier that will be used for the actual indentation + // of the #define. This clone is put into the activeBeautifierStack in order + // to be called for the actual indentation. + // The original beautifier will have isInDefineDefinition = true, isInDefine = false + // The cloned beautifier will have isInDefineDefinition = true, isInDefine = true + if (preprocessorIndent && preproc.compare(0, 6, "define") == 0 && line[line.length() - 1] == '\\') + { + if (!isInDefineDefinition) + { + ASBeautifier *defineBeautifier; + + // this is the original beautifier + isInDefineDefinition = true; + + // push a new beautifier into the active stack + // this beautifier will be used for the indentation of this define + defineBeautifier = new ASBeautifier(*this); + activeBeautifierStack->push_back(defineBeautifier); + } + else + { + // the is the cloned beautifier that is in charge of indenting the #define. + isInDefine = true; + } + } + else if (preproc.compare(0, 2, "if") == 0) + { + // push a new beautifier into the stack + waitingBeautifierStackLengthStack->push_back(waitingBeautifierStack->size()); + activeBeautifierStackLengthStack->push_back(activeBeautifierStack->size()); + waitingBeautifierStack->push_back(new ASBeautifier(*this)); + } + else if (preproc.compare(0, 4/*2*/, "else") == 0) + { + if (waitingBeautifierStack && !waitingBeautifierStack->empty()) + { + // MOVE current waiting beautifier to active stack. + activeBeautifierStack->push_back(waitingBeautifierStack->back()); + waitingBeautifierStack->pop_back(); + } + } + else if (preproc.compare(0, 4, "elif") == 0) + { + if (waitingBeautifierStack && !waitingBeautifierStack->empty()) + { + // append a COPY current waiting beautifier to active stack, WITHOUT deleting the original. + activeBeautifierStack->push_back(new ASBeautifier(*(waitingBeautifierStack->back()))); + } + } + else if (preproc.compare(0, 5, "endif") == 0) + { + int stackLength; + ASBeautifier *beautifier; + + if (waitingBeautifierStackLengthStack && !waitingBeautifierStackLengthStack->empty()) + { + stackLength = waitingBeautifierStackLengthStack->back(); + waitingBeautifierStackLengthStack->pop_back(); + while ((int) waitingBeautifierStack->size() > stackLength) + { + beautifier = waitingBeautifierStack->back(); + waitingBeautifierStack->pop_back(); + delete beautifier; + } + } + + if (!activeBeautifierStackLengthStack->empty()) + { + stackLength = activeBeautifierStackLengthStack->back(); + activeBeautifierStackLengthStack->pop_back(); + while ((int) activeBeautifierStack->size() > stackLength) + { + beautifier = activeBeautifierStack->back(); + activeBeautifierStack->pop_back(); + delete beautifier; + } + } + } + } + + // check if the last char is a backslash + if (line.length() > 0) + backslashEndsPrevLine = (line[line.length() - 1] == '\\'); + else + backslashEndsPrevLine = false; + + // check if this line ends a multi-line #define + // if so, use the #define's cloned beautifier for the line's indentation + // and then remove it from the active beautifier stack and delete it. + if (!backslashEndsPrevLine && isInDefineDefinition && !isInDefine) + { + string beautifiedLine; + ASBeautifier *defineBeautifier; + + isInDefineDefinition = false; + defineBeautifier = activeBeautifierStack->back(); + activeBeautifierStack->pop_back(); + + beautifiedLine = defineBeautifier->beautify(line); + delete defineBeautifier; + return beautifiedLine; + } + + // unless this is a multi-line #define, return this precompiler line as is. + if (!isInDefine && !isInDefineDefinition) + return originalLine; + } + + // if there exists any worker beautifier in the activeBeautifierStack, + // then use it instead of me to indent the current line. + // variables set by ASFormatter must be updated. + if (!isInDefine && activeBeautifierStack != NULL && !activeBeautifierStack->empty()) + { + activeBeautifierStack->back()->inLineNumber = inLineNumber; + activeBeautifierStack->back()->outLineNumber = outLineNumber; + activeBeautifierStack->back()->lineCommentNoBeautify = lineCommentNoBeautify; + activeBeautifierStack->back()->isNonInStatementArray = isNonInStatementArray; + return activeBeautifierStack->back()->beautify(line); + } + + // calculate preliminary indentation based on data from past lines + if (!inStatementIndentStack->empty()) + spaceTabCount = inStatementIndentStack->back(); + + + for (i = 0; i < (int) headerStackSize; i++) + { + isInClass = false; + + if (blockIndent || (!(i > 0 && (*headerStack)[i-1] != &AS_OPEN_BRACKET + && (*headerStack)[i] == &AS_OPEN_BRACKET))) + ++tabCount; + + if (!isJavaStyle && !namespaceIndent && i >= 1 + && (*headerStack)[i-1] == &AS_NAMESPACE + && (*headerStack)[i] == &AS_OPEN_BRACKET) + --tabCount; + + if (isCStyle && i >= 1 + && (*headerStack)[i-1] == &AS_CLASS + && (*headerStack)[i] == &AS_OPEN_BRACKET) + { + if (classIndent) + ++tabCount; + isInClass = true; + } + + // is the switchIndent option is on, indent switch statements an additional indent. + else if (switchIndent && i > 1 && + (*headerStack)[i-1] == &AS_SWITCH && + (*headerStack)[i] == &AS_OPEN_BRACKET + ) + { + ++tabCount; + isInSwitch = true; + } + + } + + if (!lineStartsInComment + && isCStyle + && isInClass + && classIndent + && headerStackSize >= 2 + && (*headerStack)[headerStackSize-2] == &AS_CLASS + && (*headerStack)[headerStackSize-1] == &AS_OPEN_BRACKET + && line[0] == '}') + --tabCount; + + else if (!lineStartsInComment + && isInSwitch + && switchIndent + && headerStackSize >= 2 + && (*headerStack)[headerStackSize-2] == &AS_SWITCH + && (*headerStack)[headerStackSize-1] == &AS_OPEN_BRACKET + && line[0] == '}') + --tabCount; + + if (isInClassHeader) + { + isInClassHeaderTab = true; + tabCount += 2; + } + + if (isInConditional) + { + --tabCount; + } + + + // parse characters in the current line. + + for (i = 0; i < (int) line.length(); i++) + { + tempCh = line[i]; + + prevCh = ch; + ch = tempCh; + + outBuffer.append(1, ch); + + if (isWhiteSpace(ch)) + continue; + + // check for utf8 characters + // isalnum() will display an assert message in debug if not bypassed here + if (ch < 0) + continue; + + // handle special characters (i.e. backslash+character such as \n, \t, ...) + if (isSpecialChar) + { + isSpecialChar = false; + continue; + } + if (!(isInComment || isInLineComment) && line.compare(i, 2, "\\\\") == 0) + { + outBuffer.append(1, '\\'); + i++; + continue; + } + if (!(isInComment || isInLineComment) && ch == '\\') + { + isSpecialChar = true; + continue; + } + + // handle quotes (such as 'x' and "Hello Dolly") + if (!(isInComment || isInLineComment) && (ch == '"' || ch == '\'')) + if (!isInQuote) + { + quoteChar = ch; + isInQuote = true; + } + else if (quoteChar == ch) + { + isInQuote = false; + isInStatement = true; + continue; + } + if (isInQuote) + continue; + + // handle comments + + if (!(isInComment || isInLineComment) && line.compare(i, 2, "//") == 0) + { + isInLineComment = true; + outBuffer.append(1, '/'); + i++; + continue; + } + else if (!(isInComment || isInLineComment) && line.compare(i, 2, "/*") == 0) + { + isInComment = true; + outBuffer.append(1, '*'); + i++; + size_t j = line.find_first_not_of(" \t"); + if (!line.compare(j, 2, "/*") == 0) // does line start with comment? + blockCommentNoIndent = true; // if no, cannot indent continuation lines + continue; + } + else if ((isInComment || isInLineComment) && line.compare(i, 2, "*/") == 0) + { + isInComment = false; + outBuffer.append(1, '/'); + i++; + blockCommentNoIndent = false; // ok to indent next comment + continue; + } + + if (isInComment || isInLineComment) + continue; + + // if we have reached this far then we are NOT in a comment or string of special character... + + if (probationHeader != NULL) + { + if (((probationHeader == &AS_STATIC || probationHeader == &AS_CONST) && ch == '{') + || (probationHeader == &AS_SYNCHRONIZED && ch == '(')) + { + // insert the probation header as a new header + isInHeader = true; + headerStack->push_back(probationHeader); + + // handle the specific probation header + isInConditional = (probationHeader == &AS_SYNCHRONIZED); + if (probationHeader == &AS_CONST) + isImmediatelyAfterConst = true; + + isInStatement = false; + // if the probation comes from the previous line, then indent by 1 tab count. + if (previousLineProbation && ch == '{') + { + tabCount++; + previousLineProbationTab = true; + } + previousLineProbation = false; + } + + // dismiss the probation header + probationHeader = NULL; + } + + prevNonSpaceCh = currentNonSpaceCh; + currentNonSpaceCh = ch; + if (!isLegalNameChar(ch) && ch != ',' && ch != ';') + { + prevNonLegalCh = currentNonLegalCh; + currentNonLegalCh = ch; + } + + if (isInHeader) + { + isInHeader = false; + currentHeader = headerStack->back(); + } + else + currentHeader = NULL; + + if (isCStyle && isInTemplate + && (ch == '<' || ch == '>') + && findHeader(line, i, nonAssignmentOperators) == NULL) + { + if (ch == '<') + { + ++templateDepth; + } + else if (ch == '>') + { + if (--templateDepth <= 0) + { + if (isInTemplate) + ch = ';'; + else + ch = 't'; + isInTemplate = false; + templateDepth = 0; + } + } + } + + // handle parenthesies + if (ch == '(' || ch == '[' || ch == ')' || ch == ']') + { + if (ch == '(' || ch == '[') + { + if (parenDepth == 0) + { + parenStatementStack->push_back(isInStatement); + isInStatement = true; + } + parenDepth++; + + inStatementIndentStackSizeStack->push_back(inStatementIndentStack->size()); + + if (currentHeader != NULL) + registerInStatementIndent(line, i, spaceTabCount, minConditionalIndent/*indentLength*2*/, true); + else + registerInStatementIndent(line, i, spaceTabCount, 0, true); + } + else if (ch == ')' || ch == ']') + { + parenDepth--; + if (parenDepth == 0) + { + isInStatement = parenStatementStack->back(); + parenStatementStack->pop_back(); + ch = ' '; + + isInConditional = false; + } + + if (!inStatementIndentStackSizeStack->empty()) + { + int previousIndentStackSize = inStatementIndentStackSizeStack->back(); + inStatementIndentStackSizeStack->pop_back(); + while (previousIndentStackSize < (int) inStatementIndentStack->size()) + inStatementIndentStack->pop_back(); + + if (!parenIndentStack->empty()) + { + int poppedIndent = parenIndentStack->back(); + parenIndentStack->pop_back(); + + if (i == 0) + spaceTabCount = poppedIndent; + } + } + } + + continue; + } + + + if (ch == '{') + { + bool isBlockOpener; + // first, check if '{' is a block-opener or an static-array opener + isBlockOpener = ((prevNonSpaceCh == '{' && bracketBlockStateStack->back()) + || prevNonSpaceCh == '}' + || prevNonSpaceCh == ')' + || prevNonSpaceCh == ';' + || peekNextChar(line, i) == '{' + || isNonInStatementArray + || isInClassHeader +// || isBlockOpener + || isImmediatelyAfterConst + || (isInDefine && + (prevNonSpaceCh == '(' + || prevNonSpaceCh == '_' + || isalnum(prevNonSpaceCh)))); + + isInClassHeader = false; + if (!isBlockOpener && currentHeader != NULL) + { + for (size_t n = 0; n < nonParenHeaders.size(); n++) + if (currentHeader == nonParenHeaders[n]) + { + isBlockOpener = true; + break; + } + } + bracketBlockStateStack->push_back(isBlockOpener); + if (!isBlockOpener) + { + inStatementIndentStackSizeStack->push_back(inStatementIndentStack->size()); + registerInStatementIndent(line, i, spaceTabCount, 0, true); + parenDepth++; + if (i == 0) + shouldIndentBrackettedLine = false; + + continue; + } + + // this bracket is a block opener... + + ++lineOpeningBlocksNum; +// if (isInClassHeader) +// isInClassHeader = false; + + if (isInClassHeaderTab) + { + isInClassHeaderTab = false; + // decrease tab count if bracket is broken + size_t firstChar = line.find_first_not_of(" \t"); + if (firstChar != string::npos) + if (line[firstChar] == '{' && (int) firstChar == i) + tabCount -= 2; + } + + // do not allow inStatementIndent - should occur for Java files only + if (inStatementIndentStack->size() > 0) + { + spaceTabCount = 0; + inStatementIndentStack->back() = 0; + } + + blockParenDepthStack->push_back(parenDepth); + blockStatementStack->push_back(isInStatement); + + inStatementIndentStackSizeStack->push_back(inStatementIndentStack->size()); + if (inStatementIndentStack->size() > 0) + inStatementIndentStack->back() = 0; + + blockTabCount += isInStatement ? 1 : 0; + parenDepth = 0; + isInStatement = false; + + tempStacks->push_back(new vector<const string*>); + headerStack->push_back(&AS_OPEN_BRACKET); + lastLineHeader = &AS_OPEN_BRACKET; + + continue; + } + + //check if a header has been reached + if (isWhiteSpace(prevCh)) + { + bool isIndentableHeader = true; + const string *newHeader = findHeader(line, i, headers); + if (newHeader != NULL) + { + // if we reached here, then this is a header... + isInHeader = true; + + vector<const string*> *lastTempStack; + if (tempStacks->empty()) + lastTempStack = NULL; + else + lastTempStack = tempStacks->back(); + + // if a new block is opened, push a new stack into tempStacks to hold the + // future list of headers in the new block. + + // take care of the special case: 'else if (...)' + if (newHeader == &AS_IF && lastLineHeader == &AS_ELSE) + { + headerStack->pop_back(); + } + + // take care of 'else' + else if (newHeader == &AS_ELSE) + { + if (lastTempStack != NULL) + { + int indexOfIf = indexOf(*lastTempStack, &AS_IF); + if (indexOfIf != -1) + { + // recreate the header list in headerStack up to the previous 'if' + // from the temporary snapshot stored in lastTempStack. + int restackSize = lastTempStack->size() - indexOfIf - 1; + for (int r = 0; r < restackSize; r++) + { + headerStack->push_back(lastTempStack->back()); + lastTempStack->pop_back(); + } + if (!closingBracketReached) + tabCount += restackSize; + } + /* + * If the above if is not true, i.e. no 'if' before the 'else', + * then nothing beautiful will come out of this... + * I should think about inserting an Exception here to notify the caller of this... + */ + } + } + + // check if 'while' closes a previous 'do' + else if (newHeader == &AS_WHILE) + { + if (lastTempStack != NULL) + { + int indexOfDo = indexOf(*lastTempStack, &AS_DO); + if (indexOfDo != -1) + { + // recreate the header list in headerStack up to the previous 'do' + // from the temporary snapshot stored in lastTempStack. + int restackSize = lastTempStack->size() - indexOfDo - 1; + for (int r = 0; r < restackSize; r++) + { + headerStack->push_back(lastTempStack->back()); + lastTempStack->pop_back(); + } + if (!closingBracketReached) + tabCount += restackSize; + } + } + } + // check if 'catch' closes a previous 'try' or 'catch' + else if (newHeader == &AS_CATCH || newHeader == &AS_FINALLY) + { + if (lastTempStack != NULL) + { + int indexOfTry = indexOf(*lastTempStack, &AS_TRY); + if (indexOfTry == -1) + indexOfTry = indexOf(*lastTempStack, &AS_CATCH); + if (indexOfTry != -1) + { + // recreate the header list in headerStack up to the previous 'try' + // from the temporary snapshot stored in lastTempStack. + int restackSize = lastTempStack->size() - indexOfTry - 1; + for (int r = 0; r < restackSize; r++) + { + headerStack->push_back(lastTempStack->back()); + lastTempStack->pop_back(); + } + + if (!closingBracketReached) + tabCount += restackSize; + } + } + } + else if (newHeader == &AS_CASE) + { + isInCase = true; + --tabCount; + } + else if (newHeader == &AS_DEFAULT) + { + isInCase = true; + --tabCount; + } + else if (newHeader == &AS_STATIC + || newHeader == &AS_SYNCHRONIZED + || (newHeader == &AS_CONST && isCStyle)) + { + if (!headerStack->empty() && + (headerStack->back() == &AS_STATIC + || headerStack->back() == &AS_SYNCHRONIZED + || headerStack->back() == &AS_CONST)) + { + isIndentableHeader = false; + } + else + { + isIndentableHeader = false; + probationHeader = newHeader; + } + } + else if (newHeader == &AS_CONST) + { + isIndentableHeader = false; + } + else if (newHeader == &AS_TEMPLATE) + { + if (isCStyle) + isInTemplate = true; + isIndentableHeader = false; + } + + + if (isIndentableHeader) + { + headerStack->push_back(newHeader); + isInStatement = false; + if (indexOf(nonParenHeaders, newHeader) == -1) + { + isInConditional = true; + } + lastLineHeader = newHeader; + } + else + isInHeader = false; + + outBuffer.append(newHeader->substr(1)); + i += newHeader->length() - 1; + + continue; + } + } + + if (isCStyle && !isalpha(prevCh) + && line.compare(i, 8, "operator") == 0 && !isalnum(line[i+8])) + { + isInOperator = true; + outBuffer.append(AS_OPERATOR.substr(1)); + i += 7; + continue; + } + + // "new" operator is a pointer, not a calculation + if (!isalpha(prevCh) + && line.compare(i, 3, "new") == 0 && !isalnum(line[i+3])) + { + if (prevNonSpaceCh == '=' && isInStatement && !inStatementIndentStack->empty()) + inStatementIndentStack->back() = 0; + } + + if (ch == '?') + isInQuestion = true; + + + // special handling of 'case' statements + if (ch == ':') + { + if ((int) line.length() > i + 1 && line[i+1] == ':') // look for :: + { + ++i; + outBuffer.append(1, ':'); + ch = ' '; + continue; + } + + else if (isInQuestion) + { + isInQuestion = false; + } + + else if (isCStyle && isInClass && prevNonSpaceCh != ')') + { + --tabCount; + // found a 'private:' or 'public:' inside a class definition + // so do nothing special + } + + else if (!isJavaStyle && isInClassHeader) + { + // found a 'class A : public B' definition + // so do nothing special + } + + else if (isJavaStyle && lastLineHeader == &AS_FOR) + { + // found a java for-each statement + // so do nothing special + } + + else if (isCStyle && prevNonSpaceCh == ')') + { + isInClassHeader = true; + if (i == 0) + tabCount += 2; + } + else + { + currentNonSpaceCh = ';'; // so that brackets after the ':' will appear as block-openers + if (isInCase) + { + isInCase = false; + ch = ';'; // from here on, treat char as ';' + } + + + else // is in a label (e.g. 'label1:') + { + if (labelIndent) + --tabCount; // unindent label by one indent + else + tabCount = 0; // completely flush indent to left + } + + + + } + } + + if ((ch == ';' || (parenDepth > 0 && ch == ',')) && !inStatementIndentStackSizeStack->empty()) + while ((int) inStatementIndentStackSizeStack->back() + (parenDepth > 0 ? 1 : 0) + < (int) inStatementIndentStack->size()) + inStatementIndentStack->pop_back(); + + + // handle ends of statements + if ((ch == ';' && parenDepth == 0) || ch == '}'/* || (ch == ',' && parenDepth == 0)*/) + { + if (ch == '}') + { + // first check if this '}' closes a previous block, or a static array... + if (!bracketBlockStateStack->empty()) + { + bool bracketBlockState = bracketBlockStateStack->back(); + bracketBlockStateStack->pop_back(); + if (!bracketBlockState) + { + if (!inStatementIndentStackSizeStack->empty()) + { + // this bracket is a static array + + int previousIndentStackSize = inStatementIndentStackSizeStack->back(); + inStatementIndentStackSizeStack->pop_back(); + while (previousIndentStackSize < (int) inStatementIndentStack->size()) + inStatementIndentStack->pop_back(); + parenDepth--; + if (i == 0) + shouldIndentBrackettedLine = false; + + if (!parenIndentStack->empty()) + { + int poppedIndent = parenIndentStack->back(); + parenIndentStack->pop_back(); + if (i == 0) + spaceTabCount = poppedIndent; + } + } + continue; + } + } + + // this bracket is block closer... + + ++lineClosingBlocksNum; + + if (!inStatementIndentStackSizeStack->empty()) + inStatementIndentStackSizeStack->pop_back(); + + if (!blockParenDepthStack->empty()) + { + parenDepth = blockParenDepthStack->back(); + blockParenDepthStack->pop_back(); + isInStatement = blockStatementStack->back(); + blockStatementStack->pop_back(); + + if (isInStatement) + blockTabCount--; + } + + closingBracketReached = true; + int headerPlace = indexOf(*headerStack, &AS_OPEN_BRACKET); + if (headerPlace != -1) + { + const string *popped = headerStack->back(); + while (popped != &AS_OPEN_BRACKET) + { + headerStack->pop_back(); + popped = headerStack->back(); + } + headerStack->pop_back(); + + if (!tempStacks->empty()) + { + vector<const string*> *temp = tempStacks->back(); + tempStacks->pop_back(); + delete temp; + } + } + + + ch = ' '; // needed due to cases such as '}else{', so that headers ('else' tn tih case) will be identified... + } + + /* + * Create a temporary snapshot of the current block's header-list in the + * uppermost inner stack in tempStacks, and clear the headerStack up to + * the begining of the block. + * Thus, the next future statement will think it comes one indent past + * the block's '{' unless it specifically checks for a companion-header + * (such as a previous 'if' for an 'else' header) within the tempStacks, + * and recreates the temporary snapshot by manipulating the tempStacks. + */ + if (!tempStacks->back()->empty()) + while (!tempStacks->back()->empty()) + tempStacks->back()->pop_back(); + while (!headerStack->empty() && headerStack->back() != &AS_OPEN_BRACKET) + { + tempStacks->back()->push_back(headerStack->back()); + headerStack->pop_back(); + } + + if (parenDepth == 0 && ch == ';') + isInStatement = false; + + previousLastLineHeader = NULL; + isInClassHeader = false; + isInQuestion = false; + + continue; + } + + + // check for preBlockStatements ONLY if not within parenthesies + // (otherwise 'struct XXX' statements would be wrongly interpreted...) + if (isWhiteSpace(prevCh) && !isInTemplate && parenDepth == 0) + { + const string *newHeader = findHeader(line, i, preBlockStatements); + if (newHeader != NULL) + { + isInClassHeader = true; + outBuffer.append(newHeader->substr(1)); + i += newHeader->length() - 1; + headerStack->push_back(newHeader); + } + } + + // Handle operators + + immediatelyPreviousAssignmentOp = NULL; + + // Check if an operator has been reached. + const string *foundAssignmentOp = findHeader(line, i, assignmentOperators, false); + if (foundAssignmentOp == &AS_RETURN) + foundAssignmentOp = findHeader(line, i, assignmentOperators, true); + const string *foundNonAssignmentOp = findHeader(line, i, nonAssignmentOperators, false); + + // Since findHeader's boundry checking was not used above, it is possible + // that both an assignment op and a non-assignment op where found, + // e.g. '>>' and '>>='. If this is the case, treat the LONGER one as the + // found operator. + if (foundAssignmentOp != NULL && foundNonAssignmentOp != NULL) + if (foundAssignmentOp->length() < foundNonAssignmentOp->length()) + foundAssignmentOp = NULL; + else + foundNonAssignmentOp = NULL; + + if (foundNonAssignmentOp != NULL) + { + if (foundNonAssignmentOp->length() > 1) + { + outBuffer.append(foundNonAssignmentOp->substr(1)); + i += foundNonAssignmentOp->length() - 1; + } + } + + else if (foundAssignmentOp != NULL) + { + if (foundAssignmentOp->length() > 1) + { + outBuffer.append(foundAssignmentOp->substr(1)); + i += foundAssignmentOp->length() - 1; + } + + if (!isInOperator && !isInTemplate && !isNonInStatementArray) + { + registerInStatementIndent(line, i, spaceTabCount, 0, false); + immediatelyPreviousAssignmentOp = foundAssignmentOp; + isInStatement = true; + } + } + + if (isInOperator) + isInOperator = false; + } + + // handle special cases of unindentation: + + /* + * if '{' doesn't follow an immediately previous '{' in the headerStack + * (but rather another header such as "for" or "if", then unindent it + * by one indentation relative to its block. + */ + + if (!lineStartsInComment + && !blockIndent + && outBuffer.length() > 0 + && outBuffer[0] == '{' + && !(lineOpeningBlocksNum > 0 && lineOpeningBlocksNum == lineClosingBlocksNum) + && !(headerStack->size() > 1 && (*headerStack)[headerStack->size()-2] == &AS_OPEN_BRACKET) + && shouldIndentBrackettedLine) + --tabCount; + + else if (!lineStartsInComment + && outBuffer.length() > 0 + && outBuffer[0] == '}' + && shouldIndentBrackettedLine) + --tabCount; + + // correctly indent one-line-blocks... + else if (!lineStartsInComment + && outBuffer.length() > 0 + && lineOpeningBlocksNum > 0 + && lineOpeningBlocksNum == lineClosingBlocksNum + && previousLineProbationTab) + --tabCount; //lineOpeningBlocksNum - (blockIndent ? 1 : 0); + + if (tabCount < 0) + tabCount = 0; + + // take care of extra bracket indentatation option... + if (bracketIndent && outBuffer.length() > 0 && shouldIndentBrackettedLine) + if (outBuffer[0] == '{' || outBuffer[0] == '}') + tabCount++; + + + if (isInDefine) + { + if (outBuffer[0] == '#') + { + string preproc = trim(string(outBuffer.c_str() + 1)); + if (preproc.compare(0, 6, "define") == 0) + { + if (!inStatementIndentStack->empty() + && inStatementIndentStack->back() > 0) + { + defineTabCount = tabCount; + } + else + { + defineTabCount = tabCount - 1; + tabCount--; + } + } + } + + tabCount -= defineTabCount; + } + + if (tabCount < 0) + tabCount = 0; + if (lineCommentNoBeautify || blockCommentNoBeautify) + tabCount = spaceTabCount = 0; + + // finally, insert indentations into begining of line + + prevFinalLineSpaceTabCount = spaceTabCount; + prevFinalLineTabCount = tabCount; + + if (shouldForceTabIndentation) + { + tabCount += spaceTabCount / indentLength; + spaceTabCount = spaceTabCount % indentLength; + } + + outBuffer = preLineWS(spaceTabCount, tabCount) + outBuffer; + + if (lastLineHeader != NULL) + previousLastLineHeader = lastLineHeader; + + return outBuffer; +} + + +string ASBeautifier::preLineWS(int spaceTabCount, int tabCount) +{ + string ws; + + for (int i = 0; i < tabCount; i++) + ws += indentString; + + while ((spaceTabCount--) > 0) + ws += string(" "); + + return ws; + +} + +/** + * register an in-statement indent. + */ +void ASBeautifier::registerInStatementIndent(const string &line, int i, int spaceTabCount, + int minIndent, bool updateParenStack) +{ + int inStatementIndent; + int remainingCharNum = line.length() - i; + int nextNonWSChar = getNextProgramCharDistance(line, i); + + // if indent is around the last char in the line, indent instead 2 spaces from the previous indent + if (nextNonWSChar == remainingCharNum) + { + int previousIndent = spaceTabCount; + if (!inStatementIndentStack->empty()) + previousIndent = inStatementIndentStack->back(); + + inStatementIndentStack->push_back(/*2*/ indentLength + previousIndent); + if (updateParenStack) + parenIndentStack->push_back(previousIndent); + return; + } + + if (updateParenStack) + parenIndentStack->push_back(i + spaceTabCount); + + inStatementIndent = i + nextNonWSChar + spaceTabCount; + + if (i + nextNonWSChar < minIndent) + inStatementIndent = minIndent + spaceTabCount; + + if (i + nextNonWSChar > maxInStatementIndent) + inStatementIndent = indentLength * 2 + spaceTabCount; + + if (!inStatementIndentStack->empty() && + inStatementIndent < inStatementIndentStack->back()) + inStatementIndent = inStatementIndentStack->back(); + + if (isNonInStatementArray) + inStatementIndent = 0; + + inStatementIndentStack->push_back(inStatementIndent); +} + +/** + * get distance to the next non-white sspace, non-comment character in the line. + * if no such character exists, return the length remaining to the end of the line. + */ +int ASBeautifier::getNextProgramCharDistance(const string &line, int i) +{ + bool inComment = false; + int remainingCharNum = line.length() - i; + int charDistance; + char ch; + + for (charDistance = 1; charDistance < remainingCharNum; charDistance++) + { + ch = line[i + charDistance]; + if (inComment) + { + if (line.compare(i + charDistance, 2, "*/") == 0) + { + charDistance++; + inComment = false; + } + continue; + } + else if (isWhiteSpace(ch)) + continue; + else if (ch == '/') + { + if (line.compare(i + charDistance, 2, "//") == 0) + return remainingCharNum; + else if (line.compare(i + charDistance, 2, "/*") == 0) + { + charDistance++; + inComment = true; + } + } + else + return charDistance; + } + + return charDistance; +} + + +/** + * check if a specific line position contains a header, out of several possible headers. + * + * @return a pointer to the found header. if no header was found then return NULL. + */ +const string *ASBeautifier::findHeader(const string &line, int i, const vector<const string*> &possibleHeaders, bool checkBoundry) +{ + int maxHeaders = possibleHeaders.size(); + // const string *header = NULL; + int p; + + for (p = 0; p < maxHeaders; p++) + { + const string *header = possibleHeaders[p]; + + if (line.compare(i, header->length(), header->c_str()) == 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 headerEnd = i + header->length(); + char startCh = (*header)[0]; // first char of header + char endCh = 0; // char just after header + char prevCh = 0; // char just before header + + if (headerEnd < lineLength) + { + endCh = line[headerEnd]; + } + if (i > 0) + { + prevCh = line[i-1]; + } + + if (!checkBoundry) + { + return header; + } + else if (prevCh != 0 + && isLegalNameChar(startCh) + && isLegalNameChar(prevCh)) + { + return NULL; + } + else if (headerEnd >= lineLength + || !isLegalNameChar(startCh) + || !isLegalNameChar(endCh)) + { + return header; + } + else + { + return NULL; + } + } + } + + return NULL; +} + +/** + * find the index number of a string element in a container of strings + * + * @return the index number of element in the ocntainer. -1 if element not found. + * @param container a vector of strings. + * @param element the element to find . + */ +int ASBeautifier::indexOf(vector<const string*> &container, const string *element) +{ + vector<const string*>::const_iterator where; + + where = find(container.begin(), container.end(), element); + if (where == container.end()) + return -1; + else + return (int) (where - container.begin()); +} + +/** + * trim removes the white space surrounding a line. + * + * @return the trimmed line. + * @param str the line to trim. + */ +string ASBeautifier::trim(const string &str) +{ + + int start = 0; + int end = str.length() - 1; + + while (start < end && isWhiteSpace(str[start])) + start++; + + while (start <= end && isWhiteSpace(str[end])) + end--; + + string returnStr(str, start, end + 1 - start); + return returnStr; +} + +/** +* peek at the next unread character. +* +* @return the next unread character. +* @param line the line to check. +* @param i the current char position on the line. +*/ +char ASBeautifier::peekNextChar(string &line, int i) +{ + char ch = ' '; + size_t peekNum = line.find_first_not_of(" \t", i + 1); + + if (peekNum == string::npos) + return ch; + + ch = line[peekNum]; + + return ch; +} + + +} // end namespace astyle + 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 diff --git a/lib/astyle/ASFormatter.cpp b/lib/astyle/ASFormatter.cpp new file mode 100644 index 00000000..eb418760 --- /dev/null +++ b/lib/astyle/ASFormatter.cpp @@ -0,0 +1,2197 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * + * ASFormatter.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. + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + */ + +#include "astyle.h" + +#include <algorithm> +#include <fstream> +#include <iostream> +#ifdef __VMS +#include <assert> +#else +#include <cassert> +#endif + +// can trace only if NDEBUG is not defined +#ifndef NDEBUG +// #define TRACEunpad +// #define TRACEcomment +// #define TRACEheader +// #define TRACEbracket +// #define TRACEarray +#if defined(TRACEunpad) || defined(TRACEcomment) || defined(TRACEheader) \ +|| defined(TRACEbracket) || defined(TRACEarray) +ofstream *traceOutF; +#define TRACEF +#endif +#endif + +#ifdef TRACEunpad +#define TRunpad(a,b,c) if(b > 0 || c > 0) *traceOutF << outLineNumber << " " << b << a << c << endl +#else +#define TRunpad(a,b,c) ((void)0) +#endif + +#ifdef TRACEcomment +#define TRcomment(a) *traceOutF << outLineNumber << " " << a << endl +#else +#define TRcomment(a) ((void)0) +#endif + +#ifdef TRACEheader +#define TRxtra(a) *traceOutF << outLineNumber << " " << a << endl +#else +#define TRxtra(a) ((void)0) +#endif + +#ifdef TRACEbracket +#define TRbracket(a) *traceOutF << outLineNumber << " " << a << endl +#else +#define TRbracket(a) ((void)0) +#endif + +#ifdef TRACEarray +#define TRarray(a) *traceOutF << outLineNumber << " " << a << endl +#else +#define TRarray(a) ((void)0) +#endif + +#define INIT_CONTAINER(container, value) {if ( (container) != NULL ) delete (container); (container) = (value); } +#define DELETE_CONTAINER(container) {if ( (container) != NULL ) delete (container); } +#define IS_A(a,b) ( ((a) & (b)) == (b)) + +using namespace std; + +namespace astyle +{ +vector<const string*> ASFormatter::headers; +vector<const string*> ASFormatter::nonParenHeaders; +vector<const string*> ASFormatter::preDefinitionHeaders; +vector<const string*> ASFormatter::preCommandHeaders; +vector<const string*> ASFormatter::operators; +vector<const string*> ASFormatter::assignmentOperators; +vector<const string*> ASFormatter::castOperators; + +/** + * Constructor of ASFormatter + */ +ASFormatter::ASFormatter() +{ + preBracketHeaderStack = NULL; + bracketTypeStack = NULL; + parenStack = NULL; + lineCommentNoIndent = false; + sourceIterator = NULL; + bracketFormatMode = NONE_MODE; + shouldPadOperators = false; + shouldPadParensOutside = false; + shouldPadParensInside = false; + shouldUnPadParens = false; + shouldBreakOneLineBlocks = true; + shouldBreakOneLineStatements = true; + shouldConvertTabs = false; + shouldBreakBlocks = false; + shouldBreakClosingHeaderBlocks = false; + shouldBreakClosingHeaderBrackets = false; + shouldBreakElseIfs = false; +#ifdef TRACEF + // create a trace text file + string filename = "tracef.txt"; + char* env = getenv("HOME"); + if (env != NULL) + filename = string(env) + string("/tracef.txt"); + else + { + env = getenv("USERPROFILE"); + if (env != NULL) + filename = string(env) + string("\\My Documents\\tracef.txt"); + else + { + cout << "\nCould not open tracef.txt\n" << endl; + exit(1); + } + } + traceOutF = new ofstream(filename.c_str()); +#endif +} + +/** + * Destructor of ASFormatter + */ +ASFormatter::~ASFormatter() +{ + DELETE_CONTAINER(preBracketHeaderStack); +#ifdef TRACEF + delete traceOutF; +#endif +} + +/** + * initialization of static data of ASFormatter. + */ +void ASFormatter::staticInit() +{ + static int formatterFileType = 9; // initialized with an invalid type + + if (fileType == formatterFileType) // don't build unless necessary + return; + + formatterFileType = fileType; + + headers.clear(); + nonParenHeaders.clear(); + assignmentOperators.clear(); + operators.clear(); + preDefinitionHeaders.clear(); + preCommandHeaders.clear(); + castOperators.clear(); + + ASResource::buildHeaders(headers, fileType); + ASResource::buildNonParenHeaders(nonParenHeaders, fileType); + ASResource::buildAssignmentOperators(assignmentOperators); + ASResource::buildOperators(operators); + ASResource::buildPreDefinitionHeaders(preDefinitionHeaders); + ASResource::buildPreCommandHeaders(preCommandHeaders); + ASResource::buildCastOperators(castOperators); +} + +/** + * initialize the ASFormatter. + * + * init() should be called every time a ASFormatter object is to start + * formatting a NEW source file. + * init() recieves a pointer to a DYNAMICALLY CREATED ASSourceIterator object + * that will be used to iterate through the source code. This object will be + * deleted during the ASFormatter's destruction, and thus should not be + * deleted elsewhere. + * + * @param iter a pointer to the DYNAMICALLY CREATED ASSourceIterator object. + */ +void ASFormatter::init(ASSourceIterator *si) +{ + staticInit(); + + ASBeautifier::init(si); + ASEnhancer::init(ASBeautifier::getIndentLength(), + ASBeautifier::getIndentString(), + ASBeautifier::getCStyle(), + ASBeautifier::getJavaStyle(), + ASBeautifier::getSharpStyle(), + ASBeautifier::getCaseIndent(), + ASBeautifier::getEmptyLineFill()); + sourceIterator = si; + + INIT_CONTAINER(preBracketHeaderStack, new vector<const string*>); + INIT_CONTAINER(bracketTypeStack, new vector<BracketType>); + bracketTypeStack->push_back(NULL_TYPE); + INIT_CONTAINER(parenStack, new vector<int>); + parenStack->push_back(0); + + currentHeader = NULL; + currentLine = string(""); + readyFormattedLine = string(""); + formattedLine = ""; + currentChar = ' '; + previousChar = ' '; + previousCommandChar = ' '; + previousNonWSChar = ' '; + quoteChar = '"'; + charNum = 0; + spacePadNum = 0; + previousReadyFormattedLineLength = string::npos; + templateDepth = 0; + previousBracketType = NULL_TYPE; + previousOperator = NULL; + + isVirgin = true; + isInLineComment = false; + isInComment = false; + isInPreprocessor = false; + doesLineStartComment = false; + isInQuote = false; + isSpecialChar = false; + isNonParenHeader = true; + foundNamespaceHeader = false; + foundClassHeader = false; + foundPreDefinitionHeader = false; + foundPreCommandHeader = false; + foundCastOperator = false; + foundQuestionMark = false; + isInLineBreak = false; + endOfCodeReached = false; + isLineReady = false; + isPreviousBracketBlockRelated = true; + isInPotentialCalculation = false; + shouldReparseCurrentChar = false; + passedSemicolon = false; + passedColon = false; + isInTemplate = false; + isInBlParen = false; + shouldBreakLineAfterComments = false; + isImmediatelyPostComment = false; + isImmediatelyPostLineComment = false; + isImmediatelyPostEmptyBlock = false; + isImmediatelyPostPreprocessor = false; + + isPrependPostBlockEmptyLineRequested = false; + isAppendPostBlockEmptyLineRequested = false; + prependEmptyLine = false; + appendOpeningBracket = false; + + foundClosingHeader = false; + previousReadyFormattedLineLength = 0; + + isImmediatelyPostHeader = false; + isInHeader = false; +#ifdef TRACEF + // fileName will be empty if ASTYLE_LIB is defined + if (fileName.empty()) + *traceOutF << "new file" << endl; + else + *traceOutF << fileName << endl; +#endif +} + +/** + * get the next formatted line. + * + * @return formatted line. + */ + +string ASFormatter::nextLine() +{ + // these are reset with each new line + const string *newHeader; + bool isInVirginLine = isVirgin; + isCharImmediatelyPostComment = false; + isPreviousCharPostComment = false; + isCharImmediatelyPostLineComment = false; + isCharImmediatelyPostOpenBlock = false; + isCharImmediatelyPostCloseBlock = false; + isCharImmediatelyPostTemplate = false; + + while (!isLineReady) + { + if (shouldReparseCurrentChar) + shouldReparseCurrentChar = false; + else if (!getNextChar()) + { + breakLine(); + return beautify(readyFormattedLine); + } + else // stuff to do when reading a new character... + { + // make sure that a virgin '{' at the begining ofthe file will be treated as a block... + if (isInVirginLine && currentChar == '{') + previousCommandChar = '{'; + isPreviousCharPostComment = isCharImmediatelyPostComment; + isCharImmediatelyPostComment = false; + isCharImmediatelyPostTemplate = false; + } + + //if (inLineNumber >= 185) + // int x = 1; + + if (isInLineComment) + { + appendCurrentChar(); + + // explicitely break a line when a line comment's end is found. + if (charNum + 1 == (int) currentLine.length()) + { + isInLineBreak = true; + isInLineComment = false; + isImmediatelyPostLineComment = true; + currentChar = 0; //make sure it is a neutral char. + } + continue; + } + else if (isInComment) + { + if (isSequenceReached("*/")) + { + isInComment = false; + isImmediatelyPostComment = true; + appendSequence(AS_CLOSE_COMMENT); + goForward(1); + } + else + appendCurrentChar(); + + continue; + } + + // not in line comment or comment + + else if (isInQuote) + { + if (isSpecialChar) + { + isSpecialChar = false; + appendCurrentChar(); + } + else if (currentChar == '\\') + { + isSpecialChar = true; + appendCurrentChar(); + } + else if (quoteChar == currentChar) + { + isInQuote = false; + appendCurrentChar(); + } + else + { + appendCurrentChar(); + } + + continue; + } + + // handle white space - needed to simplify the rest. + if (isWhiteSpace(currentChar) || isInPreprocessor) + { + appendCurrentChar(); + continue; + } + + /* not in MIDDLE of quote or comment or white-space of any type ... */ + + if (isSequenceReached("//")) + { + if (currentLine[charNum+2] == '\xf2') // check for windows line marker + isAppendPostBlockEmptyLineRequested = false; + isInLineComment = true; + // do not indent if in column 1 or 2 + if (lineCommentNoIndent == false) + { + if (charNum == 0) + lineCommentNoIndent = true; + else if (charNum == 1 && currentLine[0] == ' ') + lineCommentNoIndent = true; + } + // move comment if spaces were added or deleted + if (lineCommentNoIndent == false && spacePadNum != 0) + adjustComments(); + formattedLineCommentNum = formattedLine.length(); + appendSequence(AS_OPEN_LINE_COMMENT); + goForward(1); + // explicitely break a line when a line comment's end is found. + if (charNum + 1 == (int) currentLine.length()) + { + isInLineBreak = true; + isInLineComment = false; + isImmediatelyPostLineComment = true; + currentChar = 0; //make sure it is a neutral char. + } + continue; + } + else if (isSequenceReached("/*")) + { + isInComment = true; + if (spacePadNum != 0) + adjustComments(); + formattedLineCommentNum = formattedLine.length(); + appendSequence(AS_OPEN_COMMENT); + goForward(1); + continue; + } + else if (currentChar == '"' || currentChar == '\'') + { + isInQuote = true; + quoteChar = currentChar; + appendCurrentChar(); + continue; + } + + /* not in quote or comment or white-space of any type ... */ + + // check if in preprocessor + // ** isInPreprocessor will be automatically reset at the begining + // of a new line in getnextChar() + if (currentChar == '#') + { + isInPreprocessor = true; + appendCurrentChar(); + continue; + } + + /* not in preprocessor ... */ + + if (isImmediatelyPostComment) + { + isImmediatelyPostComment = false; + isCharImmediatelyPostComment = true; + } + + if (isImmediatelyPostLineComment) + { + isImmediatelyPostLineComment = false; + isCharImmediatelyPostLineComment = true; + } + + if (shouldBreakLineAfterComments) + { + shouldBreakLineAfterComments = false; + shouldReparseCurrentChar = true; + breakLine(); + continue; + } + + // reset isImmediatelyPostHeader information + if (isImmediatelyPostHeader) + { + isImmediatelyPostHeader = false; + + // Make sure headers are broken from their succeeding blocks + // (e.g. + // if (isFoo) DoBar(); + // should become + // if (isFoo) + // DoBar; + // ) + // But treat else if() as a special case which should not be broken! + if (shouldBreakOneLineStatements) + { + // if may break 'else if()'s, then simply break the line + + if (shouldBreakElseIfs) + isInLineBreak = true; + } + } + + if (passedSemicolon) // need to break the formattedLine + { + passedSemicolon = false; + if (parenStack->back() == 0 && currentChar != ';') // allow ;; + { + // does a one-line statement have ending comments? + if (IS_A(bracketTypeStack->back(), SINGLE_LINE_TYPE)) + { + size_t blockEnd = currentLine.rfind(AS_CLOSE_BRACKET); + assert(blockEnd != string::npos); + // move ending comments to this formattedLine + if (isBeforeLineEndComment(blockEnd)) + { + size_t commentStart = currentLine.find_first_not_of(" \t", blockEnd + 1); + assert(commentStart != string::npos); + assert((currentLine.compare(commentStart, 2, "//") == 0) + || (currentLine.compare(commentStart, 2, "/*") == 0)); + size_t commentLength = currentLine.length() - commentStart; + int tabCount = getIndentLength(); + appendSpacePad(); + for (int i=1; i<tabCount; i++) + formattedLine.append(1, ' '); + formattedLine.append(currentLine, commentStart, commentLength); + currentLine.erase(commentStart, commentLength); + } + } + shouldReparseCurrentChar = true; + isInLineBreak = true; + continue; + } + } + + if (passedColon) + { + passedColon = false; + if (parenStack->back() == 0 && !isBeforeComment()) + { + shouldReparseCurrentChar = true; + isInLineBreak = true; + continue; + } + } + + // Check if in template declaration, e.g. foo<bar> or foo<bar,fig> + // If so, set isInTemplate to true + if (!isInTemplate && currentChar == '<') + { + int maxTemplateDepth = 0; + templateDepth = 0; + const string *oper; + for (size_t i = charNum; + i < currentLine.length(); + i += (oper ? oper->length() : 1)) + { + oper = ASBeautifier::findHeader(currentLine, i, operators); + + if (oper == &AS_LS) + { + templateDepth++; + maxTemplateDepth++; + } + else if (oper == &AS_GR) + { + templateDepth--; + if (templateDepth == 0) + { + // this is a template! + isInTemplate = true; + templateDepth = maxTemplateDepth; + break; + } + } + else if (oper == &AS_COMMA // comma, e.g. A<int, char> + || oper == &AS_BIT_AND // reference, e.g. A<int&> + || oper == &AS_MULT // pointer, e.g. A<int*> + || oper == &AS_COLON_COLON) // ::, e.g. std::string + { + continue; + } + else if (!isLegalNameChar(currentLine[i]) && !isWhiteSpace(currentLine[i])) + { + // this is not a template -> leave... + isInTemplate = false; + break; + } + } + } + + // handle parenthesies + if (currentChar == '(' || currentChar == '[' || (isInTemplate && currentChar == '<')) + { + parenStack->back()++; + if (currentChar == '[') + isInBlParen = true; + } + else if (currentChar == ')' || currentChar == ']' || (isInTemplate && currentChar == '>')) + { + parenStack->back()--; + if (isInTemplate && currentChar == '>') + { + templateDepth--; + if (templateDepth == 0) + { + isInTemplate = false; + isCharImmediatelyPostTemplate = true; + } + } + + // check if this parenthesis closes a header, e.g. if (...), while (...) + if (isInHeader && parenStack->back() == 0) + { + isInHeader = false; + isImmediatelyPostHeader = true; + } + if (currentChar == ']') + isInBlParen = false; + if (currentChar == ')') + foundCastOperator = false; + } + + // handle brackets + if (currentChar == '{' || currentChar == '}') + { + if (currentChar == '{') + { + BracketType newBracketType = getBracketType(); + foundNamespaceHeader = false; + foundClassHeader = false; + foundPreDefinitionHeader = false; + foundPreCommandHeader = false; + isInPotentialCalculation = false; + + bracketTypeStack->push_back(newBracketType); + preBracketHeaderStack->push_back(currentHeader); + currentHeader = NULL; + + isPreviousBracketBlockRelated = !IS_A(newBracketType, ARRAY_TYPE); + } + + // this must be done before the bracketTypeStack is popped + BracketType bracketType = bracketTypeStack->back(); + bool isOpeningArrayBracket = (IS_A(bracketType, ARRAY_TYPE) + && bracketTypeStack->size() >= 2 + && !IS_A((*bracketTypeStack)[bracketTypeStack->size()-2], ARRAY_TYPE) + ); + + if (currentChar == '}') + { + // if a request has been made to append a post block empty line, + // but the block exists immediately before a closing bracket, + // then there is not need for the post block empty line. + // + isAppendPostBlockEmptyLineRequested = false; + + if (!bracketTypeStack->empty()) + { + previousBracketType = bracketTypeStack->back(); + bracketTypeStack->pop_back(); + isPreviousBracketBlockRelated = !IS_A(bracketType, ARRAY_TYPE); + } + + if (!preBracketHeaderStack->empty()) + { + currentHeader = preBracketHeaderStack->back(); + preBracketHeaderStack->pop_back(); + } + else + currentHeader = NULL; + } + + // format brackets + if (IS_A(bracketType, ARRAY_TYPE)) + formatArrayBrackets(bracketType, isOpeningArrayBracket); + else + formatBrackets(bracketType); + continue; + } + + if (((previousCommandChar == '{' && isPreviousBracketBlockRelated) + || (previousCommandChar == '}' + && bracketFormatMode != NONE_MODE + && !isImmediatelyPostEmptyBlock + && isPreviousBracketBlockRelated + && !isPreviousCharPostComment // Fixes wrongly appended newlines after '}' immediately after comments + && peekNextChar() != ' ' + && !IS_A(previousBracketType, DEFINITION_TYPE) + && !(ASBeautifier::isJavaStyle && currentChar == ')')) + && !IS_A(bracketTypeStack->back(), DEFINITION_TYPE)) + && (shouldBreakOneLineBlocks + || !IS_A(bracketTypeStack->back(), SINGLE_LINE_TYPE))) + { + isCharImmediatelyPostOpenBlock = (previousCommandChar == '{'); + isCharImmediatelyPostCloseBlock = (previousCommandChar == '}'); + + //if (bracketFormatMode != NONE_MODE) + //{ + previousCommandChar = ' '; + isInLineBreak = true; + //} + } + + // reset block handling flags + isImmediatelyPostEmptyBlock = false; + + // look for headers + if (!isInTemplate) + { + if ((newHeader = findHeader(headers)) != NULL) + { + foundClosingHeader = false; + const string *previousHeader; + + // recognize closing headers of do..while, if..else, try..catch..finally + if ((newHeader == &AS_ELSE && currentHeader == &AS_IF) + || (newHeader == &AS_WHILE && currentHeader == &AS_DO) + || (newHeader == &AS_CATCH && currentHeader == &AS_TRY) + || (newHeader == &AS_CATCH && currentHeader == &AS_CATCH) + || (newHeader == &AS_FINALLY && currentHeader == &AS_TRY) + || (newHeader == &AS_FINALLY && currentHeader == &AS_CATCH)) + foundClosingHeader = true; + + previousHeader = currentHeader; + currentHeader = newHeader; + + // If in ATTACH or LINUX bracket modes, attach closing headers (e.g. 'else', 'catch') + // to their preceding bracket, + // But do not perform the attachment if the shouldBreakClosingHeaderBrackets is set! + if (!shouldBreakClosingHeaderBrackets + && foundClosingHeader + && (bracketFormatMode == ATTACH_MODE || bracketFormatMode == BDAC_MODE) + && (shouldBreakOneLineBlocks || !IS_A(previousBracketType, SINGLE_LINE_TYPE)) + && previousNonWSChar == '}') + { + spacePadNum = 0; // don't count as padding + + size_t firstChar = formattedLine.find_first_not_of(" \t"); + if (firstChar != string::npos) // if a blank line does not preceed this + { + isInLineBreak = false; + appendSpacePad(); + } + + if (shouldBreakBlocks) + isAppendPostBlockEmptyLineRequested = false; + } + + // If NONE bracket mode, leave closing headers as they are (e.g. 'else', 'catch') + if (foundClosingHeader && bracketFormatMode == NONE_MODE && previousCommandChar == '}') + { + if (lineBeginsWith('}')) // is closing bracket broken? + { + isInLineBreak = false; + appendSpacePad(); + } + + if (shouldBreakBlocks) + isAppendPostBlockEmptyLineRequested = false; + } + + if (foundClosingHeader && bracketFormatMode == BREAK_MODE && previousCommandChar == '}') + breakLine(); + + //Check if a template definition as been reached, e.g. template<class A> + //if (newHeader == &AS_TEMPLATE) + //{ + // isInTemplate = true; + //} + + // check if the found header is non-paren header + isNonParenHeader = (find(nonParenHeaders.begin(), nonParenHeaders.end(), + newHeader) != nonParenHeaders.end()); + + appendSequence(*currentHeader); + goForward(currentHeader->length() - 1); + // if a paren-header is found add a space after it, if needed + // this checks currentLine, appendSpacePad() checks formattedLine + if (!isNonParenHeader && charNum < (int) currentLine.length() && !isWhiteSpace(currentLine[charNum+1])) + appendSpacePad(); + + // Signal that a header has been reached + // *** But treat a closing while() (as in do...while) + // as if it where NOT a header since a closing while() + // should never have a block after it! + if (!(foundClosingHeader && currentHeader == &AS_WHILE)) + { + isInHeader = true; + if (isNonParenHeader) + { + isImmediatelyPostHeader = true; + isInHeader = false; + } + } + + if (currentHeader == &AS_IF && previousHeader == &AS_ELSE) + isInLineBreak = false; + + if (shouldBreakBlocks) + { + if (previousHeader == NULL + && !foundClosingHeader + && !isCharImmediatelyPostOpenBlock) + { + isPrependPostBlockEmptyLineRequested = true; + } + + if (currentHeader == &AS_ELSE + || currentHeader == &AS_CATCH + || currentHeader == &AS_FINALLY + || foundClosingHeader) + { + isPrependPostBlockEmptyLineRequested = false; + } + + if (shouldBreakClosingHeaderBlocks + && isCharImmediatelyPostCloseBlock) + { + isPrependPostBlockEmptyLineRequested = true; + } + + } + + continue; + } + else if ((newHeader = findHeader(preDefinitionHeaders)) != NULL + && parenStack->back() == 0) + { + if (newHeader == &AS_NAMESPACE) + foundNamespaceHeader = true; + if (newHeader == &AS_CLASS) + foundClassHeader = true; + foundPreDefinitionHeader = true; + appendSequence(*newHeader); + goForward(newHeader->length() - 1); + + if (shouldBreakBlocks) + isPrependPostBlockEmptyLineRequested = true; + + continue; + } + else if ((newHeader = findHeader(preCommandHeaders)) != NULL) + { + if (ASBeautifier::isJavaStyle + || (*newHeader == AS_CONST && previousCommandChar == ')') // 'const' member functions is a command bracket + || *newHeader == AS_EXTERN) + foundPreCommandHeader = true; + appendSequence(*newHeader); + goForward(newHeader->length() - 1); + + continue; + } + else if ((newHeader = findHeader(castOperators)) != NULL) + { + foundCastOperator = true; + appendSequence(*newHeader); + goForward(newHeader->length() - 1); + + continue; + } + + } + + if (isInLineBreak) // OK to break line here + breakLine(); + + if (previousNonWSChar == '}' || currentChar == ';') + { + if (shouldBreakOneLineStatements && currentChar == ';' + && (shouldBreakOneLineBlocks || !IS_A(bracketTypeStack->back(), SINGLE_LINE_TYPE)) + //&& (! bracketFormatMode == NONE_MODE) + ) + { + passedSemicolon = true; + } + + if (shouldBreakBlocks && currentHeader != NULL && parenStack->back() == 0) + { + isAppendPostBlockEmptyLineRequested = true; + } + + if (currentChar != ';') + currentHeader = NULL; + + foundQuestionMark = false; + foundNamespaceHeader = false; + foundClassHeader = false; + foundPreDefinitionHeader = false; + foundPreCommandHeader = false; + foundCastOperator = false; + isInPotentialCalculation = false; + isNonInStatementArray = false; + } + + if (currentChar == ':' + && shouldBreakOneLineStatements + && !foundQuestionMark // not in a ... ? ... : ... sequence + && !foundPreDefinitionHeader // not in a definition block (e.g. class foo : public bar + && previousCommandChar != ')' // not immediately after closing paren of a method header, e.g. ASFormatter::ASFormatter(...) : ASBeautifier(...) + && previousChar != ':' // not part of '::' + && peekNextChar() != ':') // not part of '::' + { + passedColon = true; + if (shouldBreakBlocks) + isPrependPostBlockEmptyLineRequested = true; + } + + if (currentChar == '?') + foundQuestionMark = true; + + // determine if this is a potential calculation + newHeader = findHeader(operators); + + if (newHeader != NULL) + { + if (!isInPotentialCalculation) + { + if (find(assignmentOperators.begin(), assignmentOperators.end(), newHeader) + != assignmentOperators.end()) + { + char peekedChar = peekNextChar(); + isInPotentialCalculation = (newHeader != &AS_RETURN + && !(newHeader == &AS_EQUAL && peekedChar == '*') + && !(newHeader == &AS_EQUAL && peekedChar == '&')); + } + } + } + else + { + // the following are not calculations + if (currentLine.compare(charNum, 3, "new") == 0 && !isLegalNameChar(currentLine[charNum+3])) + isInPotentialCalculation = false; + } + + if (shouldPadOperators && newHeader != NULL) + { + padOperators(newHeader); + continue; + } + + if ((shouldPadParensOutside || shouldPadParensInside || shouldUnPadParens) + && (currentChar == '(' || currentChar == ')')) + { + padParens(); + continue; + } + + appendCurrentChar(); + } // end of while loop * end of while loop * end of while loop * end of while loop + + // return a beautified (i.e. correctly indented) line. + + string beautifiedLine; + size_t readyFormattedLineLength = trim(readyFormattedLine).length(); + + if (prependEmptyLine // prepend a blank line before this formatted line + && readyFormattedLineLength > 0 + && previousReadyFormattedLineLength > 0) + { + isLineReady = true; // signal that a readyFormattedLine is still waiting + beautifiedLine = beautify(""); + previousReadyFormattedLineLength = 0; + } + else // format the current formatted line + { + isLineReady = false; + beautifiedLine = beautify(readyFormattedLine); + previousReadyFormattedLineLength = readyFormattedLineLength; + lineCommentNoBeautify = lineCommentNoIndent; + lineCommentNoIndent = false; + if (appendOpeningBracket) // insert bracket after this formatted line + { + appendOpeningBracket = false; + isLineReady = true; // signal that a readyFormattedLine is still waiting + readyFormattedLine = "{"; + isPrependPostBlockEmptyLineRequested = false; // next line should not be empty + } + } + + prependEmptyLine = false; + enhance(beautifiedLine); // call the enhancer function + return beautifiedLine; +} + + +/** +* check if there are any indented lines ready to be read by nextLine() +* +* @return are there any indented lines ready? +*/ +bool ASFormatter::hasMoreLines() const +{ + return !endOfCodeReached; +} + +/** + * set the bracket formatting mode. + * options: + * astyle::NONE_MODE no formatting of brackets. + * astyle::ATTACH_MODE Java, K&R style bracket placement. + * astyle::BREAK_MODE ANSI C/C++ style bracket placement. + * + * @param mode the bracket formatting mode. + */ +void ASFormatter::setBracketFormatMode(BracketMode mode) +{ + bracketFormatMode = mode; +} + +/** + * set closing header bracket breaking mode + * options: + * true brackets just before closing headers (e.g. 'else', 'catch') + * will be broken, even if standard brackets are attached. + * false closing header brackets will be treated as standard brackets. + * + * @param state the closing header bracket breaking mode. + */ +void ASFormatter::setBreakClosingHeaderBracketsMode(bool state) +{ + shouldBreakClosingHeaderBrackets = state; +} + +/** + * set 'else if()' breaking mode + * options: + * true 'else' headers will be broken from their succeeding 'if' headers. + * false 'else' headers will be attached to their succeeding 'if' headers. + * + * @param state the 'else if()' breaking mode. + */ +void ASFormatter::setBreakElseIfsMode(bool state) +{ + shouldBreakElseIfs = state; +} + +/** + * set operator padding mode. + * options: + * true statement operators will be padded with spaces around them. + * false statement operators will not be padded. + * + * @param state the padding mode. + */ +void ASFormatter::setOperatorPaddingMode(bool state) +{ + shouldPadOperators = state; +} + +/** +* set parenthesis outside padding mode. +* options: +* true statement parenthesiss will be padded with spaces around them. +* false statement parenthesiss will not be padded. +* +* @param state the padding mode. +*/ +void ASFormatter::setParensOutsidePaddingMode(bool state) +{ + shouldPadParensOutside = state; +} + +/** +* set parenthesis inside padding mode. +* options: +* true statement parenthesis will be padded with spaces around them. +* false statement parenthesis will not be padded. +* +* @param state the padding mode. +*/ +void ASFormatter::setParensInsidePaddingMode(bool state) +{ + shouldPadParensInside = state; +} + +/** +* set parenthesis unpadding mode. +* options: +* true statement parenthesis will be unpadded with spaces removed around them. +* false statement parenthesis will not be unpadded. +* +* @param state the padding mode. +*/ +void ASFormatter::setParensUnPaddingMode(bool state) +{ + shouldUnPadParens = state; +} + +/** + * set option to break/not break one-line blocks + * + * @param state true = break, false = don't break. + */ +void ASFormatter::setBreakOneLineBlocksMode(bool state) +{ + shouldBreakOneLineBlocks = state; +} + +/** + * set option to break/not break lines consisting of multiple statements. + * + * @param state true = break, false = don't break. + */ +void ASFormatter::setSingleStatementsMode(bool state) +{ + shouldBreakOneLineStatements = state; +} + +/** + * set option to convert tabs to spaces. + * + * @param state true = convert, false = don't convert. + */ +void ASFormatter::setTabSpaceConversionMode(bool state) +{ + shouldConvertTabs = state; +} + + +/** + * set option to break unrelated blocks of code with empty lines. + * + * @param state true = convert, false = don't convert. + */ +void ASFormatter::setBreakBlocksMode(bool state) +{ + shouldBreakBlocks = state; +} + +/** + * set option to break closing header blocks of code (such as 'else', 'catch', ...) with empty lines. + * + * @param state true = convert, false = don't convert. + */ +void ASFormatter::setBreakClosingHeaderBlocksMode(bool state) +{ + shouldBreakClosingHeaderBlocks = state; +} + +/** + * jump over several characters. + * + * @param i the number of characters to jump over. + */ +void ASFormatter::goForward(int i) +{ + while (--i >= 0) + getNextChar(); +} + +/** +* peek at the next unread character. +* +* @return the next unread character. +*/ +char ASFormatter::peekNextChar() const +{ + char ch = ' '; + size_t peekNum = currentLine.find_first_not_of(" \t", charNum + 1); + + if (peekNum == string::npos) + return ch; + + ch = currentLine[peekNum]; + +// if (shouldConvertTabs && ch == '\t') +// ch = ' '; + + return ch; +} + +/** +* check if current placement is before a comment or line-comment +* +* @return is before a comment or line-comment. +*/ +bool ASFormatter::isBeforeComment() const +{ + bool foundComment = false; + size_t peekNum = currentLine.find_first_not_of(" \t", charNum + 1); + + if (peekNum == string::npos) + return foundComment; + + foundComment = (currentLine.compare(peekNum, 2, "/*") == 0 + || currentLine.compare(peekNum, 2, "//") == 0); + + return foundComment; +} + +/** +* check if current placement is before a comment or line-comment +* if a block comment it must be at the end of the line +* +* @return is before a comment or line-comment. +*/ +bool ASFormatter::isBeforeLineEndComment(int startPos) const +{ + bool foundLineEndComment = false; + size_t peekNum = currentLine.find_first_not_of(" \t", startPos + 1); + + if (peekNum != string::npos) + { + if (currentLine.compare(peekNum, 2, "//") == 0) + foundLineEndComment = true; + else if (currentLine.compare(peekNum, 2, "/*") == 0) + { + // comment must be closed on this line with nothing after it + size_t endNum = currentLine.find("*/", peekNum + 2); + if (endNum != string::npos) + if (currentLine.find_first_not_of(" \t", endNum + 2) == string::npos) + foundLineEndComment = true; + } + } + return foundLineEndComment; +} + + +/** +* get the next character, increasing the current placement in the process. +* the new character is inserted into the variable currentChar. +* +* @return whether succeded to recieve the new character. +*/ +bool ASFormatter::getNextChar() +{ + isInLineBreak = false; + previousChar = currentChar; + + if (!isWhiteSpace(currentChar)) + { + previousNonWSChar = currentChar; + if (!isInComment && !isInLineComment && !isInQuote + && !isImmediatelyPostComment + && !isImmediatelyPostLineComment + && !isSequenceReached("/*") + && !isSequenceReached("//")) + previousCommandChar = previousNonWSChar; + } + + int currentLineLength = currentLine.length(); + + if (charNum + 1 < currentLineLength + && (!isWhiteSpace(peekNextChar()) || isInComment || isInLineComment)) + { + currentChar = currentLine[++charNum]; + + if (shouldConvertTabs && currentChar == '\t') + currentChar = ' '; + + return true; + } + else // end of line has been reached + { + if (sourceIterator->hasMoreLines()) + { + currentLine = sourceIterator->nextLine(); + spacePadNum = 0; + inLineNumber++; + + if (currentLine.length() == 0) + { + currentLine = string(" "); // a null is inserted if this is not done + } + + // unless reading in the first line of the file, + // break a new line. + if (!isVirgin) + isInLineBreak = true; + else + isVirgin = false; + + if (isInLineComment) + isImmediatelyPostLineComment = true; + isInLineComment = false; + + // check if is in preprocessor before line trimming + isImmediatelyPostPreprocessor = isInPreprocessor; + if (previousNonWSChar != '\\') + isInPreprocessor = false; + + trimNewLine(); + currentChar = currentLine[charNum]; + + if (shouldConvertTabs && currentChar == '\t') + currentChar = ' '; + + return true; + } + else + { + endOfCodeReached = true; + return false; + } + } +} + +/** +* jump over the leading white space in the current line, +* IF the line does not begin a comment or is in a preprocessor definition. +*/ +void ASFormatter::trimNewLine() +{ + int len = currentLine.length(); + charNum = 0; + + if (isInComment || isInPreprocessor) + return; + + while (isWhiteSpace(currentLine[charNum]) && charNum + 1 < len) + ++charNum; + + doesLineStartComment = false; + if (isSequenceReached("/*")) + { + charNum = 0; + doesLineStartComment = true; + } +} + +/** + * append a character to the current formatted line. + * Unless disabled (via canBreakLine == false), first check if a + * line-break has been registered, and if so break the + * formatted line, and only then append the character into + * the next formatted line. + * + * @param ch the character to append. + * @param canBreakLine if true, a registered line-break + */ +void ASFormatter::appendChar(char ch, bool canBreakLine) +{ + if (canBreakLine && isInLineBreak) + breakLine(); + formattedLine.append(1, ch); +} + +/** + * append a string sequence to the current formatted line. + * Unless disabled (via canBreakLine == false), first check if a + * line-break has been registered, and if so break the + * formatted line, and only then append the sequence into + * the next formatted line. + * + * @param sequence the sequence to append. + * @param canBreakLine if true, a registered line-break + */ +void ASFormatter::appendSequence(const string &sequence, bool canBreakLine) +{ + if (canBreakLine && isInLineBreak) + breakLine(); + formattedLine.append(sequence); +} + +/** + * append a space to the current formattedline, UNLESS the + * last character is already a white-space character. + */ +void ASFormatter::appendSpacePad() +{ + int len = formattedLine.length(); + if (len > 0 && !isWhiteSpace(formattedLine[len-1])) + { + formattedLine.append(1, ' '); + spacePadNum++; + } +} + +/** + * append a space to the current formattedline, UNLESS the + * next character is already a white-space character. + */ +void ASFormatter::appendSpaceAfter() +{ + int len = currentLine.length(); + if (charNum + 1 < len && !isWhiteSpace(currentLine[charNum+1])) + { + formattedLine.append(1, ' '); + spacePadNum++; + } +} + +/** + * register a line break for the formatted line. + */ +void ASFormatter::breakLine() +{ + isLineReady = true; + isInLineBreak = false; + spacePadNum = 0; + formattedLineCommentNum = string::npos; + + // queue an empty line prepend request if one exists + prependEmptyLine = isPrependPostBlockEmptyLineRequested; + + readyFormattedLine = formattedLine; + if (isAppendPostBlockEmptyLineRequested) + { + isAppendPostBlockEmptyLineRequested = false; + isPrependPostBlockEmptyLineRequested = true; + } + else + { + isPrependPostBlockEmptyLineRequested = false; + } + + formattedLine = ""; +} + +/** + * check if the currently reached open-bracket (i.e. '{') + * opens a: + * - a definition type block (such as a class or namespace), + * - a command block (such as a method block) + * - a static array + * this method takes for granted that the current character + * is an opening bracket. + * + * @return the type of the opened block. + */ +BracketType ASFormatter::getBracketType() const +{ + BracketType returnVal; + + if (foundPreDefinitionHeader) + { + returnVal = DEFINITION_TYPE; + if (foundNamespaceHeader) + returnVal = (BracketType)(returnVal | NAMESPACE_TYPE); + else if (foundClassHeader) + returnVal = (BracketType)(returnVal | CLASS_TYPE); + } + else + { + bool isCommandType = false; + + if (previousNonWSChar != '=') + isCommandType = (foundPreCommandHeader + || (currentHeader != NULL && isNonParenHeader) + || (previousCommandChar == ')') + || (previousCommandChar == ':' && !foundQuestionMark) + || (previousCommandChar == ';') + || ((previousCommandChar == '{' || previousCommandChar == '}') + && isPreviousBracketBlockRelated)); + + returnVal = (isCommandType ? COMMAND_TYPE : ARRAY_TYPE); + } + + if (isOneLineBlockReached()) + returnVal = (BracketType)(returnVal | SINGLE_LINE_TYPE); + + TRbracket(returnVal); + return returnVal; +} + +/** + * check if the currently reached '*' or '&' character is + * a pointer-or-reference symbol, or another operator. + * this method takes for granted that the current character + * is either a '*' or '&'. + * + * @return whether current character is a reference-or-pointer + */ +bool ASFormatter::isPointerOrReference() const +{ + bool isPR; + isPR = (!isInPotentialCalculation + || IS_A(bracketTypeStack->back(), DEFINITION_TYPE) + || (!isLegalNameChar(previousNonWSChar) + && previousNonWSChar != ')' + && previousNonWSChar != ']') + ); + + if (!isPR) + { + char nextChar = peekNextChar(); + isPR |= (!isWhiteSpace(nextChar) + && nextChar != '-' + && nextChar != '(' + && nextChar != '[' + && !isLegalNameChar(nextChar)); + } + + return isPR; +} + + +/** + * check if the currently reached '-' character is + * a unary minus + * this method takes for granted that the current character + * is a '-'. + * + * @return whether the current '-' is a unary minus. + */ +bool ASFormatter::isUnaryMinus() const +{ + return ((previousOperator == &AS_RETURN || !isalnum(previousCommandChar)) + && previousCommandChar != '.' + && previousCommandChar != ')' + && previousCommandChar != ']'); +} + + +/** + * check if the currently reached '-' or '+' character is + * part of an exponent, i.e. 0.2E-5. + * this method takes for granted that the current character + * is a '-' or '+'. + * + * @return whether the current '-' is in an exponent. + */ +bool ASFormatter::isInExponent() const +{ + int formattedLineLength = formattedLine.length(); + if (formattedLineLength >= 2) + { + char prevPrevFormattedChar = formattedLine[formattedLineLength - 2]; + char prevFormattedChar = formattedLine[formattedLineLength - 1]; + + return ((prevFormattedChar == 'e' || prevFormattedChar == 'E') + && (prevPrevFormattedChar == '.' || isdigit(prevPrevFormattedChar))); + } + else + return false; +} + +/** + * check if a one-line bracket has been reached, + * i.e. if the currently reached '{' character is closed + * with a complimentry '}' elsewhere on the current line, + *. + * @return has a one-line bracket been reached? + */ +bool ASFormatter::isOneLineBlockReached() const +{ + bool isInComment = false; + bool isInQuote = false; + int bracketCount = 1; + int currentLineLength = currentLine.length(); + char quoteChar = ' '; + + for (int i = charNum + 1; i < currentLineLength; ++i) + { + char ch = currentLine[i]; + + if (isInComment) + { + if (currentLine.compare(i, 2, "*/") == 0) + { + isInComment = false; + ++i; + } + continue; + } + + if (ch == '\\') + { + ++i; + continue; + } + + if (isInQuote) + { + if (ch == quoteChar) + isInQuote = false; + continue; + } + + if (ch == '"' || ch == '\'') + { + isInQuote = true; + quoteChar = ch; + continue; + } + + if (currentLine.compare(i, 2, "//") == 0) + break; + + if (currentLine.compare(i, 2, "/*") == 0) + { + isInComment = true; + ++i; + continue; + } + + if (ch == '{') + ++bracketCount; + else if (ch == '}') + --bracketCount; + + if (bracketCount == 0) + return true; + } + + return false; +} + +/** + * check if one of a set of headers has been reached in the + * current position of the current line. + * + * @return a pointer to the found header. Or a NULL if no header has been reached. + * @param headers a vector of headers. + * @param checkBoundry + */ +const string *ASFormatter::findHeader(const vector<const string*> &headers, bool checkBoundry) +{ + return ASBeautifier::findHeader(currentLine, charNum, headers, checkBoundry); +} + +/** + * check if a line begins with the specified character + * i.e. if the current line begins with a open bracket. + * + * @return true or false + */ +bool ASFormatter::lineBeginsWith(char charToCheck) const +{ + bool beginsWith = false; + size_t i = currentLine.find_first_not_of(" \t"); + + if (i != string::npos) + if (currentLine[i] == charToCheck && (int) i == charNum) + beginsWith = true; + + return beginsWith; +} + +/** + * adjust comment position because of adding or deleting spaces + * the spaces are added or deleted to formattedLine + * spacePadNum contains the adjustment + */ +void ASFormatter::adjustComments(void) +{ + assert(spacePadNum != 0); + assert(currentLine.compare(charNum, 2, "//") == 0 + || currentLine.compare(charNum, 2, "/*") == 0); + + + // block comment must be closed on this line with nothing after it + if (currentLine.compare(charNum, 2, "/*") == 0) + { + size_t endNum = currentLine.find("*/", charNum + 2); + if (endNum == string::npos) + return; + if (currentLine.find_first_not_of(" \t", endNum + 2) != string::npos) + return; + } + + size_t len = formattedLine.length(); + // if spaces were removed, need to add spaces before the comment + if (spacePadNum < 0) + { + int adjust = -spacePadNum; // make the number positive + if (formattedLine[len-1] != '\t') // don't adjust if a tab + formattedLine.append(adjust, ' '); +// else // comment out to avoid compiler warning +// adjust = 0; +// TRcomment(adjust); // trace macro + } + // if spaces were added, need to delete spaces before the comment, if possible + else if (spacePadNum > 0) + { + int adjust = spacePadNum; + if (formattedLine.find_last_not_of(' ') < len - adjust - 1 + && formattedLine[len-1] != '\t') // don't adjust a tab + formattedLine.resize(len - adjust); + // the following are commented out to avoid a Borland compiler warning + //else + // adjust = 0; + TRcomment(-adjust); // trace macro + } +} + +/** + * append the current bracket inside the end of line comments + * currentChar contains the bracket, it will be appended to formattedLine + * formattedLineCommentNum is the comment location on formattedLine + */ +void ASFormatter::appendCharInsideComments(void) +{ + if (formattedLineCommentNum == string::npos // does the comment start on the previous line? + || isBeforeComment()) // does a comment follow on this line? + { + appendCurrentChar(true); // don't attach + return; + } + assert(formattedLine.compare(formattedLineCommentNum, 2, "//") == 0 + || formattedLine.compare(formattedLineCommentNum, 2, "/*") == 0); + + // find the previous non space char + size_t end = formattedLineCommentNum; + size_t beg = formattedLine.find_last_not_of(" \t", end-1); + if (beg == string::npos) // is the previous line comment only? + { + appendCurrentChar(true); // don't attach + return; + } + beg++; + + // insert the bracket + if (end - beg < 3) // is there room to insert? + formattedLine.insert(beg, 3-end+beg, ' '); + if (formattedLine[beg] == '\t') // don't pad with a tab + formattedLine.insert(beg, 1, ' '); + formattedLine[beg+1] = currentChar; +} + +/** + * add or remove space padding to operators + * currentChar contains the paren + * the operators and necessary padding will be appended to formattedLine + * the calling function should have a continue statement after calling this method + * + * @param *newOperator the operator to be padded + */ +void ASFormatter::padOperators(const string *newOperator) +{ + assert (shouldPadOperators); + assert(newOperator != NULL); + + bool shouldPad = (newOperator != &AS_COLON_COLON + && newOperator != &AS_PAREN_PAREN + && newOperator != &AS_BLPAREN_BLPAREN + && newOperator != &AS_PLUS_PLUS + && newOperator != &AS_MINUS_MINUS + && newOperator != &AS_NOT + && newOperator != &AS_BIT_NOT + && newOperator != &AS_ARROW + && newOperator != &AS_OPERATOR + && newOperator != &AS_RETURN + && !(newOperator == &AS_MINUS && isInExponent()) + && !(newOperator == &AS_MINUS // check for negative number + && (previousNonWSChar == '(' + || previousNonWSChar == '=' + || previousNonWSChar == ',')) + && !(newOperator == &AS_PLUS && isInExponent()) + && previousOperator != &AS_OPERATOR + && !((newOperator == &AS_MULT || newOperator == &AS_BIT_AND) + && isPointerOrReference()) + && !(newOperator == &AS_MULT + && (previousNonWSChar == '.' + || previousNonWSChar == '>')) // check for -> + && !((isInTemplate || isCharImmediatelyPostTemplate) + && (newOperator == &AS_LS || newOperator == &AS_GR)) + ); + // pad before operator + if (shouldPad + && !isInBlParen + && !(newOperator == &AS_COLON && !foundQuestionMark) + && newOperator != &AS_SEMICOLON + && newOperator != &AS_COMMA) + appendSpacePad(); + appendSequence(*newOperator); + goForward(newOperator->length() - 1); + + // since this block handles '()' and '[]', + // the parenStack must be updated here accordingly! + if (newOperator == &AS_PAREN_PAREN + || newOperator == &AS_BLPAREN_BLPAREN) + parenStack->back()--; + + currentChar = (*newOperator)[newOperator->length() - 1]; + // pad after operator + // but do not pad after a '-' that is a unary-minus. + if (shouldPad + && !isInBlParen + && !isBeforeComment() + && !(newOperator == &AS_MINUS && isUnaryMinus()) + && !(currentLine.compare(charNum + 1, 1, ";") == 0) + && !(currentLine.compare(charNum + 1, 2, "::") == 0)) + appendSpaceAfter(); + + previousOperator = newOperator; + return; +} + +/** + * add or remove space padding to parens + * currentChar contains the paren + * the parens and necessary padding will be appended to formattedLine + * the calling function should have a continue statement after calling this method + */ +void ASFormatter::padParens(void) +{ + assert(shouldPadParensOutside || shouldPadParensInside || shouldUnPadParens); + assert (currentChar == '(' || currentChar == ')'); + + if (currentChar == '(') + { + int spacesOutsideToDelete = formattedLine.length() - 1; + int spacesInsideToDelete = 0; + + // compute spaces outside the opening paren to delete + if (shouldUnPadParens) + { + char lastChar = ' '; + bool prevIsParenHeader = false; + size_t i = formattedLine.find_last_not_of(" \t"); + if (i != string::npos) + { + size_t end = i; + spacesOutsideToDelete -= i; + lastChar = formattedLine[i]; + // was last word a paren header? + int start; // start of the previous word + for (start = i; start > 0; start--) + { + if (isLegalNameChar(formattedLine[start]) || formattedLine[start] == '*') + continue; + start++; + break; + } + string prevWord = formattedLine.substr(start, end-start+1); + // if previous word is a header, it will be a paren header + const string *prevWordH = ASBeautifier::findHeader(formattedLine, start, headers); + if (prevWordH != NULL) + { + prevIsParenHeader = true; + TRxtra(*prevWordH); // trace macro + } + else if (prevWord == "return" // don't unpad return statements + || prevWord == "*") // don't unpad multiply or pointer + { + prevIsParenHeader = true; + TRxtra(prevWord); // trace macro + } + // don't unpad variables + else if (prevWord == "bool" + || prevWord == "int" + || prevWord == "void" + || prevWord == "void*" + || (prevWord.length() >= 6 // check end of word for _t + && prevWord.compare(prevWord.length()-2, 2, "_t") == 0) + || prevWord == "BOOL" + || prevWord == "DWORD" + || prevWord == "HWND" + || prevWord == "INT" + || prevWord == "LPSTR" + || prevWord == "VOID" + || prevWord == "LPVOID" + ) + { + prevIsParenHeader = true; + TRxtra(prevWord); // trace macro + } + } + // do not unpad operators, but leave them if already padded + if (shouldPadParensOutside || prevIsParenHeader) + spacesOutsideToDelete--; + else if (lastChar == '|' // check for || + || lastChar == '&' // check for && + || lastChar == ',' + || (lastChar == '>' && !foundCastOperator) + || lastChar == '<' + || lastChar == '?' + || lastChar == ':' + || lastChar == ';' + || lastChar == '=' + || lastChar == '+' + || lastChar == '-' + || (lastChar == '*' && isInPotentialCalculation) + || lastChar == '/' + || lastChar == '%') + spacesOutsideToDelete--; + + if (spacesOutsideToDelete > 0) + { + formattedLine.erase(i + 1, spacesOutsideToDelete); + spacePadNum -= spacesOutsideToDelete; + } + } + + // pad open paren outside + char peekedCharOutside = peekNextChar(); + if (shouldPadParensOutside) + if (!(currentChar == '(' && peekedCharOutside == ')')) + appendSpacePad(); + + appendCurrentChar(); + + // unpad open paren inside + if (shouldUnPadParens) + { + size_t j = currentLine.find_first_not_of(" \t", charNum + 1); + if (j != string::npos) + spacesInsideToDelete = j - charNum - 1; + if (shouldPadParensInside) + spacesInsideToDelete--; + if (spacesInsideToDelete > 0) + { + currentLine.erase(charNum + 1, spacesInsideToDelete); + spacePadNum -= spacesInsideToDelete; + } + } + + // pad open paren inside + char peekedCharInside = peekNextChar(); + if (shouldPadParensInside) + if (!(currentChar == '(' && peekedCharInside == ')')) + appendSpaceAfter(); + + TRunpad('(', spacesOutsideToDelete, spacesInsideToDelete); // trace macro + } + else if (currentChar == ')' /*|| currentChar == ']'*/) + { + int spacesOutsideToDelete = 0; + int spacesInsideToDelete = formattedLine.length(); + + // unpad close paren inside + if (shouldUnPadParens) + { + size_t i = formattedLine.find_last_not_of(" \t"); + if (i != string::npos) + spacesInsideToDelete = formattedLine.length() - 1 - i; + if (shouldPadParensInside) + spacesInsideToDelete--; + if (spacesInsideToDelete > 0) + { + formattedLine.erase(i + 1, spacesInsideToDelete); + spacePadNum -= spacesInsideToDelete; + } + } + + // pad close paren inside + if (shouldPadParensInside) + if (!(previousChar == '(' && currentChar == ')')) + appendSpacePad(); + + appendCurrentChar(); + + // unpad close paren outside + if (shouldUnPadParens) + { + // may have end of line comments + size_t j = currentLine.find_first_not_of(" \t", charNum + 1); + if (j != string::npos) + if (currentLine[j] == '[' || currentLine[j] == ']') + spacesOutsideToDelete = j - charNum - 1; + if (shouldPadParensOutside) + spacesOutsideToDelete--; +// spacesOutsideToDelete--; // always leave 1 space + + if (spacesOutsideToDelete > 0) + { + currentLine.erase(charNum + 1, spacesOutsideToDelete); + spacePadNum -= spacesOutsideToDelete; + } + } + + // pad close paren outside + char peekedCharOutside = peekNextChar(); + if (shouldPadParensOutside) + if (peekedCharOutside != ';' + && peekedCharOutside != ',' + && peekedCharOutside != '.' + && peekedCharOutside != '-') // check for -> +// && !(currentChar == ']' && peekedCharOutside == '[')) + appendSpaceAfter(); + + TRunpad(')', spacesInsideToDelete, 0 /*spacesOutsideToDelete*/); // trace macro + } + return; +} + +/** + * format brackets as attached or broken + * currentChar contains the bracket + * the brackets will be appended to the current formattedLine or a new formattedLine as necessary + * the calling function should have a continue statement after calling this method + * + * @param bracketType the type of bracket to be formatted. + */ +void ASFormatter::formatBrackets(BracketType bracketType) +{ + assert(!IS_A(bracketType, ARRAY_TYPE)); + assert (currentChar == '{' || currentChar == '}'); + + if (currentChar == '{') + { + parenStack->push_back(0); + } + else if (currentChar == '}') + { + if (!parenStack->empty()) + { + parenStack->pop_back(); + } + } + + if (currentChar == '{') + { + bool bdacBreak = false; + // should a Linux bracket be broken? + if (bracketFormatMode == BDAC_MODE) + { + // always break a class + if (IS_A((*bracketTypeStack)[bracketTypeStack->size()-1], CLASS_TYPE)) + bdacBreak = true; + // break a namespace and the first bracket if a function + else if (bracketTypeStack->size() <= 2) + { + if (IS_A((*bracketTypeStack)[bracketTypeStack->size()-1], NAMESPACE_TYPE) + || IS_A((*bracketTypeStack)[bracketTypeStack->size()-1], COMMAND_TYPE)) + bdacBreak = true; + } + // break the first bracket after a namespace if a function + else if (IS_A((*bracketTypeStack)[bracketTypeStack->size()-2], NAMESPACE_TYPE)) + { + if (IS_A((*bracketTypeStack)[bracketTypeStack->size()-1], COMMAND_TYPE)) + bdacBreak = true; + } + // if not C style then break the first bracket after a class if a function + else if (!ASBeautifier::isCStyle) + { + if (IS_A((*bracketTypeStack)[bracketTypeStack->size()-2], CLASS_TYPE) + && IS_A((*bracketTypeStack)[bracketTypeStack->size()-1], COMMAND_TYPE)) + bdacBreak = true; + } + } + if (bracketFormatMode == ATTACH_MODE + || (bracketFormatMode == BDAC_MODE && !bdacBreak)) + { + // are there comments before the bracket? + if (isCharImmediatelyPostComment || isCharImmediatelyPostLineComment) + { + if ((shouldBreakOneLineBlocks || !IS_A(bracketType, SINGLE_LINE_TYPE)) + && peekNextChar() != '}') + appendCharInsideComments(); + else + appendCurrentChar(true); // don't attach + } + else if (previousCommandChar == '{' + || previousCommandChar == '}' + || previousCommandChar == ';') // '}' , ';' chars added for proper handling of '{' immediately after a '}' or ';' + { + appendCurrentChar(true); // don't attach + } + else + { + size_t firstChar = formattedLine.find_first_not_of(" \t"); + if (firstChar == string::npos) // if a blank line preceeds this + appendCurrentChar(true); // don't attach + else if (shouldBreakOneLineBlocks + || !IS_A(bracketType, SINGLE_LINE_TYPE) + || peekNextChar() == '}') + { + appendSpacePad(); + appendCurrentChar(false); // OK to attach + } + else + appendCurrentChar(true); // don't attach + } + } + else if (bracketFormatMode == BREAK_MODE + || (bracketFormatMode == BDAC_MODE && bdacBreak)) + { + if (isBeforeComment()) + { + // do not break unless comment is at line end + if (isBeforeLineEndComment(charNum)) + { + currentChar = ' '; // remove bracket from current line + appendOpeningBracket = true; // append bracket to following line + } + } + else if (!IS_A(bracketType, SINGLE_LINE_TYPE)) + breakLine(); + else if (shouldBreakOneLineBlocks && peekNextChar() != '}') + breakLine(); + + appendCurrentChar(); + } + else if (bracketFormatMode == NONE_MODE) + { + if (lineBeginsWith('{')) // is opening bracket broken? + appendCurrentChar(true); + else + appendCurrentChar(false); + } + } + else if (currentChar == '}') + { + // mark state of immediately after empty block + // this state will be used for locating brackets that appear immedately AFTER an empty block (e.g. '{} \n}'). + if (previousCommandChar == '{') + isImmediatelyPostEmptyBlock = true; + + if ((!(previousCommandChar == '{' && isPreviousBracketBlockRelated)) // this '{' does not close an empty block + && (shouldBreakOneLineBlocks || !IS_A(bracketType, SINGLE_LINE_TYPE)) // astyle is allowed to break on line blocks + && (!(bracketFormatMode == NONE_MODE && IS_A(bracketType, SINGLE_LINE_TYPE))) + && !isImmediatelyPostEmptyBlock) // this '}' does not immediately follow an empty block + { + breakLine(); + appendCurrentChar(); + } + else + { + if (!isCharImmediatelyPostComment + && !bracketFormatMode == NONE_MODE + && !isImmediatelyPostEmptyBlock) + isInLineBreak = false; + + appendCurrentChar(); + + //if (!bracketFormatMode == NONE_MODE) + // if ((shouldBreakOneLineBlocks || !IS_A(bracketType, SINGLE_LINE_TYPE)) + // && !(currentChar == '}' && peekNextChar() == ';')) // fixes }; placed on separate lines + // shouldBreakLineAfterComments = true; + } + + if (shouldBreakBlocks) + { + isAppendPostBlockEmptyLineRequested = true; + } + } + return; +} + +/** + * format array brackets as attached or broken + * determine if the brackets can have an inStatement indent + * currentChar contains the bracket + * the brackets will be appended to the current formattedLine or a new formattedLine as necessary + * the calling function should have a continue statement after calling this method + * + * @param bracketType the type of bracket to be formatted, must be an ARRAY_TYPE. + * @param isOpeningArrayBracket indicates if this is the opening bracket for the array block. + */ +void ASFormatter::formatArrayBrackets(BracketType bracketType, bool isOpeningArrayBracket) +{ + assert(IS_A(bracketType, ARRAY_TYPE)); + assert (currentChar == '{' || currentChar == '}'); + + if (currentChar == '{') + { + // is this the first opening bracket in the array? + if (isOpeningArrayBracket) + { + if (bracketFormatMode == ATTACH_MODE || bracketFormatMode == BDAC_MODE) + { + // don't attach to a preprocessor directive + if (isImmediatelyPostPreprocessor) + appendCurrentChar(true); // don't attach + // are there comments before the bracket? + else if (isCharImmediatelyPostComment || isCharImmediatelyPostLineComment) + { + appendCharInsideComments(); + } + else + { + // if bracket is broken or not an assignment + if (lineBeginsWith('{') || previousNonWSChar != '=') + appendSpacePad(); + appendCurrentChar(false); // OK to attach + } + } + else if (bracketFormatMode == BREAK_MODE) + { + if (isWhiteSpace(peekNextChar())) + breakLine(); + else if (isBeforeComment()) + { + // do not break unless comment is at line end + if (isBeforeLineEndComment(charNum)) + { + currentChar = ' '; // remove bracket from current line + appendOpeningBracket = true; // append bracket to following line + } + } + appendCurrentChar(); + } + else if (bracketFormatMode == NONE_MODE) + { + if (lineBeginsWith('{')) // is opening bracket broken? + appendCurrentChar(); + else + appendCurrentChar(false); + } + } + else + appendCurrentChar(); // not the first opening bracket - don't change + + // if an opening bracket ends the line there will be no inStatement indent + char nextChar = peekNextChar(); + if (isWhiteSpace(nextChar) + || isBeforeLineEndComment(charNum) + || nextChar == '{') + isNonInStatementArray = true; + if (isNonInStatementArray) + TRarray('x'); + else + TRarray(' '); + + } + else if (currentChar == '}') + { + // does this close the first opening bracket in the array? + if (isOpeningArrayBracket && !IS_A(bracketType, SINGLE_LINE_TYPE) ) + { + breakLine(); + appendCurrentChar(); + } + else + appendCurrentChar(); + } +} + + +} // end namespace astyle diff --git a/lib/astyle/ASResource.cpp b/lib/astyle/ASResource.cpp new file mode 100644 index 00000000..0c554ac0 --- /dev/null +++ b/lib/astyle/ASResource.cpp @@ -0,0 +1,389 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * + * ASResource.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. + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + */ + +#include "astyle.h" + + +namespace astyle +{ +const string ASResource::AS_IF = string("if"); +const string ASResource::AS_ELSE = string("else"); +const string ASResource::AS_FOR = string("for"); +const string ASResource::AS_DO = string("do"); +const string ASResource::AS_WHILE = string("while"); +const string ASResource::AS_SWITCH = string("switch"); +const string ASResource::AS_CASE = string("case"); +const string ASResource::AS_DEFAULT = string("default"); +const string ASResource::AS_CLASS = string("class"); +const string ASResource::AS_STRUCT = string("struct"); +const string ASResource::AS_UNION = string("union"); +const string ASResource::AS_INTERFACE = string("interface"); +const string ASResource::AS_NAMESPACE = string("namespace"); +const string ASResource::AS_EXTERN = string("extern"); +const string ASResource::AS_PUBLIC = string("public"); +const string ASResource::AS_PROTECTED = string("protected"); +const string ASResource::AS_PRIVATE = string("private"); +const string ASResource::AS_STATIC = string("static"); +const string ASResource::AS_SYNCHRONIZED = string("synchronized"); +const string ASResource::AS_OPERATOR = string("operator"); +const string ASResource::AS_TEMPLATE = string("template"); +const string ASResource::AS_TRY = string("try"); +const string ASResource::AS_CATCH = string("catch"); +const string ASResource::AS_FINALLY = string("finally"); +const string ASResource::AS_THROWS = string("throws"); +const string ASResource::AS_CONST = string("const"); + +const string ASResource::AS_ASM = string("asm"); + +const string ASResource::AS_BAR_DEFINE = string("#define"); +const string ASResource::AS_BAR_INCLUDE = string("#include"); +const string ASResource::AS_BAR_IF = string("#if"); +const string ASResource::AS_BAR_EL = string("#el"); +const string ASResource::AS_BAR_ENDIF = string("#endif"); + +const string ASResource::AS_OPEN_BRACKET = string("{"); +const string ASResource::AS_CLOSE_BRACKET = string("}"); +const string ASResource::AS_OPEN_LINE_COMMENT = string("//"); +const string ASResource::AS_OPEN_COMMENT = string("/*"); +const string ASResource::AS_CLOSE_COMMENT = string("*/"); + +const string ASResource::AS_ASSIGN = string("="); +const string ASResource::AS_PLUS_ASSIGN = string("+="); +const string ASResource::AS_MINUS_ASSIGN = string("-="); +const string ASResource::AS_MULT_ASSIGN = string("*="); +const string ASResource::AS_DIV_ASSIGN = string("/="); +const string ASResource::AS_MOD_ASSIGN = string("%="); +const string ASResource::AS_OR_ASSIGN = string("|="); +const string ASResource::AS_AND_ASSIGN = string("&="); +const string ASResource::AS_XOR_ASSIGN = string("^="); +const string ASResource::AS_GR_GR_ASSIGN = string(">>="); +const string ASResource::AS_LS_LS_ASSIGN = string("<<="); +const string ASResource::AS_GR_GR_GR_ASSIGN = string(">>>="); +const string ASResource::AS_LS_LS_LS_ASSIGN = string("<<<="); +const string ASResource::AS_RETURN = string("return"); + +const string ASResource::AS_EQUAL = string("=="); +const string ASResource::AS_PLUS_PLUS = string("++"); +const string ASResource::AS_MINUS_MINUS = string("--"); +const string ASResource::AS_NOT_EQUAL = string("!="); +const string ASResource::AS_GR_EQUAL = string(">="); +const string ASResource::AS_GR_GR = string(">>"); +const string ASResource::AS_GR_GR_GR = string(">>>"); +const string ASResource::AS_LS_EQUAL = string("<="); +const string ASResource::AS_LS_LS = string("<<"); +const string ASResource::AS_LS_LS_LS = string("<<<"); +const string ASResource::AS_ARROW = string("->"); +const string ASResource::AS_AND = string("&&"); +const string ASResource::AS_OR = string("||"); +const string ASResource::AS_COLON_COLON = string("::"); +const string ASResource::AS_PAREN_PAREN = string("()"); +const string ASResource::AS_BLPAREN_BLPAREN = string("[]"); + +const string ASResource::AS_PLUS = string("+"); +const string ASResource::AS_MINUS = string("-"); +const string ASResource::AS_MULT = string("*"); +const string ASResource::AS_DIV = string("/"); +const string ASResource::AS_MOD = string("%"); +const string ASResource::AS_GR = string(">"); +const string ASResource::AS_LS = string("<"); +const string ASResource::AS_NOT = string("!"); +const string ASResource::AS_BIT_OR = string("|"); +const string ASResource::AS_BIT_AND = string("&"); +const string ASResource::AS_BIT_NOT = string("~"); +const string ASResource::AS_BIT_XOR = string("^"); +const string ASResource::AS_QUESTION = string("?"); +const string ASResource::AS_COLON = string(":"); +const string ASResource::AS_COMMA = string(","); +const string ASResource::AS_SEMICOLON = string(";"); + +const string ASResource::AS_FOREACH = string("foreach"); +const string ASResource::AS_LOCK = string("lock"); +const string ASResource::AS_UNSAFE = string("unsafe"); +const string ASResource::AS_FIXED = string("fixed"); +const string ASResource::AS_GET = string("get"); +const string ASResource::AS_SET = string("set"); +const string ASResource::AS_ADD = string("add"); +const string ASResource::AS_REMOVE = string("remove"); + +const string ASResource::AS_CONST_CAST = string("const_cast"); +const string ASResource::AS_DYNAMIC_CAST = string("dynamic_cast"); +const string ASResource::AS_REINTERPRET_CAST = string("reinterpret_cast"); +const string ASResource::AS_STATIC_CAST = string("static_cast"); + + +/** + * Build the vector of assignment operators. + * Used by BOTH ASFormatter.cpp and ASBeautifier.cpp + * + * @param assignmentOperators a reference to the vector to be built. + */ +void ASResource::buildAssignmentOperators(vector<const string*> &assignmentOperators) +{ + assignmentOperators.push_back(&AS_ASSIGN); + assignmentOperators.push_back(&AS_PLUS_ASSIGN); + assignmentOperators.push_back(&AS_MINUS_ASSIGN); + assignmentOperators.push_back(&AS_MULT_ASSIGN); + assignmentOperators.push_back(&AS_DIV_ASSIGN); + assignmentOperators.push_back(&AS_MOD_ASSIGN); + assignmentOperators.push_back(&AS_OR_ASSIGN); + assignmentOperators.push_back(&AS_AND_ASSIGN); + assignmentOperators.push_back(&AS_XOR_ASSIGN); + + // Java + assignmentOperators.push_back(&AS_GR_GR_GR_ASSIGN); + assignmentOperators.push_back(&AS_GR_GR_ASSIGN); + assignmentOperators.push_back(&AS_LS_LS_ASSIGN); + + // Unknown + assignmentOperators.push_back(&AS_LS_LS_LS_ASSIGN); + + assignmentOperators.push_back(&AS_RETURN); +} + +/** + * Build the vector of C++ cast operators. + * Used by ONLY ASFormatter.cpp + * + * @param castOperators a reference to the vector to be built. + */ +void ASResource::buildCastOperators(vector<const string*> &castOperators) +{ + castOperators.push_back(&AS_CONST_CAST); + castOperators.push_back(&AS_DYNAMIC_CAST); + castOperators.push_back(&AS_REINTERPRET_CAST); + castOperators.push_back(&AS_STATIC_CAST); +} + +/** + * Build the vector of header words. + * Used by BOTH ASFormatter.cpp and ASBeautifier.cpp + * + * @param headers a reference to the vector to be built. + */ +void ASResource::buildHeaders(vector<const string*> &headers, int fileType, bool beautifier) +{ + headers.push_back(&AS_IF); + headers.push_back(&AS_ELSE); + headers.push_back(&AS_FOR); + headers.push_back(&AS_WHILE); + headers.push_back(&AS_DO); + headers.push_back(&AS_SWITCH); + headers.push_back(&AS_TRY); + headers.push_back(&AS_CATCH); + + if (beautifier) + { + headers.push_back(&AS_CASE); + headers.push_back(&AS_DEFAULT); + headers.push_back(&AS_CONST); + headers.push_back(&AS_STATIC); + headers.push_back(&AS_EXTERN); + headers.push_back(&AS_TEMPLATE); + } + + if (fileType == JAVA_TYPE) + { + headers.push_back(&AS_FINALLY); + headers.push_back(&AS_SYNCHRONIZED); + } + + if (fileType == SHARP_TYPE) + { + headers.push_back(&AS_FINALLY); + headers.push_back(&AS_FOREACH); + headers.push_back(&AS_LOCK); + headers.push_back(&AS_UNSAFE); + headers.push_back(&AS_FIXED); + headers.push_back(&AS_GET); + headers.push_back(&AS_SET); + headers.push_back(&AS_ADD); + headers.push_back(&AS_REMOVE); + } +} + +/** + * Build the vector of non-assignment operators. + * Used by ONLY ASBeautifier.cpp + * + * @param nonParenHeaders a reference to the vector to be built. + */ +void ASResource::buildNonAssignmentOperators(vector<const string*> &nonAssignmentOperators) +{ + nonAssignmentOperators.push_back(&AS_EQUAL); + nonAssignmentOperators.push_back(&AS_PLUS_PLUS); + nonAssignmentOperators.push_back(&AS_MINUS_MINUS); + nonAssignmentOperators.push_back(&AS_NOT_EQUAL); + nonAssignmentOperators.push_back(&AS_GR_EQUAL); + nonAssignmentOperators.push_back(&AS_GR_GR_GR); + nonAssignmentOperators.push_back(&AS_GR_GR); + nonAssignmentOperators.push_back(&AS_LS_EQUAL); + nonAssignmentOperators.push_back(&AS_LS_LS_LS); + nonAssignmentOperators.push_back(&AS_LS_LS); + nonAssignmentOperators.push_back(&AS_ARROW); + nonAssignmentOperators.push_back(&AS_AND); + nonAssignmentOperators.push_back(&AS_OR); +} + +/** + * Build the vector of header non-paren headers. + * Used by BOTH ASFormatter.cpp and ASBeautifier.cpp + * + * @param nonParenHeaders a reference to the vector to be built. + */ +void ASResource::buildNonParenHeaders(vector<const string*> &nonParenHeaders, int fileType, bool beautifier) +{ + nonParenHeaders.push_back(&AS_ELSE); + nonParenHeaders.push_back(&AS_DO); + nonParenHeaders.push_back(&AS_TRY); + + if (beautifier) + { + nonParenHeaders.push_back(&AS_CASE); + nonParenHeaders.push_back(&AS_DEFAULT); + nonParenHeaders.push_back(&AS_CONST); + nonParenHeaders.push_back(&AS_STATIC); + nonParenHeaders.push_back(&AS_EXTERN); + nonParenHeaders.push_back(&AS_TEMPLATE); + } + + if (fileType == JAVA_TYPE) + { + nonParenHeaders.push_back(&AS_FINALLY); + } + + if (fileType == SHARP_TYPE) + { + nonParenHeaders.push_back(&AS_FINALLY); + nonParenHeaders.push_back(&AS_UNSAFE); + nonParenHeaders.push_back(&AS_GET); + nonParenHeaders.push_back(&AS_SET); + nonParenHeaders.push_back(&AS_ADD); + nonParenHeaders.push_back(&AS_REMOVE); + } +} + +/** + * Build the vector of operators. + * Used by ONLY ASFormatter.cpp + * + * @param operators a reference to the vector to be built. + */ +void ASResource::buildOperators(vector<const string*> &operators) +{ + operators.push_back(&AS_PLUS_ASSIGN); + operators.push_back(&AS_MINUS_ASSIGN); + operators.push_back(&AS_MULT_ASSIGN); + operators.push_back(&AS_DIV_ASSIGN); + operators.push_back(&AS_MOD_ASSIGN); + operators.push_back(&AS_OR_ASSIGN); + operators.push_back(&AS_AND_ASSIGN); + operators.push_back(&AS_XOR_ASSIGN); + operators.push_back(&AS_EQUAL); + operators.push_back(&AS_PLUS_PLUS); + operators.push_back(&AS_MINUS_MINUS); + operators.push_back(&AS_NOT_EQUAL); + operators.push_back(&AS_GR_EQUAL); + operators.push_back(&AS_GR_GR_GR_ASSIGN); + operators.push_back(&AS_GR_GR_ASSIGN); + operators.push_back(&AS_GR_GR_GR); + operators.push_back(&AS_GR_GR); + operators.push_back(&AS_LS_EQUAL); + operators.push_back(&AS_LS_LS_LS_ASSIGN); + operators.push_back(&AS_LS_LS_ASSIGN); + operators.push_back(&AS_LS_LS_LS); + operators.push_back(&AS_LS_LS); + operators.push_back(&AS_ARROW); + operators.push_back(&AS_AND); + operators.push_back(&AS_OR); + operators.push_back(&AS_COLON_COLON); + operators.push_back(&AS_PLUS); + operators.push_back(&AS_MINUS); + operators.push_back(&AS_MULT); + operators.push_back(&AS_DIV); + operators.push_back(&AS_MOD); + operators.push_back(&AS_QUESTION); + operators.push_back(&AS_COLON); + operators.push_back(&AS_ASSIGN); + operators.push_back(&AS_LS); + operators.push_back(&AS_GR); + operators.push_back(&AS_NOT); + operators.push_back(&AS_BIT_OR); + operators.push_back(&AS_BIT_AND); + operators.push_back(&AS_BIT_NOT); + operators.push_back(&AS_BIT_XOR); + operators.push_back(&AS_OPERATOR); + operators.push_back(&AS_COMMA); + operators.push_back(&AS_RETURN); +} + +/** + * Build the vector of pre-block statements. + * Used by ONLY ASBeautifier.cpp + * + * @param preBlockStatements a reference to the vector to be built. + */ +void ASResource::buildPreBlockStatements(vector<const string*> &preBlockStatements) +{ + preBlockStatements.push_back(&AS_CLASS); + preBlockStatements.push_back(&AS_STRUCT); + preBlockStatements.push_back(&AS_UNION); + preBlockStatements.push_back(&AS_INTERFACE); + preBlockStatements.push_back(&AS_NAMESPACE); + preBlockStatements.push_back(&AS_THROWS); + preBlockStatements.push_back(&AS_EXTERN); +} + +/** + * Build the vector of pre-command headers. + * Used by ONLY ASFormatter.cpp + * + * @param preCommandHeaders a reference to the vector to be built. + */ +void ASResource::buildPreCommandHeaders(vector<const string*> &preCommandHeaders) +{ + preCommandHeaders.push_back(&AS_EXTERN); + preCommandHeaders.push_back(&AS_THROWS); + preCommandHeaders.push_back(&AS_CONST); +} + +/** + * Build the vector of pre-definition headers. + * Used by ONLY ASFormatter.cpp + * + * @param preDefinitionHeaders a reference to the vector to be built. + */ +void ASResource::buildPreDefinitionHeaders(vector<const string*> &preDefinitionHeaders) +{ + preDefinitionHeaders.push_back(&AS_CLASS); + preDefinitionHeaders.push_back(&AS_INTERFACE); + preDefinitionHeaders.push_back(&AS_NAMESPACE); + preDefinitionHeaders.push_back(&AS_STRUCT); +} + + +} // end namespace astyle diff --git a/lib/astyle/Makefile.am b/lib/astyle/Makefile.am new file mode 100644 index 00000000..dbafd18e --- /dev/null +++ b/lib/astyle/Makefile.am @@ -0,0 +1,4 @@ +INCLUDES = $(all_includes) +noinst_LTLIBRARIES = libastyle.la +libastyle_la_LDFLAGS = $(all_libraries) +libastyle_la_SOURCES = ASBeautifier.cpp ASEnhancer.cpp ASFormatter.cpp ASResource.cpp diff --git a/lib/astyle/astyle.h b/lib/astyle/astyle.h new file mode 100644 index 00000000..445aacf6 --- /dev/null +++ b/lib/astyle/astyle.h @@ -0,0 +1,497 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * + * astyle.h + * + * 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. + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + */ + +#ifndef ASTYLE_H +#define ASTYLE_H + +#ifdef __VMS +#define __USE_STD_IOSTREAM 1 +#include <sstream> +#endif + +#include <string> +#include <vector> +#include <cctype> + +#include <string.h> + +using namespace std; + + +// 4996 - secure version deprecation warnings for .NET 2005 +// 4267 - 64 bit signed/unsigned loss of data +#ifdef _MSC_VER +#pragma warning(disable: 4996) +#pragma warning(disable: 4267) +#endif + +namespace astyle +{ + +enum FileType { C_TYPE=0, JAVA_TYPE=1, SHARP_TYPE=2 }; + +/* The enums below are not recognized by 'vectors' in Microsoft Visual C++ + V5 when they are part of a namespace!!! Use Visual C++ V6 or higher. +*/ +enum BracketMode { NONE_MODE, ATTACH_MODE, BREAK_MODE, BDAC_MODE }; + +enum BracketType { NULL_TYPE = 0, + NAMESPACE_TYPE = 1, // also a DEFINITION_TYPE + CLASS_TYPE = 2, // also a DEFINITION_TYPE + DEFINITION_TYPE = 4, + COMMAND_TYPE = 8, + ARRAY_TYPE = 16, // arrays and enums + SINGLE_LINE_TYPE = 32 + }; + +class ASSourceIterator +{ + public: + int eolWindows; + int eolLinux; + int eolMacOld; + char outputEOL[4]; // output end of line char + ASSourceIterator() { eolWindows = eolLinux = eolMacOld = 0; } + virtual ~ASSourceIterator() {} + virtual bool hasMoreLines() const = 0; + virtual string nextLine() = 0; +}; + +class ASResource +{ + public: + void buildAssignmentOperators(vector<const string*> &assignmentOperators); + void buildCastOperators(vector<const string*> &castOperators); + void buildHeaders(vector<const string*> &headers, int fileType, bool beautifier=false); + void buildNonAssignmentOperators(vector<const string*> &nonAssignmentOperators); + void buildNonParenHeaders(vector<const string*> &nonParenHeaders, int fileType, bool beautifier=false); + void buildOperators(vector<const string*> &operators); + void buildPreBlockStatements(vector<const string*> &preBlockStatements); + void buildPreCommandHeaders(vector<const string*> &preCommandHeaders); + void buildPreDefinitionHeaders(vector<const string*> &preDefinitionHeaders); + + public: + static const string AS_IF, AS_ELSE; + static const string AS_DO, AS_WHILE; + static const string AS_FOR; + static const string AS_SWITCH, AS_CASE, AS_DEFAULT; + static const string AS_TRY, AS_CATCH, AS_THROWS, AS_FINALLY; + static const string AS_PUBLIC, AS_PROTECTED, AS_PRIVATE; + static const string AS_CLASS, AS_STRUCT, AS_UNION, AS_INTERFACE, AS_NAMESPACE, AS_EXTERN; + static const string AS_STATIC; + static const string AS_CONST; + static const string AS_SYNCHRONIZED; + static const string AS_OPERATOR, AS_TEMPLATE; + static const string AS_OPEN_BRACKET, AS_CLOSE_BRACKET; + static const string AS_OPEN_LINE_COMMENT, AS_OPEN_COMMENT, AS_CLOSE_COMMENT; + static const string AS_BAR_DEFINE, AS_BAR_INCLUDE, AS_BAR_IF, AS_BAR_EL, AS_BAR_ENDIF; + static const string AS_RETURN; + static const string AS_ASSIGN, AS_PLUS_ASSIGN, AS_MINUS_ASSIGN, AS_MULT_ASSIGN; + static const string AS_DIV_ASSIGN, AS_MOD_ASSIGN, AS_XOR_ASSIGN, AS_OR_ASSIGN, AS_AND_ASSIGN; + static const string AS_GR_GR_ASSIGN, AS_LS_LS_ASSIGN, AS_GR_GR_GR_ASSIGN, AS_LS_LS_LS_ASSIGN; + static const string AS_EQUAL, AS_PLUS_PLUS, AS_MINUS_MINUS, AS_NOT_EQUAL, AS_GR_EQUAL, AS_GR_GR_GR, AS_GR_GR; + static const string AS_LS_EQUAL, AS_LS_LS_LS, AS_LS_LS, AS_ARROW, AS_AND, AS_OR; + static const string AS_COLON_COLON, AS_PAREN_PAREN, AS_BLPAREN_BLPAREN; + static const string AS_PLUS, AS_MINUS, AS_MULT, AS_DIV, AS_MOD, AS_GR, AS_LS; + static const string AS_NOT, AS_BIT_XOR, AS_BIT_OR, AS_BIT_AND, AS_BIT_NOT; + static const string AS_QUESTION, AS_COLON, AS_SEMICOLON, AS_COMMA; + static const string AS_ASM; + static const string AS_FOREACH, AS_LOCK, AS_UNSAFE, AS_FIXED; + static const string AS_GET, AS_SET, AS_ADD, AS_REMOVE; + static const string AS_CONST_CAST, AS_DYNAMIC_CAST, AS_REINTERPRET_CAST, AS_STATIC_CAST; +}; + +class ASBeautifier : protected ASResource +{ + public: + ASBeautifier(); + virtual ~ASBeautifier(); + virtual void init(ASSourceIterator* iter); // pointer to dynamically created iterator. + void init(); + virtual bool hasMoreLines() const; + virtual string nextLine(); + virtual string beautify(const string &line); + void setTabIndentation(int length = 4, bool forceTabs = false); + void setSpaceIndentation(int length = 4); + void setMaxInStatementIndentLength(int max); + void setMinConditionalIndentLength(int min); + void setClassIndent(bool state); + void setSwitchIndent(bool state); + void setCaseIndent(bool state); + void setBracketIndent(bool state); + void setBlockIndent(bool state); + void setNamespaceIndent(bool state); + void setLabelIndent(bool state); + void setCStyle(); + void setJavaStyle(); + void setSharpStyle(); + void setEmptyLineFill(bool state); + void setPreprocessorIndent(bool state); + int getIndentLength(void); + string getIndentString(void); + bool getCaseIndent(void); + bool getCStyle(void); + bool getJavaStyle(void); + bool getSharpStyle(void); + bool getEmptyLineFill(void); + + protected: + int getNextProgramCharDistance(const string &line, int i); +// bool isLegalNameChar(char ch) const; + const string *findHeader(const string &line, int i, + const vector<const string*> &possibleHeaders, + bool checkBoundry = true); + string trim(const string &str); + int indexOf(vector<const string*> &container, const string *element); + int fileType; + bool isCStyle; + bool isJavaStyle; + bool isSharpStyle; + + // variables set by ASFormatter - must be updated in preprocessor + int inLineNumber; // for debugging + int outLineNumber; // for debugging + bool lineCommentNoBeautify; + bool isNonInStatementArray; + + private: + ASBeautifier(const ASBeautifier ©); + void operator=(ASBeautifier&); // not to be implemented + + void initStatic(); + void registerInStatementIndent(const string &line, int i, int spaceTabCount, + int minIndent, bool updateParenStack); + string preLineWS(int spaceTabCount, int tabCount); + + static vector<const string*> headers; + static vector<const string*> nonParenHeaders; + static vector<const string*> preBlockStatements; + static vector<const string*> assignmentOperators; + static vector<const string*> nonAssignmentOperators; + + ASSourceIterator *sourceIterator; + vector<ASBeautifier*> *waitingBeautifierStack; + vector<ASBeautifier*> *activeBeautifierStack; + vector<int> *waitingBeautifierStackLengthStack; + vector<int> *activeBeautifierStackLengthStack; + vector<const string*> *headerStack; + vector< vector<const string*>* > *tempStacks; + vector<int> *blockParenDepthStack; + vector<bool> *blockStatementStack; + vector<bool> *parenStatementStack; + vector<int> *inStatementIndentStack; + vector<int> *inStatementIndentStackSizeStack; + vector<int> *parenIndentStack; + vector<bool> *bracketBlockStateStack; + string indentString; + const string *currentHeader; + const string *previousLastLineHeader; + const string *immediatelyPreviousAssignmentOp; + const string *probationHeader; + bool isInQuote; + bool isInComment; + bool isInCase; + bool isInQuestion; + bool isInStatement; + bool isInHeader; + bool isInOperator; + bool isInTemplate; + bool isInDefine; + bool isInDefineDefinition; + bool classIndent; + bool isInClassHeader; + bool isInClassHeaderTab; + bool switchIndent; + bool caseIndent; + bool namespaceIndent; + bool bracketIndent; + bool blockIndent; + bool labelIndent; + bool preprocessorIndent; + bool isInConditional; + bool isMinimalConditinalIndentSet; + bool shouldForceTabIndentation; + bool emptyLineFill; + bool backslashEndsPrevLine; + bool blockCommentNoIndent; + bool blockCommentNoBeautify; + bool previousLineProbationTab; + int minConditionalIndent; + int parenDepth; + int indentLength; + int blockTabCount; + int leadingWhiteSpaces; + int maxInStatementIndent; + int templateDepth; + int prevFinalLineSpaceTabCount; + int prevFinalLineTabCount; + int defineTabCount; + char quoteChar; + char prevNonSpaceCh; + char currentNonSpaceCh; + char currentNonLegalCh; + char prevNonLegalCh; + char peekNextChar(string &line, int i); + + protected: // inline functions + // check if a specific character can be used in a legal variable/method/class name + inline bool isLegalNameChar(char ch) const { + return (isalnum(ch) || ch == '.' || ch == '_' || (isJavaStyle && ch == '$') || (isCStyle && ch == '~')); + } + + // check if a specific character is a whitespace character + inline bool isWhiteSpace(char ch) const { + return (ch == ' ' || ch == '\t'); + } +}; + + +class ASEnhancer +{ + public: + // functions + ASEnhancer(); + ~ASEnhancer(); + void init(int, string, bool, bool, bool, bool, bool); + void enhance(string &line); + + private: + // set by init function + int indentLength; + bool useTabs; + bool isCStyle; + bool isJavaStyle; + bool isSharpStyle; + bool caseIndent; + bool emptyLineFill; + + // parsing variables + int lineNumber; + bool isInQuote; + bool isInComment; + char quoteChar; + + // unindent variables + int bracketCount; + int switchDepth; + bool lookingForCaseBracket; + bool unindentNextLine; + + // stringstream for trace + stringstream *traceOut; + + private: // private functions + bool findKeyword(const string &line, int i, const char *header) const; + int indentLine(string &line, const int indent) const; + int unindentLine(string &line, const int unindent) const; + + private: + // struct used by ParseFormattedLine function + // contains variables used to unindent the case blocks + struct switchVariables { + int switchBracketCount; + int unindentDepth; + bool unindentCase; + + switchVariables() { // constructor + switchBracketCount = 0; + unindentDepth = 0; + unindentCase = false; + } + }; + + private: // inline functions + // check if a specific character can be used in a legal variable/method/class name + inline bool isLegalNameCharX(char ch) const { + return (isalnum(ch) || ch == '.' || ch == '_' || (isJavaStyle && ch == '$') || (isCStyle && ch == '~')); + } + + // check if a specific character is a whitespace character + inline bool isWhiteSpaceX(char ch) const { + return (ch == ' ' || ch == '\t'); + } +}; + + +class ASFormatter : public ASBeautifier, private ASEnhancer +{ + public: + ASFormatter(); + virtual ~ASFormatter(); + virtual void init(ASSourceIterator* iter); + virtual bool hasMoreLines() const; + virtual string nextLine(); + void setBracketFormatMode(BracketMode mode); + void setBreakClosingHeaderBracketsMode(bool state); + void setOperatorPaddingMode(bool mode); + void setParensOutsidePaddingMode(bool mode); + void setParensInsidePaddingMode(bool mode); + void setParensUnPaddingMode(bool state); + void setBreakOneLineBlocksMode(bool state); + void setSingleStatementsMode(bool state); + void setTabSpaceConversionMode(bool state); + void setBreakBlocksMode(bool state); + void setBreakClosingHeaderBlocksMode(bool state); + void setBreakElseIfsMode(bool state); + string fileName; + + private: + void ASformatter(ASFormatter ©); // not to be imlpemented + void operator=(ASFormatter&); // not to be implemented + void staticInit(); + void goForward(int i); + void trimNewLine(); + char peekNextChar() const; + BracketType getBracketType() const; + bool getNextChar(); + bool isBeforeComment() const; + bool isBeforeLineEndComment(int startPos) const; + bool isPointerOrReference() const; + bool isUnaryMinus() const; + bool isInExponent() const; + bool isOneLineBlockReached() const; +// bool isNextCharWhiteSpace() const; + bool lineBeginsWith(char charToCheck) const; + void appendChar(char ch, bool canBreakLine = true); + void appendCharInsideComments(); + void appendSequence(const string &sequence, bool canBreakLine = true); + void appendSpacePad(); + void appendSpaceAfter(); + void breakLine(); + void padOperators(const string *newOperator); + void padParens(); + void formatBrackets(BracketType bracketType); + void formatArrayBrackets(BracketType bracketType, bool isOpeningArrayBracket); + void adjustComments(); + const string *findHeader(const vector<const string*> &headers, bool checkBoundry = true); + + static vector<const string*> headers; + static vector<const string*> nonParenHeaders; + static vector<const string*> preDefinitionHeaders; + static vector<const string*> preCommandHeaders; + static vector<const string*> operators; + static vector<const string*> assignmentOperators; + static vector<const string*> castOperators; + + ASSourceIterator *sourceIterator; + vector<const string*> *preBracketHeaderStack; + vector<BracketType> *bracketTypeStack; + vector<int> *parenStack; + string readyFormattedLine; + string currentLine; + string formattedLine; + const string *currentHeader; + const string *previousOperator; // used ONLY by pad=oper + char currentChar; + char previousChar; + char previousNonWSChar; + char previousCommandChar; + char quoteChar; + int charNum; + int spacePadNum; + int templateDepth; + int traceFileNumber; + size_t formattedLineCommentNum; // comment location on formattedLine + size_t previousReadyFormattedLineLength; + BracketMode bracketFormatMode; + BracketType previousBracketType; + bool isVirgin; + bool shouldPadOperators; + bool shouldPadParensOutside; + bool shouldPadParensInside; + bool shouldUnPadParens; + bool shouldConvertTabs; + bool isInLineComment; + bool isInComment; + bool isInPreprocessor; + bool isInTemplate; // true both in template definitions (e.g. template<class A>) and template usage (e.g. F<int>). + bool doesLineStartComment; + bool isInQuote; + bool isInBlParen; + bool isSpecialChar; + bool isNonParenHeader; + bool foundQuestionMark; + bool foundPreDefinitionHeader; + bool foundNamespaceHeader; + bool foundClassHeader; + bool foundPreCommandHeader; + bool foundCastOperator; + bool isInLineBreak; +// bool isInClosingBracketLineBreak; + bool endOfCodeReached; + bool lineCommentNoIndent; + bool isLineReady; + bool isPreviousBracketBlockRelated; + bool isInPotentialCalculation; + bool isCharImmediatelyPostComment; + bool isPreviousCharPostComment; + bool isCharImmediatelyPostLineComment; + bool isCharImmediatelyPostOpenBlock; + bool isCharImmediatelyPostCloseBlock; + bool isCharImmediatelyPostTemplate; + bool shouldBreakOneLineBlocks; + bool shouldReparseCurrentChar; + bool shouldBreakOneLineStatements; + bool shouldBreakLineAfterComments; + bool shouldBreakClosingHeaderBrackets; + bool shouldBreakElseIfs; + bool passedSemicolon; + bool passedColon; + bool isImmediatelyPostComment; + bool isImmediatelyPostLineComment; + bool isImmediatelyPostEmptyBlock; + bool isImmediatelyPostPreprocessor; + + bool shouldBreakBlocks; + bool shouldBreakClosingHeaderBlocks; + bool isPrependPostBlockEmptyLineRequested; + bool isAppendPostBlockEmptyLineRequested; + + bool prependEmptyLine; + bool appendOpeningBracket; + bool foundClosingHeader; + + bool isInHeader; + bool isImmediatelyPostHeader; + + private: // inline functions + // append the CURRENT character (curentChar)to the current formatted line. + inline void appendCurrentChar(bool canBreakLine = true) { + appendChar(currentChar, canBreakLine); + } + + // check if a specific sequence exists in the current placement of the current line + inline bool isSequenceReached(const char *sequence) const { + return currentLine.compare(charNum, strlen(sequence), sequence) == 0; + } +}; + +} // end of namespace astyle + +#endif // closes ASTYLE_H + diff --git a/lib/astyle/compiler_defines.h b/lib/astyle/compiler_defines.h new file mode 100644 index 00000000..347ac40d --- /dev/null +++ b/lib/astyle/compiler_defines.h @@ -0,0 +1,49 @@ + +/* + * Copyright (c) 1998, 1999 Tal Davidson. All rights reserved. + * + * compiler_defines.h (1 January 1999) + * by Tal Davidson (davidsont@bigfoot.com) + * This file is a part of "Artistic Style" - an indentater and reformatter + * of C++, C, and Java source files. + * + * The "Artistic Style" project, including all files needed to compile it, + * is free software; you can redistribute it and/or use it and/or modify it + * under the terms of EITHER the "Artistic License" OR + * the GNU General Public License as published by the Free Software Foundation; + * either version 2 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. + * + * You should have received a copy of EITHER the "Artistic License" or + * the GNU General Public License along with this program. + */ + + + + + +/* + * comment out the line below if your compiler does NOT understand NAMESPACES + */ +#define USES_NAMESPACE + + +#if defined(__GNUC__) && __GNUC__ < 3 +// for G++ implementation of string.compare: +#define COMPARE(place, length, str) compare((str), (place), (length)) +#else +// for standard implementation of string.compare: +#define COMPARE(place, length, str) compare((place), (length), (str)) +#endif + + +// Fix by John A. McNamara +// Get rid of annoying MSVC warnings on debug builds about lengths of +// identifiers in template instantiations. +#ifdef _MSC_VER +#pragma warning( disable:4786 ) +#endif + |