You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdevelop/lib/astyle/ASFormatter.cpp

2198 lines
61 KiB

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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 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