/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 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 #include #include #ifdef __VMS #include #else #include #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 ASFormatter::headers; vector ASFormatter::nonParenHeaders; vector ASFormatter::preDefinitionHeaders; vector ASFormatter::preCommandHeaders; vector ASFormatter::operators; vector ASFormatter::assignmentOperators; vector 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); INIT_CONTAINER(bracketTypeStack, new vector); bracketTypeStack->push_back(NULL_TYPE); INIT_CONTAINER(parenStack, new vector); 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; iback() == 0 && !isBeforeComment()) { shouldReparseCurrentChar = true; isInLineBreak = true; continue; } } // Check if in template declaration, e.g. foo or foo // 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 || oper == &AS_BIT_AND // reference, e.g. A || oper == &AS_MULT // pointer, e.g. A || 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 //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 &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