kde-extraapps/kdevelop/formatters/astyle/lib/ASBeautifier.cpp
2015-07-26 14:23:17 +03:00

2870 lines
78 KiB
C++

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* ASBeautifier.cpp
*
* Copyright (C) 2006-2011 by Jim Pattee <jimp03@email.com>
* Copyright (C) 1998-2002 by Tal Davidson
* <http://www.gnu.org/licenses/lgpl-3.0.html>
*
* 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>
*
* Artistic Style 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 3 of the License, or
* (at your option) any later version.
*
* Artistic Style 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 Artistic Style. If not, see <http://www.gnu.org/licenses/>.
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*/
#include "astyle.h"
#include <algorithm>
#include <iostream>
namespace astyle
{
/**
* ASBeautifier's constructor
*/
ASBeautifier::ASBeautifier()
{
waitingBeautifierStack = NULL;
activeBeautifierStack = NULL;
waitingBeautifierStackLengthStack = NULL;
activeBeautifierStackLengthStack = NULL;
headerStack = NULL;
tempStacks = NULL;
blockParenDepthStack = NULL;
blockStatementStack = NULL;
parenStatementStack = NULL;
bracketBlockStateStack = NULL;
inStatementIndentStack = NULL;
inStatementIndentStackSizeStack = NULL;
parenIndentStack = NULL;
sourceIterator = NULL;
isMinConditionalManuallySet = false;
isModeManuallySet = false;
shouldForceTabIndentation = false;
setSpaceIndentation(4);
setMinConditionalIndentOption(MINCOND_TWO);
setMaxInStatementIndentLength(40);
classInitializerIndents = 1;
tabLength = 0;
setClassIndent(false);
setSwitchIndent(false);
setCaseIndent(false);
setBlockIndent(false);
setBracketIndent(false);
setNamespaceIndent(false);
setLabelIndent(false);
setEmptyLineFill(false);
setCStyle();
setPreprocessorIndent(false);
// initialize ASBeautifier member vectors
beautifierFileType = 9; // reset to an invalid type
headers = new vector<const string*>;
nonParenHeaders = new vector<const string*>;
assignmentOperators = new vector<const string*>;
nonAssignmentOperators = new vector<const string*>;
preBlockStatements = new vector<const string*>;
preCommandHeaders = new vector<const string*>;
indentableHeaders = new vector<const string*>;
}
/**
* ASBeautifier's copy constructor
* must explicitly call the base class copy constructor
*/
ASBeautifier::ASBeautifier(const ASBeautifier &other) : ASBase(other)
{
// Copy the vector objects to vectors in the new ASBeautifier
// object so the new object can be destroyed without deleting
// the vector objects in the copied vector.
// This is the reason a copy constructor is needed.
// these don't need to copy the stack
waitingBeautifierStack = NULL;
activeBeautifierStack = NULL;
waitingBeautifierStackLengthStack = NULL;
activeBeautifierStackLengthStack = NULL;
// vector '=' operator performs a DEEP copy of all elements in the vector
headerStack = new vector<const string*>;
*headerStack = *other.headerStack;
tempStacks = copyTempStacks(other);
blockParenDepthStack = new vector<int>;
*blockParenDepthStack = *other.blockParenDepthStack;
blockStatementStack = new vector<bool>;
*blockStatementStack = *other.blockStatementStack;
parenStatementStack = new vector<bool>;
*parenStatementStack = *other.parenStatementStack;
bracketBlockStateStack = new vector<bool>;
*bracketBlockStateStack = *other.bracketBlockStateStack;
inStatementIndentStack = new vector<int>;
*inStatementIndentStack = *other.inStatementIndentStack;
inStatementIndentStackSizeStack = new vector<int>;
*inStatementIndentStackSizeStack = *other.inStatementIndentStackSizeStack;
parenIndentStack = new vector<int>;
*parenIndentStack = *other.parenIndentStack;
// Copy the pointers to vectors.
// This is ok because the original ASBeautifier object
// is not deleted until end of job.
beautifierFileType = other.beautifierFileType;
headers = other.headers;
nonParenHeaders = other.nonParenHeaders;
assignmentOperators = other.assignmentOperators;
nonAssignmentOperators = other.nonAssignmentOperators;
preBlockStatements = other.preBlockStatements;
preCommandHeaders = other.preCommandHeaders;
indentableHeaders = other.indentableHeaders;
// protected variables
// variables set by ASFormatter
// must also be updated in activeBeautifierStack
inLineNumber = other.inLineNumber;
horstmannIndentInStatement = other.horstmannIndentInStatement;
nonInStatementBracket = other.nonInStatementBracket;
lineCommentNoBeautify = other.lineCommentNoBeautify;
isNonInStatementArray = other.isNonInStatementArray;
isSharpAccessor = other.isSharpAccessor;
isSharpDelegate = other.isSharpDelegate;
isInExtern = other.isInExtern;
isInBeautifySQL = other.isInBeautifySQL;
isInIndentableStruct = other.isInIndentableStruct;
// private variables
sourceIterator = other.sourceIterator;
currentHeader = other.currentHeader;
previousLastLineHeader = other.previousLastLineHeader;
probationHeader = other.probationHeader;
lastLineHeader = other.lastLineHeader;
indentString = other.indentString;
isInQuote = other.isInQuote;
isInVerbatimQuote = other.isInVerbatimQuote;
haveLineContinuationChar = other.haveLineContinuationChar;
isInAsm = other.isInAsm;
isInAsmOneLine = other.isInAsmOneLine;
isInAsmBlock = other.isInAsmBlock;
isInComment = other.isInComment;
isInPreprocessorComment = other.isInPreprocessorComment;
isInHorstmannComment = other.isInHorstmannComment;
isInCase = other.isInCase;
isInQuestion = other.isInQuestion;
isInStatement = other.isInStatement;
isInHeader = other.isInHeader;
isInTemplate = other.isInTemplate;
isInDefine = other.isInDefine;
isInDefineDefinition = other.isInDefineDefinition;
classIndent = other.classIndent;
isInClassInitializer = other.isInClassInitializer;
isInClassHeaderTab = other.isInClassHeaderTab;
isInEnum = other.isInEnum;
switchIndent = other.switchIndent;
caseIndent = other.caseIndent;
namespaceIndent = other.namespaceIndent;
bracketIndent = other.bracketIndent;
blockIndent = other.blockIndent;
labelIndent = other.labelIndent;
preprocessorIndent = other.preprocessorIndent;
isInConditional = other.isInConditional;
isMinConditionalManuallySet = other.isMinConditionalManuallySet;
isModeManuallySet = other.isModeManuallySet;
shouldForceTabIndentation = other.shouldForceTabIndentation;
emptyLineFill = other.emptyLineFill;
lineOpensComment = other.lineOpensComment;
backslashEndsPrevLine = other.backslashEndsPrevLine;
blockCommentNoIndent = other.blockCommentNoIndent;
blockCommentNoBeautify = other.blockCommentNoBeautify;
previousLineProbationTab = other.previousLineProbationTab;
lineBeginsWithBracket = other.lineBeginsWithBracket;
shouldIndentBrackettedLine = other.shouldIndentBrackettedLine;
isInClass = other.isInClass;
isInSwitch = other.isInSwitch;
foundPreCommandHeader = other.foundPreCommandHeader;
indentCount = other.indentCount;
spaceIndentCount = other.spaceIndentCount;
lineOpeningBlocksNum = other.lineOpeningBlocksNum;
lineClosingBlocksNum = other.lineClosingBlocksNum;
fileType = other.fileType;
minConditionalOption = other.minConditionalOption;
minConditionalIndent = other.minConditionalIndent;
parenDepth = other.parenDepth;
indentLength = other.indentLength;
tabLength = other.tabLength;
blockTabCount = other.blockTabCount;
maxInStatementIndent = other.maxInStatementIndent;
classInitializerIndents = other.classInitializerIndents;
templateDepth = other.templateDepth;
preprocessorCppExternCBracket = other.preprocessorCppExternCBracket;
prevFinalLineSpaceIndentCount = other.prevFinalLineSpaceIndentCount;
prevFinalLineIndentCount = other.prevFinalLineIndentCount;
defineIndentCount = other.defineIndentCount;
quoteChar = other.quoteChar;
prevNonSpaceCh = other.prevNonSpaceCh;
currentNonSpaceCh = other.currentNonSpaceCh;
currentNonLegalCh = other.currentNonLegalCh;
prevNonLegalCh = other.prevNonLegalCh;
}
/**
* ASBeautifier's destructor
*/
ASBeautifier::~ASBeautifier()
{
deleteContainer(waitingBeautifierStack);
deleteContainer(activeBeautifierStack);
deleteContainer(waitingBeautifierStackLengthStack);
deleteContainer(activeBeautifierStackLengthStack);
deleteContainer(headerStack);
deleteContainer(tempStacks);
deleteContainer(blockParenDepthStack);
deleteContainer(blockStatementStack);
deleteContainer(parenStatementStack);
deleteContainer(bracketBlockStateStack);
deleteContainer(inStatementIndentStack);
deleteContainer(inStatementIndentStackSizeStack);
deleteContainer(parenIndentStack);
}
/**
* initialize the ASBeautifier.
*
* init() should be called every time a ABeautifier object is to start
* beautifying a NEW source file.
* init() recieves a pointer to a ASSourceIterator object that will be
* used to iterate through the source code.
*
* @param iter a pointer to the ASSourceIterator or ASStreamIterator object.
*/
void ASBeautifier::init(ASSourceIterator* iter)
{
sourceIterator = iter;
init();
}
/**
* initialize the ASBeautifier.
*/
void ASBeautifier::init()
{
initVectors();
ASBase::init(getFileType());
initContainer(waitingBeautifierStack, new vector<ASBeautifier*>);
initContainer(activeBeautifierStack, new vector<ASBeautifier*>);
initContainer(waitingBeautifierStackLengthStack, new vector<int>);
initContainer(activeBeautifierStackLengthStack, new vector<int>);
initContainer(headerStack, new vector<const string*>);
initContainer(tempStacks, new vector<vector<const string*>*>);
tempStacks->push_back(new vector<const string*>);
initContainer(blockParenDepthStack, new vector<int>);
initContainer(blockStatementStack, new vector<bool>);
initContainer(parenStatementStack, new vector<bool>);
initContainer(bracketBlockStateStack, new vector<bool>);
bracketBlockStateStack->push_back(true);
initContainer(inStatementIndentStack, new vector<int>);
initContainer(inStatementIndentStackSizeStack, new vector<int>);
inStatementIndentStackSizeStack->push_back(0);
initContainer(parenIndentStack, new vector<int>);
previousLastLineHeader = NULL;
currentHeader = NULL;
isInQuote = false;
isInVerbatimQuote = false;
haveLineContinuationChar = false;
isInAsm = false;
isInAsmOneLine = false;
isInAsmBlock = false;
isInComment = false;
isInPreprocessorComment = false;
isInHorstmannComment = false;
isInStatement = false;
isInCase = false;
isInQuestion = false;
isInClassInitializer = false;
isInClassHeaderTab = false;
isInEnum = false;
isInHeader = false;
isInTemplate = false;
isInConditional = false;
indentCount = 0;
spaceIndentCount = 0;
lineOpeningBlocksNum = 0;
lineClosingBlocksNum = 0;
templateDepth = 0;
parenDepth = 0;
blockTabCount = 0;
preprocessorCppExternCBracket = 0;
prevFinalLineSpaceIndentCount = 0;
prevFinalLineIndentCount = 0;
defineIndentCount = 0;
prevNonSpaceCh = '{';
currentNonSpaceCh = '{';
prevNonLegalCh = '{';
currentNonLegalCh = '{';
quoteChar = ' ';
probationHeader = NULL;
lastLineHeader = NULL;
backslashEndsPrevLine = false;
lineOpensComment = false;
isInDefine = false;
isInDefineDefinition = false;
lineCommentNoBeautify = false;
blockCommentNoIndent = false;
blockCommentNoBeautify = false;
previousLineProbationTab = false;
lineBeginsWithBracket = false;
shouldIndentBrackettedLine = true;
isInClass = false;
isInSwitch = false;
foundPreCommandHeader = false;
isNonInStatementArray = false;
isSharpAccessor = false;
isSharpDelegate = false;
isInExtern = false;
isInBeautifySQL = false;
isInIndentableStruct = false;
inLineNumber = 0;
horstmannIndentInStatement = 0;
nonInStatementBracket = 0;
}
/*
* initialize the vectors
*/
void ASBeautifier::initVectors()
{
if (fileType == beautifierFileType) // don't build unless necessary
return;
beautifierFileType = fileType;
headers->clear();
nonParenHeaders->clear();
assignmentOperators->clear();
nonAssignmentOperators->clear();
preBlockStatements->clear();
preCommandHeaders->clear();
indentableHeaders->clear();
ASResource::buildHeaders(headers, fileType, true);
ASResource::buildNonParenHeaders(nonParenHeaders, fileType, true);
ASResource::buildAssignmentOperators(assignmentOperators);
ASResource::buildNonAssignmentOperators(nonAssignmentOperators);
ASResource::buildPreBlockStatements(preBlockStatements, fileType);
ASResource::buildPreCommandHeaders(preCommandHeaders, fileType);
ASResource::buildIndentableHeaders(indentableHeaders);
}
/**
* set indentation style to C/C++.
*/
void ASBeautifier::setCStyle()
{
fileType = C_TYPE;
}
/**
* set indentation style to Java.
*/
void ASBeautifier::setJavaStyle()
{
fileType = JAVA_TYPE;
}
/**
* set indentation style to C#.
*/
void ASBeautifier::setSharpStyle()
{
fileType = SHARP_TYPE;
}
/**
* set mode manually set flag
*/
void ASBeautifier::setModeManuallySet(bool state)
{
isModeManuallySet = state;
}
/**
* set tabLength equal to indentLength.
* This is done when tabLength is not explicitely set by
* "indent=force-tab-x"
*
*/
void ASBeautifier::setDefaultTabLength()
{
tabLength = indentLength;
}
/**
* indent using a different tab setting for indent=force-tab
*
* @param length number of spaces per tab.
*/
void ASBeautifier::setForceTabXIndentation(int length)
{
// set tabLength instead of indentLength
indentString = "\t";
tabLength = length;
shouldForceTabIndentation = true;
}
/**
* indent using one tab per indentation
*/
void ASBeautifier::setTabIndentation(int length, bool forceTabs)
{
indentString = "\t";
indentLength = length;
shouldForceTabIndentation = forceTabs;
}
/**
* indent using a number of spaces per indentation.
*
* @param length number of spaces per indent.
*/
void ASBeautifier::setSpaceIndentation(int length)
{
indentString = string(length, ' ');
indentLength = length;
}
/**
* set the maximum indentation between two lines in a multi-line statement.
*
* @param max maximum indentation length.
*/
void ASBeautifier::setMaxInStatementIndentLength(int max)
{
maxInStatementIndent = max;
}
/**
* set the minimum conditional indentation option.
*
* @param min minimal indentation option.
*/
void ASBeautifier::setMinConditionalIndentOption(int min)
{
minConditionalOption = min;
}
/**
* set minConditionalIndent from the minConditionalOption.
*/
void ASBeautifier::setMinConditionalIndentLength()
{
if (minConditionalOption == MINCOND_ZERO)
minConditionalIndent = 0;
else if (minConditionalOption == MINCOND_ONE)
minConditionalIndent = indentLength;
else if (minConditionalOption == MINCOND_ONEHALF)
minConditionalIndent = indentLength / 2;
// minConditionalOption = INDENT_TWO
else minConditionalIndent = indentLength * 2;
}
/**
* set the state of the bracket indentation option. If true, brackets will
* be indented one additional indent.
*
* @param state state of option.
*/
void ASBeautifier::setBracketIndent(bool state)
{
bracketIndent = state;
}
/**
* set the state of the block indentation option. If true, entire blocks
* will be indented one additional indent, similar to the GNU indent style.
*
* @param state state of option.
*/
void ASBeautifier::setBlockIndent(bool state)
{
blockIndent = state;
}
/**
* set the state of the class indentation option. If true, C++ class
* definitions will be indented one additional indent.
*
* @param state state of option.
*/
void ASBeautifier::setClassIndent(bool state)
{
classIndent = state;
}
/**
* set the state of the switch indentation option. If true, blocks of 'switch'
* statements will be indented one additional indent.
*
* @param state state of option.
*/
void ASBeautifier::setSwitchIndent(bool state)
{
switchIndent = state;
}
/**
* set the state of the case indentation option. If true, lines of 'case'
* statements will be indented one additional indent.
*
* @param state state of option.
*/
void ASBeautifier::setCaseIndent(bool state)
{
caseIndent = state;
}
/**
* set the state of the namespace indentation option.
* If true, blocks of 'namespace' statements will be indented one
* additional indent. Otherwise, NO indentation will be added.
*
* @param state state of option.
*/
void ASBeautifier::setNamespaceIndent(bool state)
{
namespaceIndent = state;
}
/**
* set the state of the label indentation option.
* If true, labels will be indented one indent LESS than the
* current indentation level.
* If false, labels will be flushed to the left with NO
* indent at all.
*
* @param state state of option.
*/
void ASBeautifier::setLabelIndent(bool state)
{
labelIndent = state;
}
/**
* set the state of the preprocessor indentation option.
* If true, multiline #define statements will be indented.
*
* @param state state of option.
*/
void ASBeautifier::setPreprocessorIndent(bool state)
{
preprocessorIndent = state;
}
/**
* set the state of the empty line fill option.
* If true, empty lines will be filled with the whitespace.
* of their previous lines.
* If false, these lines will remain empty.
*
* @param state state of option.
*/
void ASBeautifier::setEmptyLineFill(bool state)
{
emptyLineFill = state;
}
/**
* get the file type.
*/
int ASBeautifier::getFileType() const
{
return fileType;
}
/**
* get the number of spaces per indent
*
* @return value of indentLength option.
*/
int ASBeautifier::getIndentLength(void) const
{
return indentLength;
}
/**
* get the char used for indentation, space or tab
*
* @return the char used for indentation.
*/
string ASBeautifier::getIndentString(void) const
{
return indentString;
}
/**
* get mode manually set flag
*/
bool ASBeautifier::getModeManuallySet() const
{
return isModeManuallySet;
}
/**
* get the state of the force tab indentation option.
*
* @return state of force tab indentation.
*/
bool ASBeautifier::getForceTabIndentation(void) const
{
return shouldForceTabIndentation;
}
/**
* get the state of the block indentation option.
*
* @return state of blockIndent option.
*/
bool ASBeautifier::getBlockIndent(void) const
{
return blockIndent;
}
/**
* get the state of the bracket indentation option.
*
* @return state of bracketIndent option.
*/
bool ASBeautifier::getBracketIndent(void) const
{
return bracketIndent;
}
/**
* get the state of the class indentation option. If true, blocks of
* the 'class' statement will be indented one additional indent.
*
* @return state of classIndent option.
*/
bool ASBeautifier::getClassIndent(void) const
{
return classIndent;
}
/**
* get the state of the switch indentation option. If true, blocks of
* the 'switch' statement will be indented one additional indent.
*
* @return state of switchIndent option.
*/
bool ASBeautifier::getSwitchIndent(void) const
{
return switchIndent;
}
/**
* get the state of the case indentation option. If true, lines of 'case'
* statements will be indented one additional indent.
*
* @return state of caseIndent option.
*/
bool ASBeautifier::getCaseIndent(void) const
{
return caseIndent;
}
/**
* get the state of the empty line fill option.
* If true, empty lines will be filled with the whitespace.
* of their previous lines.
* If false, these lines will remain empty.
*
* @return state of emptyLineFill option.
*/
bool ASBeautifier::getEmptyLineFill(void) const
{
return emptyLineFill;
}
/**
* get the state of the preprocessor indentation option.
* If true, preprocessor "define" lines will be indented.
* If false, preprocessor "define" lines will be unchanged.
*
* @return state of preprocessorIndent option.
*/
bool ASBeautifier::getPreprocessorIndent(void) const
{
return preprocessorIndent;
}
/**
* get the length of the tab indentation option.
*
* @return length of tab indent option.
*/
int ASBeautifier::getTabLength(void) const
{
return tabLength;
}
/**
* beautify a line of source code.
* every line of source code in a source code file should be sent
* one after the other to the beautify method.
*
* @return the indented line.
* @param originalLine the original unindented line.
*/
string ASBeautifier::beautify(const string &originalLine)
{
string line;
bool lineStartsInComment = false;
bool isInQuoteContinuation = isInVerbatimQuote | haveLineContinuationChar;
size_t iPrelim;
currentHeader = NULL;
lastLineHeader = NULL;
lineStartsInComment = isInComment;
blockCommentNoBeautify = blockCommentNoIndent;
isInClass = false;
isInSwitch = false;
lineBeginsWithBracket = false;
shouldIndentBrackettedLine = true;
isInAsmOneLine = false;
lineOpensComment = false;
previousLineProbationTab = false;
haveLineContinuationChar = false;
indentCount = 0;
spaceIndentCount = 0;
lineOpeningBlocksNum = 0;
lineClosingBlocksNum = 0;
// handle and remove white spaces around the line:
// If not in comment, first find out size of white space before line,
// so that possible comments starting in the line continue in
// relation to the preliminary white-space.
if (isInQuoteContinuation)
{
// trim a single space added by ASFormatter, otherwise leave it alone
if (!(originalLine.length() == 1 && originalLine[0] == ' '))
line = originalLine;
}
else if (isInComment || isInBeautifySQL)
{
// trim the end of comment and SQL lines
line = originalLine;
size_t trimEnd = line.find_last_not_of(" \t");
if (trimEnd == string::npos)
trimEnd = 0;
else
trimEnd++;
if (trimEnd < line.length())
line.erase(trimEnd);
}
else
{
line = trim(originalLine);
if (line.length() > 0 && line[0] == '{')
lineBeginsWithBracket = true;
isInHorstmannComment = false;
size_t j = line.find_first_not_of(" \t{");
if (j != string::npos && line.compare(j, 2, "/*") == 0)
{
lineOpensComment = true;
size_t k = line.find_first_not_of(" \t");
if (k != string::npos && line.compare(k, 1, "{") == 0)
isInHorstmannComment = true;
}
}
if (line.length() == 0)
{
if (backslashEndsPrevLine) // must continue to clear variables
line = ' ';
else if (emptyLineFill && !isInQuoteContinuation
&& (!headerStack->empty() || isInEnum))
return preLineWS(prevFinalLineSpaceIndentCount, prevFinalLineIndentCount);
else
return line;
}
// handle preprocessor commands
// except C# region and endregion
if (!isInComment
&& !isInQuoteContinuation
&& line.length() > 0
&& ((line[0] == '#' && !isIndentedPreprocessor(line, 0))
|| backslashEndsPrevLine))
{
if (line.length() > 0 && line[0] == '#')
processProcessor(line);
// check if the last char is a backslash
if (line.length() > 0)
backslashEndsPrevLine = (line[line.length() - 1] == '\\');
// comments within the definition line can be continued without the backslash
if (isInPreprocessorUnterminatedComment(line))
backslashEndsPrevLine = true;
// check if this line ends a multi-line #define
// if so, use the #define's cloned beautifier for the line's indentation
// and then remove it from the active beautifier stack and delete it.
if (!backslashEndsPrevLine && isInDefineDefinition && !isInDefine)
{
string beautifiedLine;
ASBeautifier* defineBeautifier;
isInDefineDefinition = false;
defineBeautifier = activeBeautifierStack->back();
activeBeautifierStack->pop_back();
beautifiedLine = defineBeautifier->beautify(line);
delete defineBeautifier;
return beautifiedLine;
}
// unless this is a multi-line #define, return this precompiler line as is.
if (!isInDefine && !isInDefineDefinition)
return originalLine;
}
// if there exists any worker beautifier in the activeBeautifierStack,
// then use it instead of me to indent the current line.
// variables set by ASFormatter must be updated.
if (!isInDefine && activeBeautifierStack != NULL && !activeBeautifierStack->empty())
{
activeBeautifierStack->back()->inLineNumber = inLineNumber;
activeBeautifierStack->back()->horstmannIndentInStatement = horstmannIndentInStatement;
activeBeautifierStack->back()->nonInStatementBracket = nonInStatementBracket;
activeBeautifierStack->back()->lineCommentNoBeautify = lineCommentNoBeautify;
activeBeautifierStack->back()->isNonInStatementArray = isNonInStatementArray;
activeBeautifierStack->back()->isSharpAccessor = isSharpAccessor;
activeBeautifierStack->back()->isSharpDelegate = isSharpDelegate;
activeBeautifierStack->back()->isInExtern = isInExtern;
activeBeautifierStack->back()->isInBeautifySQL = isInBeautifySQL;
activeBeautifierStack->back()->isInIndentableStruct = isInIndentableStruct;
// must return originalLine not the trimmed line
return activeBeautifierStack->back()->beautify(originalLine);
}
// calculate preliminary indentation based on data from past lines
if (!inStatementIndentStack->empty())
spaceIndentCount = inStatementIndentStack->back();
computePreliminaryIndentation();
iPrelim = headerStack->size();
if (!lineStartsInComment
&& isCStyle()
&& isInClass
&& classIndent
&& headerStack->size() >= 2
&& (*headerStack)[headerStack->size()-2] == &AS_CLASS
&& (*headerStack)[headerStack->size()-1] == &AS_OPEN_BRACKET
&& line.length() > 0
&& line[0] == '}'
&& bracketBlockStateStack->back() == true)
--indentCount;
else if (!lineStartsInComment
&& isInSwitch
&& switchIndent
&& headerStack->size() >= 2
&& (*headerStack)[headerStack->size()-2] == &AS_SWITCH
&& (*headerStack)[headerStack->size()-1] == &AS_OPEN_BRACKET
&& line.length() > 0
&& line[0] == '}')
--indentCount;
if (isInClassInitializer)
{
if (lineStartsInComment || lineOpensComment)
{
if (!lineBeginsWithBracket)
indentCount--;
}
else if (isCStyle() && !isClassAccessModifier(line))
{
isInClassHeaderTab = true;
indentCount += classInitializerIndents;
}
else if (blockIndent)
{
if (!lineBeginsWithBracket)
indentCount++;
}
}
// handle special case of horstmann comment in an indented class statement
if (isInClass
&& classIndent
&& isInHorstmannComment
&& !lineOpensComment
&& headerStack->size() > 1
&& (*headerStack)[headerStack->size()-2] == &AS_CLASS)
--indentCount;
// Flag an indented header in case this line is a one-line block.
// The header in the header stack will be deleted by a one-line block.
bool isInExtraHeaderIndent = false;
if (!headerStack->empty()
&& line.length() > 0
&& line[0] == '{'
&& (headerStack->back() != &AS_OPEN_BRACKET
|| probationHeader != NULL))
isInExtraHeaderIndent = true;
if (isInConditional)
--indentCount;
if (preprocessorCppExternCBracket >= 3)
--indentCount;
// parse characters in the current line.
// increment indentCount and spaceIndentCount for the current line
parseCurrentLine(line);
// handle special cases of unindentation:
// unindent a one-line statement in a header indent
if (!lineStartsInComment
&& !blockIndent
&& line.length() > 0
&& line[0] == '{'
&& headerStack->size() < iPrelim
&& isInExtraHeaderIndent
&& (lineOpeningBlocksNum > 0 && lineOpeningBlocksNum <= lineClosingBlocksNum)
&& shouldIndentBrackettedLine)
--indentCount;
/*
* if '{' doesn't follow an immediately previous '{' in the headerStack
* (but rather another header such as "for" or "if", then unindent it
* by one indentation relative to its block.
*/
else if (!lineStartsInComment
&& !blockIndent
&& line.length() > 0
&& line[0] == '{'
&& !(lineOpeningBlocksNum > 0 && lineOpeningBlocksNum <= lineClosingBlocksNum)
&& (headerStack->size() > 1 && (*headerStack)[headerStack->size()-2] != &AS_OPEN_BRACKET)
&& shouldIndentBrackettedLine)
--indentCount;
// must check one less in headerStack if more than one header on a line (allow-addins)...
else if (!lineStartsInComment
&& headerStack->size() > iPrelim + 1
&& !blockIndent
&& line.length() > 0
&& line[0] == '{'
&& !(lineOpeningBlocksNum > 0 && lineOpeningBlocksNum <= lineClosingBlocksNum)
&& (headerStack->size() > 2 && (*headerStack)[headerStack->size()-3] != &AS_OPEN_BRACKET)
&& shouldIndentBrackettedLine)
--indentCount;
// unindent a closing bracket...
else if (!lineStartsInComment
&& line.length() > 0
&& line[0] == '}'
&& shouldIndentBrackettedLine)
--indentCount;
// correctly indent one-line-blocks...
else if (!lineStartsInComment
&& line.length() > 0
&& lineOpeningBlocksNum > 0
&& lineOpeningBlocksNum == lineClosingBlocksNum
&& previousLineProbationTab)
--indentCount;
// correctly indent class continuation lines...
else if (!lineStartsInComment
&& !lineOpensComment
&& isInClassHeaderTab
&& !blockIndent
&& line.length() > 0
&& lineOpeningBlocksNum == 0
&& lineOpeningBlocksNum == lineClosingBlocksNum
&& (!headerStack->empty() && headerStack->back() == &AS_CLASS))
--indentCount;
if (indentCount < 0)
indentCount = 0;
// take care of extra bracket indentatation option...
if (!lineStartsInComment
&& bracketIndent
&& shouldIndentBrackettedLine
&& line.length() > 0
&& (line[0] == '{' || line[0] == '}'))
indentCount++;
if (isInDefine)
{
if (line.length() > 0 && line[0] == '#')
{
// the 'define' does not have to be attached to the '#'
string preproc = trim(line.substr(1));
if (preproc.compare(0, 6, "define") == 0)
{
if (!inStatementIndentStack->empty()
&& inStatementIndentStack->back() > 0)
{
defineIndentCount = indentCount;
}
else
{
defineIndentCount = indentCount - 1;
indentCount--;
}
}
}
indentCount -= defineIndentCount;
}
if (indentCount < 0)
indentCount = 0;
if (lineCommentNoBeautify || blockCommentNoBeautify || isInQuoteContinuation)
indentCount = spaceIndentCount = 0;
// finally, insert indentations into begining of line
if (shouldForceTabIndentation)
{
if (tabLength != indentLength)
{
// adjust for different tab length
int indentCountOrig = indentCount;
int spaceIndentCountOrig = spaceIndentCount;
indentCount = ((indentCountOrig * indentLength) + spaceIndentCountOrig) / tabLength;
spaceIndentCount = ((indentCountOrig * indentLength) + spaceIndentCountOrig) % tabLength;
}
else
{
indentCount += spaceIndentCount / indentLength;
spaceIndentCount = spaceIndentCount % indentLength;
}
}
string outBuffer = preLineWS(spaceIndentCount, indentCount) + line;
prevFinalLineSpaceIndentCount = spaceIndentCount;
prevFinalLineIndentCount = indentCount;
if (lastLineHeader != NULL)
previousLastLineHeader = lastLineHeader;
return outBuffer;
}
string ASBeautifier::preLineWS(int spaceTabCount_, int tabCount_)
{
string ws;
for (int i = 0; i < tabCount_; i++)
ws += indentString;
while ((spaceTabCount_--) > 0)
ws += string(" ");
return ws;
}
bool ASBeautifier::isClassAccessModifier(const string &line) const
{
size_t firstChar = line.find_first_not_of(" \t");
if (firstChar == string::npos)
return false;
// bypass a colon
if (line[firstChar] == ':')
{
firstChar = line.find_first_not_of(" \t");
if (firstChar == string::npos)
return false;
}
if (line.compare(firstChar, 7, "public ") == 0
|| line.compare(firstChar, 8, "private ") == 0
|| line.compare(firstChar, 10, "protected ") == 0)
return true;
return false;
}
/**
* register an in-statement indent.
*/
void ASBeautifier::registerInStatementIndent(const string &line, int i, int spaceTabCount_,
int tabIncrementIn, int minIndent, bool updateParenStack)
{
int inStatementIndent;
int remainingCharNum = line.length() - i;
int nextNonWSChar = getNextProgramCharDistance(line, i);
// if indent is around the last char in the line, indent instead one indent from the previous indent
if (nextNonWSChar == remainingCharNum)
{
int previousIndent = spaceTabCount_;
if (!inStatementIndentStack->empty())
previousIndent = inStatementIndentStack->back();
int currIndent = /*2*/ indentLength + previousIndent;
if (currIndent > maxInStatementIndent
&& line[i] != '{')
currIndent = indentLength * 2 + spaceTabCount_;
inStatementIndentStack->push_back(currIndent);
if (updateParenStack)
parenIndentStack->push_back(previousIndent);
return;
}
if (updateParenStack)
parenIndentStack->push_back(i + spaceTabCount_ - horstmannIndentInStatement);
int tabIncrement = tabIncrementIn;
// check for following tabs
for (int j = i + 1; j < (i + nextNonWSChar); j++)
{
if (line[j] == '\t')
tabIncrement += convertTabToSpaces(j, tabIncrement);
}
inStatementIndent = i + nextNonWSChar + spaceTabCount_ + tabIncrement;
// check for run-in statement
if (i > 0 && line[0] == '{')
inStatementIndent -= indentLength;
// if (i + nextNonWSChar < minIndent)
// inStatementIndent = minIndent + spaceTabCount_;
if (inStatementIndent < minIndent)
inStatementIndent = minIndent + spaceTabCount_;
// if (i + nextNonWSChar > maxInStatementIndent)
// inStatementIndent = indentLength * 2 + spaceTabCount_;
if (inStatementIndent > maxInStatementIndent)
inStatementIndent = indentLength * 2 + spaceTabCount_;
if (!inStatementIndentStack->empty() &&
inStatementIndent < inStatementIndentStack->back())
inStatementIndent = inStatementIndentStack->back();
// the block opener is not indented for a NonInStatementArray
if (isNonInStatementArray && !bracketBlockStateStack->empty() && bracketBlockStateStack->back())
inStatementIndent = 0;
inStatementIndentStack->push_back(inStatementIndent);
}
/**
* get distance to the next non-white space, non-comment character in the line.
* if no such character exists, return the length remaining to the end of the line.
*/
int ASBeautifier::getNextProgramCharDistance(const string &line, int i) const
{
bool inComment = false;
int remainingCharNum = line.length() - i;
int charDistance;
char ch;
for (charDistance = 1; charDistance < remainingCharNum; charDistance++)
{
ch = line[i + charDistance];
if (inComment)
{
if (line.compare(i + charDistance, 2, "*/") == 0)
{
charDistance++;
inComment = false;
}
continue;
}
else if (isWhiteSpace(ch))
continue;
else if (ch == '/')
{
if (line.compare(i + charDistance, 2, "//") == 0)
return remainingCharNum;
else if (line.compare(i + charDistance, 2, "/*") == 0)
{
charDistance++;
inComment = true;
}
}
else
return charDistance;
}
return charDistance;
}
// check if a specific line position contains a header.
const string* ASBeautifier::findHeader(const string &line, int i,
const vector<const string*>* possibleHeaders) const
{
assert(isCharPotentialHeader(line, i));
// check the word
size_t maxHeaders = possibleHeaders->size();
for (size_t p = 0; p < maxHeaders; p++)
{
const string* header = (*possibleHeaders)[p];
const size_t wordEnd = i + header->length();
if (wordEnd > line.length())
continue;
int result = (line.compare(i, header->length(), *header));
if (result > 0)
continue;
if (result < 0)
break;
// check that this is not part of a longer word
if (wordEnd == line.length())
return header;
if (isLegalNameChar(line[wordEnd]))
continue;
const char peekChar = peekNextChar(line, wordEnd - 1);
// is not a header if part of a definition
if (peekChar == ',' || peekChar == ')')
break;
// the following accessor definitions are NOT headers
// goto default; is NOT a header
// default(int) keyword in C# is NOT a header
else if ((header == &AS_GET || header == &AS_SET || header == &AS_DEFAULT)
&& (peekChar == ';' || peekChar == '('))
break;
return header;
}
return NULL;
}
// check if a specific line position contains an operator.
const string* ASBeautifier::findOperator(const string &line, int i,
const vector<const string*>* possibleOperators) const
{
assert(isCharPotentialOperator(line[i]));
// find the operator in the vector
// the vector contains the LONGEST operators first
// must loop thru the entire vector
size_t maxOperators = possibleOperators->size();
for (size_t p = 0; p < maxOperators; p++)
{
const size_t wordEnd = i + (*(*possibleOperators)[p]).length();
if (wordEnd > line.length())
continue;
if (line.compare(i, (*(*possibleOperators)[p]).length(), *(*possibleOperators)[p]) == 0)
return (*possibleOperators)[p];
}
return NULL;
}
/**
* find the index number of a string element in a container of strings
*
* @return the index number of element in the container. -1 if element not found.
* @param container a vector of strings.
* @param element the element to find .
*/
int ASBeautifier::indexOf(vector<const string*> &container, const string* element)
{
vector<const string*>::const_iterator where;
where = find(container.begin(), container.end(), element);
if (where == container.end())
return -1;
else
return (int) (where - container.begin());
}
/**
* convert tabs to spaces.
* i is the position of the character to convert to spaces.
* tabIncrementIn is the increment that must be added for tab indent characters
* to get the correct column for the current tab.
*/
int ASBeautifier::convertTabToSpaces(int i, int tabIncrementIn) const
{
int tabToSpacesAdjustment = indentLength - 1 - ((tabIncrementIn + i) % indentLength);
return tabToSpacesAdjustment;
}
/**
* trim removes the white space surrounding a line.
*
* @return the trimmed line.
* @param str the line to trim.
*/
string ASBeautifier::trim(const string &str)
{
int start = 0;
int end = str.length() - 1;
while (start < end && isWhiteSpace(str[start]))
start++;
while (start <= end && isWhiteSpace(str[end]))
end--;
// don't trim if it ends in a continuation
if (end > -1 && str[end] == '\\')
end = str.length() - 1;
string returnStr(str, start, end + 1 - start);
return returnStr;
}
/**
* Copy tempStacks for the copy constructor.
* The value of the vectors must also be copied.
*/
vector<vector<const string*>*>* ASBeautifier::copyTempStacks(const ASBeautifier &other) const
{
vector<vector<const string*>*> *tempStacksNew = new vector<vector<const string*>*>;
vector<vector<const string*>*>::iterator iter;
for (iter = other.tempStacks->begin();
iter != other.tempStacks->end();
++iter)
{
vector<const string*> *newVec = new vector<const string*>;
*newVec = **iter;
tempStacksNew->push_back(newVec);
}
return tempStacksNew;
}
/**
* delete a member vectors to eliminate memory leak reporting
*/
void ASBeautifier::deleteBeautifierVectors()
{
beautifierFileType = 9; // reset to an invalid type
delete headers;
delete nonParenHeaders;
delete preBlockStatements;
delete preCommandHeaders;
delete assignmentOperators;
delete nonAssignmentOperators;
delete indentableHeaders;
}
/**
* delete a vector object
* T is the type of vector
* used for all vectors except tempStacks
*/
template<typename T>
void ASBeautifier::deleteContainer(T &container)
{
if (container != NULL)
{
container->clear();
delete (container);
container = NULL;
}
}
/**
* Delete the tempStacks vector object.
* The tempStacks is a vector of pointers to strings allocated with
* the 'new' operator.
* Therefore the strings have to be deleted in addition to the
* tempStacks entries.
*/
void ASBeautifier::deleteContainer(vector<vector<const string*>*>* &container)
{
if (container != NULL)
{
vector<vector<const string*>*>::iterator iter = container->begin();
while (iter < container->end())
{
delete *iter;
++iter;
}
container->clear();
delete (container);
container = NULL;
}
}
/**
* initialize a vector object
* T is the type of vector
* used for all vectors
*/
template<typename T>
void ASBeautifier::initContainer(T &container, T value)
{
// since the ASFormatter object is never deleted,
// the existing vectors must be deleted before creating new ones
if (container != NULL )
deleteContainer(container);
container = value;
}
/**
* Determine if an assignment statement ends with a comma
* that is not in a function argument. It ends with a
* comma if a comma is the last char on the line.
*
* @return true if line ends with a comma, otherwise false.
*/
bool ASBeautifier::statementEndsWithComma(const string &line, int index) const
{
assert(line[index] == '=');
bool isInComment_ = false;
bool isInQuote_ = false;
int parenCount = 0;
size_t lineLength = line.length();
size_t i = 0;
char quoteChar_ = ' ';
for (i = index + 1; i < lineLength; ++i)
{
char ch = line[i];
if (isInComment_)
{
if (line.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 (line.compare(i, 2, "//") == 0)
break;
if (line.compare(i, 2, "/*") == 0)
{
if (isLineEndComment(line, i))
break;
else
{
isInComment_ = true;
++i;
continue;
}
}
if (ch == '(')
parenCount++;
if (ch == ')')
parenCount--;
}
if (isInComment_
|| isInQuote_
|| parenCount > 0)
return false;
size_t lastChar = line.find_last_not_of(" \t", i - 1);
if (lastChar == string::npos || line[lastChar] != ',')
return false;
return true;
}
/**
* check if current comment is a line-end comment
*
* @return is before a line-end comment.
*/
bool ASBeautifier::isLineEndComment(const string &line, int startPos) const
{
assert(line.compare(startPos, 2, "/*") == 0);
// comment must be closed on this line with nothing after it
size_t endNum = line.find("*/", startPos + 2);
if (endNum != string::npos)
{
size_t nextChar = line.find_first_not_of(" \t", endNum + 2);
if (nextChar == string::npos)
return true;
}
return false;
}
/**
* get the previous word index for an assignment operator
*
* @return is the index to the previous word (the in statement indent).
*/
int ASBeautifier::getInStatementIndentAssign(const string &line, size_t currPos) const
{
assert(line[currPos] == '=');
if (currPos == 0)
return 0;
// get the last legal word (may be a number)
size_t end = line.find_last_not_of(" \t", currPos-1);
if (end == string::npos || !isLegalNameChar(line[end]))
return 0;
int start; // start of the previous word
for (start = end; start > -1; start--)
{
if (!isLegalNameChar(line[start]) || line[start] == '.')
break;
}
start++;
return start;
}
/**
* get the instatement indent for a comma
*
* @return is the indent to the second word on the line (the in statement indent).
*/
int ASBeautifier::getInStatementIndentComma(const string &line, size_t currPos) const
{
assert(line[currPos] == ',');
// get first word on a line
size_t indent = line.find_first_not_of(" \t");
if (indent == string::npos || !isLegalNameChar(line[indent]))
return 0;
// bypass first word
for (; indent < currPos; indent++)
{
if (!isLegalNameChar(line[indent]))
break;
}
indent++;
if (indent >= currPos)
return 0;
// point to second word or assignment operator
indent = line.find_first_not_of(" \t", indent);
if (indent == string::npos || indent >= currPos)
return 0;
return indent;
}
/**
* get the next word on a line
* the argument 'currPos' must point to the current position.
*
* @return is the previous word or an empty string if none found.
*/
string ASBeautifier::getNextWord(const string &line, size_t currPos) const
{
size_t lineLength = line.length();
// get the last legal word (may be a number)
if (currPos == lineLength - 1)
return string();
size_t start = line.find_first_not_of(" \t", currPos+1);
if (start == string::npos || !isLegalNameChar(line[start]))
return string();
size_t end; // end of the current word
for (end = start+1; end <= lineLength; end++)
{
if (!isLegalNameChar(line[end]) || line[end] == '.')
break;
}
return line.substr(start, end-start);
}
/**
* Check if a preprocessor directive is always indented.
* C# "region" and "endregion" are always indented.
* C/C++ "pragma omp" is always indented.
*
* @return is true or false.
*/
bool ASBeautifier::isIndentedPreprocessor(const string &line, size_t currPos) const
{
assert(line[0] == '#');
string nextWord = getNextWord(line, currPos);
if (nextWord == "region" || nextWord == "endregion")
return true;
// is it #pragma omp
if (nextWord == "pragma")
{
// find pragma
size_t start = line.find("pragma");
if (start == string::npos || !isLegalNameChar(line[start]))
return false;
// bypass pragma
for (; start < line.length(); start++)
{
if (!isLegalNameChar(line[start]))
break;
}
start++;
if (start >= line.length())
return false;
// point to start of second word
start = line.find_first_not_of(" \t", start);
if (start == string::npos)
return false;
// point to end of second word
size_t end;
for (end = start; end < line.length(); end++)
{
if (!isLegalNameChar(line[end]))
break;
}
// check for "pragma omp"
string word = line.substr(start, end - start);
if (word == "omp" || word == "region" || word == "endregion")
return true;
}
return false;
}
/**
* Check if a preprocessor directive is checking for __cplusplus defined.
*
* @return is true or false.
*/
bool ASBeautifier::isPreprocessorDefinedCplusplus(const string &preproc) const
{
if (preproc.compare(0, 5, "ifdef") == 0 && getNextWord(preproc, 4) == "__cplusplus")
return true;
if (preproc.compare(0, 2, "if") == 0)
{
// check for " #if defined(__cplusplus)"
size_t charNum = 2;
charNum = preproc.find_first_not_of(" \t", charNum);
if (preproc.compare(charNum, 7, "defined") == 0)
{
charNum += 7;
charNum = preproc.find_first_not_of(" \t", charNum);
if (preproc.compare(charNum, 1, "(") == 0)
{
++charNum;
charNum = preproc.find_first_not_of(" \t", charNum);
if (preproc.compare(charNum, 11, "__cplusplus") == 0)
return true;
}
}
}
return false;
}
/**
* Check if a preprocessor definition contains an unterminated comment.
* Comments within a preprocessor definition can be continued without the backslash.
*
* @return is true or false.
*/
bool ASBeautifier::isInPreprocessorUnterminatedComment(const string &line)
{
if (!isInPreprocessorComment)
{
size_t startPos = line.find("/*");
if (startPos == string::npos)
return false;
}
size_t endNum = line.find("*/");
if (endNum != string::npos)
{
isInPreprocessorComment = false;
return false;
}
isInPreprocessorComment = true;
return true;
}
// for unit testing
int ASBeautifier::getBeautifierFileType() const
{ return beautifierFileType; }
/**
* Process preprocessor statements and update the beautifier stacks.
*/
void ASBeautifier::processProcessor(string &line)
{
string preproc = trim(string(line.c_str() + 1));
// When finding a multi-lined #define statement, the original beautifier
// 1. sets its isInDefineDefinition flag
// 2. clones a new beautifier that will be used for the actual indentation
// of the #define. This clone is put into the activeBeautifierStack in order
// to be called for the actual indentation.
// The original beautifier will have isInDefineDefinition = true, isInDefine = false
// The cloned beautifier will have isInDefineDefinition = true, isInDefine = true
if (preprocessorIndent && preproc.compare(0, 6, "define") == 0 && line[line.length() - 1] == '\\')
{
if (!isInDefineDefinition)
{
ASBeautifier* defineBeautifier;
// this is the original beautifier
isInDefineDefinition = true;
// push a new beautifier into the active stack
// this beautifier will be used for the indentation of this define
defineBeautifier = new ASBeautifier(*this);
activeBeautifierStack->push_back(defineBeautifier);
}
else
{
// the is the cloned beautifier that is in charge of indenting the #define.
isInDefine = true;
}
}
else if (preproc.compare(0, 2, "if") == 0)
{
if (isPreprocessorDefinedCplusplus(preproc))
preprocessorCppExternCBracket = 1;
// push a new beautifier into the stack
waitingBeautifierStackLengthStack->push_back(waitingBeautifierStack->size());
activeBeautifierStackLengthStack->push_back(activeBeautifierStack->size());
if (activeBeautifierStackLengthStack->back() == 0)
waitingBeautifierStack->push_back(new ASBeautifier(*this));
else
waitingBeautifierStack->push_back(new ASBeautifier(*activeBeautifierStack->back()));
}
else if (preproc.compare(0, 4, "else") == 0)
{
if (waitingBeautifierStack && !waitingBeautifierStack->empty())
{
// MOVE current waiting beautifier to active stack.
activeBeautifierStack->push_back(waitingBeautifierStack->back());
waitingBeautifierStack->pop_back();
}
}
else if (preproc.compare(0, 4, "elif") == 0)
{
if (waitingBeautifierStack && !waitingBeautifierStack->empty())
{
// append a COPY current waiting beautifier to active stack, WITHOUT deleting the original.
activeBeautifierStack->push_back(new ASBeautifier(*(waitingBeautifierStack->back())));
}
}
else if (preproc.compare(0, 5, "endif") == 0)
{
int stackLength;
ASBeautifier* beautifier;
if (waitingBeautifierStackLengthStack && !waitingBeautifierStackLengthStack->empty())
{
stackLength = waitingBeautifierStackLengthStack->back();
waitingBeautifierStackLengthStack->pop_back();
while ((int) waitingBeautifierStack->size() > stackLength)
{
beautifier = waitingBeautifierStack->back();
waitingBeautifierStack->pop_back();
delete beautifier;
}
}
if (!activeBeautifierStackLengthStack->empty())
{
stackLength = activeBeautifierStackLengthStack->back();
activeBeautifierStackLengthStack->pop_back();
while ((int) activeBeautifierStack->size() > stackLength)
{
beautifier = activeBeautifierStack->back();
activeBeautifierStack->pop_back();
delete beautifier;
}
}
}
}
// Compute the preliminary indentation based on data in the headerStack.
// Update the class variable indentCount.
void ASBeautifier::computePreliminaryIndentation()
{
for (size_t i = 0; i < headerStack->size(); i++)
{
isInClass = false;
if (blockIndent)
{
// do NOT indent opening block for these headers
if (!((*headerStack)[i] == &AS_NAMESPACE
|| (*headerStack)[i] == &AS_CLASS
|| (*headerStack)[i] == &AS_STRUCT
|| (*headerStack)[i] == &AS_UNION
|| (*headerStack)[i] == &AS_INTERFACE
|| (*headerStack)[i] == &AS_THROWS
|| (*headerStack)[i] == &AS_STATIC))
++indentCount;
}
else if (!(i > 0 && (*headerStack)[i-1] != &AS_OPEN_BRACKET
&& (*headerStack)[i] == &AS_OPEN_BRACKET))
++indentCount;
if (!isJavaStyle() && !namespaceIndent && i >= 1
&& (*headerStack)[i-1] == &AS_NAMESPACE
&& (*headerStack)[i] == &AS_OPEN_BRACKET)
--indentCount;
if (isCStyle() && i >= 1
&& (*headerStack)[i-1] == &AS_CLASS
&& (*headerStack)[i] == &AS_OPEN_BRACKET)
{
if (classIndent)
++indentCount;
isInClass = true;
}
// is the switchIndent option is on, indent switch statements an additional indent.
else if (switchIndent && i > 1
&& (*headerStack)[i-1] == &AS_SWITCH
&& (*headerStack)[i] == &AS_OPEN_BRACKET)
{
++indentCount;
isInSwitch = true;
}
} // end of for loop
}
/**
* Parse the current line to update indentCount and spaceIndentCount.
*/
void ASBeautifier::parseCurrentLine(const string &line)
{
bool isInLineComment = false;
bool isInOperator = false;
bool isSpecialChar = false;
bool haveCaseIndent = false;
bool haveAssignmentThisLine = false;
bool closingBracketReached = false;
bool previousLineProbation = (probationHeader != NULL);
char ch = ' ';
char prevCh;
char tempCh;
int tabIncrementIn = 0;
for (size_t i = 0; i < line.length(); i++)
{
tempCh = line[i];
prevCh = ch;
ch = tempCh;
if (isInBeautifySQL)
continue;
if (isWhiteSpace(ch))
{
if (ch == '\t')
tabIncrementIn += convertTabToSpaces(i, tabIncrementIn);
continue;
}
// handle special characters (i.e. backslash+character such as \n, \t, ...)
if (isInQuote && !isInVerbatimQuote)
{
if (isSpecialChar)
{
isSpecialChar = false;
continue;
}
if (line.compare(i, 2, "\\\\") == 0)
{
i++;
continue;
}
if (ch == '\\')
{
if (peekNextChar(line, i) == ' ') // is this '\' at end of line
haveLineContinuationChar = true;
else
isSpecialChar = true;
continue;
}
}
else if (isInDefine && ch == '\\')
continue;
// handle quotes (such as 'x' and "Hello Dolly")
if (!(isInComment || isInLineComment) && (ch == '"' || ch == '\''))
{
if (!isInQuote)
{
quoteChar = ch;
isInQuote = true;
if (isSharpStyle() && prevCh == '@')
isInVerbatimQuote = true;
}
else if (isInVerbatimQuote && ch == '"')
{
if (peekNextChar(line, i) == '"') // check consecutive quotes
i++;
else
{
isInQuote = false;
isInVerbatimQuote = false;
}
}
else if (quoteChar == ch)
{
isInQuote = false;
isInStatement = true;
continue;
}
}
if (isInQuote)
continue;
// handle comments
if (!(isInComment || isInLineComment) && line.compare(i, 2, "//") == 0)
{
isInLineComment = true;
i++;
continue;
}
else if (!(isInComment || isInLineComment) && line.compare(i, 2, "/*") == 0)
{
isInComment = true;
i++;
if (!lineOpensComment) // does line start with comment?
blockCommentNoIndent = true; // if no, cannot indent continuation lines
continue;
}
else if ((isInComment || isInLineComment) && line.compare(i, 2, "*/") == 0)
{
isInComment = false;
i++;
blockCommentNoIndent = false; // ok to indent next comment
continue;
}
// treat indented preprocessor lines as a line comment
else if (line[0] == '#' && isIndentedPreprocessor(line, i))
{
isInLineComment = true;
}
if (isInComment || isInLineComment)
{
// bypass rest of the comment up to the comment end
while (i+1 < line.length()
&& line.compare(i+1, 2, "*/") != 0)
i++;
continue;
}
// if we have reached this far then we are NOT in a comment or string of special character...
if (probationHeader != NULL)
{
if ((probationHeader == &AS_STATIC && ch == '{')
|| (probationHeader == &AS_SYNCHRONIZED && ch == '('))
{
// insert the probation header as a new header
isInHeader = true;
headerStack->push_back(probationHeader);
// handle the specific probation header
isInConditional = (probationHeader == &AS_SYNCHRONIZED);
isInStatement = false;
// if the probation comes from the previous line, then indent by 1 tab count.
if (previousLineProbation
&& ch == '{'
&& !(blockIndent && probationHeader == &AS_STATIC))
{
indentCount++;
previousLineProbationTab = true;
}
previousLineProbation = false;
}
// dismiss the probation header
probationHeader = NULL;
}
prevNonSpaceCh = currentNonSpaceCh;
currentNonSpaceCh = ch;
if (!isLegalNameChar(ch) && ch != ',' && ch != ';')
{
prevNonLegalCh = currentNonLegalCh;
currentNonLegalCh = ch;
}
if (isInHeader)
{
isInHeader = false;
currentHeader = headerStack->back();
}
else
currentHeader = NULL;
if (isCStyle() && isInTemplate
&& (ch == '<' || ch == '>')
&& !(line.length() > i+1 && line.compare(i, 2, ">=") == 0))
{
if (ch == '<')
{
++templateDepth;
}
else if (ch == '>')
{
if (--templateDepth <= 0)
{
ch = ';';
isInTemplate = false;
templateDepth = 0;
}
}
}
// handle parenthesies
if (ch == '(' || ch == '[' || ch == ')' || ch == ']')
{
if (ch == '(' || ch == '[')
{
isInOperator = false;
// if have a struct header, this is a declaration not a definition
if (ch == '('
&& (isInClassInitializer || isInClassHeaderTab)
&& !headerStack->empty()
&& headerStack->back() == &AS_STRUCT)
{
headerStack->pop_back();
isInClassInitializer = false;
// -1 for isInClassInitializer, -2 for isInClassHeaderTab
if (isInClassHeaderTab)
{
indentCount -= (1 + classInitializerIndents);
isInClassHeaderTab = false;
}
if (indentCount < 0)
indentCount = 0;
}
if (parenDepth == 0)
{
parenStatementStack->push_back(isInStatement);
isInStatement = true;
}
parenDepth++;
inStatementIndentStackSizeStack->push_back(inStatementIndentStack->size());
if (currentHeader != NULL)
registerInStatementIndent(line, i, spaceIndentCount, tabIncrementIn, minConditionalIndent/*indentLength*2*/, true);
else
registerInStatementIndent(line, i, spaceIndentCount, tabIncrementIn, 0, true);
}
else if (ch == ')' || ch == ']')
{
foundPreCommandHeader = false;
parenDepth--;
if (parenDepth == 0)
{
if (!parenStatementStack->empty()) // in case of unmatched closing parens
{
isInStatement = parenStatementStack->back();
parenStatementStack->pop_back();
}
ch = ' ';
isInAsm = false;
isInConditional = false;
}
if (!inStatementIndentStackSizeStack->empty())
{
int previousIndentStackSize = inStatementIndentStackSizeStack->back();
inStatementIndentStackSizeStack->pop_back();
while (previousIndentStackSize < (int) inStatementIndentStack->size())
inStatementIndentStack->pop_back();
if (!parenIndentStack->empty())
{
int poppedIndent = parenIndentStack->back();
parenIndentStack->pop_back();
if (i == 0)
spaceIndentCount = poppedIndent;
}
}
}
continue;
}
if (ch == '{')
{
// first, check if '{' is a block-opener or an static-array opener
bool isBlockOpener = ((prevNonSpaceCh == '{' && bracketBlockStateStack->back())
|| prevNonSpaceCh == '}'
|| prevNonSpaceCh == ')'
|| prevNonSpaceCh == ';'
|| peekNextChar(line, i) == '{'
|| foundPreCommandHeader
|| isInClassInitializer
|| isNonInStatementArray
|| isSharpAccessor
|| isSharpDelegate
|| isInExtern
|| getNextWord(line, i) == "new"
|| (isInDefine &&
(prevNonSpaceCh == '('
|| isLegalNameChar(prevNonSpaceCh))));
// remove inStatementIndent for C++ class initializer
if (isInClassInitializer)
{
if (!inStatementIndentStack->empty())
inStatementIndentStack->pop_back();
isInStatement = false;
if (lineBeginsWithBracket)
spaceIndentCount = 0;
isInClassInitializer = false;
}
// remove indent for preprocessor 'extern "C"' bracket
if (isCStyle() && preprocessorCppExternCBracket == 2)
++preprocessorCppExternCBracket;
if (!isBlockOpener && currentHeader != NULL)
{
for (size_t n = 0; n < nonParenHeaders->size(); n++)
if (currentHeader == (*nonParenHeaders)[n])
{
isBlockOpener = true;
break;
}
}
bracketBlockStateStack->push_back(isBlockOpener);
if (!isBlockOpener)
{
inStatementIndentStackSizeStack->push_back(inStatementIndentStack->size());
registerInStatementIndent(line, i, spaceIndentCount, tabIncrementIn, 0, true);
parenDepth++;
if (i == 0)
shouldIndentBrackettedLine = false;
continue;
}
// this bracket is a block opener...
++lineOpeningBlocksNum;
if (isInClassHeaderTab)
{
isInClassHeaderTab = false;
// decrease tab count if bracket is broken
size_t firstChar = line.find_first_not_of(" \t");
if (firstChar != string::npos
&& line[firstChar] == '{'
&& firstChar == i)
{
indentCount -= classInitializerIndents;
// decrease one more if an empty class
if (!headerStack->empty()
&& (*headerStack).back() == &AS_CLASS)
{
int nextChar = getNextProgramCharDistance(line, i);
if ((int)line.length() > nextChar && line[nextChar] == '}')
indentCount--;
}
}
}
if (bracketIndent && !namespaceIndent && !headerStack->empty()
&& (*headerStack).back() == &AS_NAMESPACE)
{
shouldIndentBrackettedLine = false;
indentCount--;
}
// an indentable struct is treated like a class in the header stack
if (!headerStack->empty()
&& (*headerStack).back() == &AS_STRUCT
&& isInIndentableStruct)
(*headerStack).back() = &AS_CLASS;
blockParenDepthStack->push_back(parenDepth);
blockStatementStack->push_back(isInStatement);
inStatementIndentStackSizeStack->push_back(inStatementIndentStack->size());
if (!inStatementIndentStack->empty())
{
spaceIndentCount = 0;
inStatementIndentStack->back() = 0;
}
blockTabCount += (isInStatement ? 1 : 0);
parenDepth = 0;
isInStatement = false;
foundPreCommandHeader = false;
tempStacks->push_back(new vector<const string*>);
headerStack->push_back(&AS_OPEN_BRACKET);
lastLineHeader = &AS_OPEN_BRACKET;
continue;
} // end '{'
//check if a header has been reached
bool isPotentialHeader = isCharPotentialHeader(line, i);
if (isPotentialHeader)
{
const string* newHeader = findHeader(line, i, headers);
if (newHeader != NULL)
{
// if we reached here, then this is a header...
bool isIndentableHeader = true;
isInHeader = true;
vector<const string*> *lastTempStack;
if (tempStacks->empty())
lastTempStack = NULL;
else
lastTempStack = tempStacks->back();
// if a new block is opened, push a new stack into tempStacks to hold the
// future list of headers in the new block.
// take care of the special case: 'else if (...)'
if (newHeader == &AS_IF && lastLineHeader == &AS_ELSE)
{
headerStack->pop_back();
}
// take care of 'else'
else if (newHeader == &AS_ELSE)
{
if (lastTempStack != NULL)
{
int indexOfIf = indexOf(*lastTempStack, &AS_IF);
if (indexOfIf != -1)
{
// recreate the header list in headerStack up to the previous 'if'
// from the temporary snapshot stored in lastTempStack.
int restackSize = lastTempStack->size() - indexOfIf - 1;
for (int r = 0; r < restackSize; r++)
{
headerStack->push_back(lastTempStack->back());
lastTempStack->pop_back();
}
if (!closingBracketReached)
indentCount += restackSize;
}
/*
* If the above if is not true, i.e. no 'if' before the 'else',
* then nothing beautiful will come out of this...
* I should think about inserting an Exception here to notify the caller of this...
*/
}
}
// check if 'while' closes a previous 'do'
else if (newHeader == &AS_WHILE)
{
if (lastTempStack != NULL)
{
int indexOfDo = indexOf(*lastTempStack, &AS_DO);
if (indexOfDo != -1)
{
// recreate the header list in headerStack up to the previous 'do'
// from the temporary snapshot stored in lastTempStack.
int restackSize = lastTempStack->size() - indexOfDo - 1;
for (int r = 0; r < restackSize; r++)
{
headerStack->push_back(lastTempStack->back());
lastTempStack->pop_back();
}
if (!closingBracketReached)
indentCount += restackSize;
}
}
}
// check if 'catch' closes a previous 'try' or 'catch'
else if (newHeader == &AS_CATCH || newHeader == &AS_FINALLY)
{
if (lastTempStack != NULL)
{
int indexOfTry = indexOf(*lastTempStack, &AS_TRY);
if (indexOfTry == -1)
indexOfTry = indexOf(*lastTempStack, &AS_CATCH);
if (indexOfTry != -1)
{
// recreate the header list in headerStack up to the previous 'try'
// from the temporary snapshot stored in lastTempStack.
int restackSize = lastTempStack->size() - indexOfTry - 1;
for (int r = 0; r < restackSize; r++)
{
headerStack->push_back(lastTempStack->back());
lastTempStack->pop_back();
}
if (!closingBracketReached)
indentCount += restackSize;
}
}
}
else if (newHeader == &AS_CASE)
{
isInCase = true;
if (!haveCaseIndent)
{
haveCaseIndent = true;
if (!lineBeginsWithBracket)
--indentCount;
}
}
else if (newHeader == &AS_DEFAULT)
{
isInCase = true;
--indentCount;
}
else if (newHeader == &AS_STATIC
|| newHeader == &AS_SYNCHRONIZED)
{
if (!headerStack->empty() &&
(headerStack->back() == &AS_STATIC
|| headerStack->back() == &AS_SYNCHRONIZED))
{
isIndentableHeader = false;
}
else
{
isIndentableHeader = false;
probationHeader = newHeader;
}
}
else if (newHeader == &AS_TEMPLATE)
{
isInTemplate = true;
isIndentableHeader = false;
}
if (isIndentableHeader)
{
headerStack->push_back(newHeader);
isInStatement = false;
if (indexOf(*nonParenHeaders, newHeader) == -1)
{
isInConditional = true;
}
lastLineHeader = newHeader;
}
else
isInHeader = false;
i += newHeader->length() - 1;
continue;
} // newHeader != NULL
if (findHeader(line, i, preCommandHeaders))
foundPreCommandHeader = true;
// this applies only to C enums
if (isCStyle() && findKeyword(line, i, AS_ENUM))
{
// need in-statement indents in an enum
isInEnum = true;
isNonInStatementArray = false;
}
} // isPotentialHeader
if (ch == '?')
isInQuestion = true;
// special handling of colons
if (ch == ':')
{
if (line.length() > i + 1 && line[i+1] == ':') // look for ::
{
++i;
ch = ' ';
continue;
}
else if (isInQuestion)
{
isInQuestion = false;
}
else if (isCStyle() && isInEnum)
{
// found an enum with a base-type
// so do nothing special
}
else if (isCStyle()
&& !headerStack->empty()
&& headerStack->back() == &AS_FOR
&& parenDepth > 0)
{
// found a range-based 'for' loop 'for (auto i : container)'
// so do nothing special
}
else if (isCStyle() && isInClassInitializer)
{
// found a 'class A : public B' definition
// so do nothing special
}
else if (isCStyle()
&& (isInAsm || isInAsmOneLine || isInAsmBlock))
{
// do nothing special
}
else if (isCStyle() && isDigit(peekNextChar(line, i)))
{
// found a bit field
// so do nothing special
}
else if (isCStyle() && isInClass && prevNonSpaceCh != ')')
{
// found a 'private:' or 'public:' inside a class definition
--indentCount;
}
else if (isCStyle() && !isInClass
&& headerStack->size() >= 2
&& (*headerStack)[headerStack->size()-2] == &AS_CLASS
&& (*headerStack)[headerStack->size()-1] == &AS_OPEN_BRACKET)
{
// found a 'private:' or 'public:' inside a class definition
// and on the same line as the class opening bracket
// do nothing
}
else if (isCStyle() && prevNonSpaceCh == ')' && !isInCase)
{
isInClassInitializer = true;
isInStatement = false; // so an inStatement indent will register
if (i == 0)
indentCount += classInitializerIndents;
}
else if (isJavaStyle() && lastLineHeader == &AS_FOR)
{
// found a java for-each statement
// so do nothing special
}
else
{
currentNonSpaceCh = ';'; // so that brackets after the ':' will appear as block-openers
if (isInCase)
{
isInCase = false;
ch = ';'; // from here on, treat char as ';'
}
else if (isCStyle() || (isSharpStyle() && peekNextChar(line, i) == ';')) // is in a label (e.g. 'label1:')
{
if (labelIndent)
--indentCount; // unindent label by one indent
else if (!lineBeginsWithBracket)
indentCount = 0; // completely flush indent to left
}
}
}
if ((ch == ';' || (parenDepth > 0 && ch == ',')) && !inStatementIndentStackSizeStack->empty())
while ((int) inStatementIndentStackSizeStack->back() + (parenDepth > 0 ? 1 : 0)
< (int) inStatementIndentStack->size())
inStatementIndentStack->pop_back();
// handle commas
// previous "isInStatement" will be from an assignment operator or class initializer
if (ch == ',' && parenDepth == 0 && !isInStatement && !isNonInStatementArray)
{
// is comma at end of line
size_t nextChar = line.find_first_not_of(" \t", i + 1);
if (nextChar != string::npos)
{
if (line.compare(nextChar, 2, "//") == 0
|| line.compare(nextChar, 2, "/*") == 0)
nextChar = string::npos;
}
// register indent
if (nextChar == string::npos)
{
// register indent at first word after the colon of a C++ class initializer
if (isInClassInitializer)
{
size_t firstChar = line.find_first_not_of(" \t");
if (firstChar != string::npos && line[firstChar] == ':')
{
size_t firstWord = line.find_first_not_of(" \t", firstChar + 1);
if (firstChar != string::npos)
{
int inStatementIndent = firstWord + spaceIndentCount + tabIncrementIn;
inStatementIndentStack->push_back(inStatementIndent);
isInStatement = true;
}
}
}
// register indent at previous word
else
{
int prevWord = getInStatementIndentComma(line, i);
int inStatementIndent = prevWord + spaceIndentCount + tabIncrementIn;
inStatementIndentStack->push_back(inStatementIndent);
isInStatement = true;
}
}
}
// handle ends of statements
if ((ch == ';' && parenDepth == 0) || ch == '}')
{
if (ch == '}')
{
// first check if this '}' closes a previous block, or a static array...
if (!bracketBlockStateStack->empty())
{
bool bracketBlockState = bracketBlockStateStack->back();
bracketBlockStateStack->pop_back();
if (!bracketBlockState)
{
if (!inStatementIndentStackSizeStack->empty())
{
// this bracket is a static array
int previousIndentStackSize = inStatementIndentStackSizeStack->back();
inStatementIndentStackSizeStack->pop_back();
while (previousIndentStackSize < (int) inStatementIndentStack->size())
inStatementIndentStack->pop_back();
parenDepth--;
if (i == 0)
shouldIndentBrackettedLine = false;
if (!parenIndentStack->empty())
{
int poppedIndent = parenIndentStack->back();
parenIndentStack->pop_back();
if (i == 0)
spaceIndentCount = poppedIndent;
}
}
continue;
}
}
// this bracket is block closer...
++lineClosingBlocksNum;
if (!inStatementIndentStackSizeStack->empty())
inStatementIndentStackSizeStack->pop_back();
if (!blockParenDepthStack->empty())
{
parenDepth = blockParenDepthStack->back();
blockParenDepthStack->pop_back();
isInStatement = blockStatementStack->back();
blockStatementStack->pop_back();
if (isInStatement)
blockTabCount--;
}
closingBracketReached = true;
isInAsmOneLine = false;
if (i == 0)
spaceIndentCount = 0;
// added for release 1.24
// TODO: remove at the appropriate time
assert(isInAsm == false);
assert(isInAsmOneLine == false);
assert(isInQuote == false);
isInAsm = isInAsmOneLine = isInQuote = false;
// end remove
int headerPlace = indexOf(*headerStack, &AS_OPEN_BRACKET);
if (headerPlace != -1)
{
const string* popped = headerStack->back();
while (popped != &AS_OPEN_BRACKET)
{
headerStack->pop_back();
popped = headerStack->back();
}
headerStack->pop_back();
// do not indent namespace bracket unless namespaces are indented
if (!namespaceIndent && !headerStack->empty()
&& (*headerStack).back() == &AS_NAMESPACE
&& i == 0) // must be the first bracket on the line
shouldIndentBrackettedLine = false;
if (!tempStacks->empty())
{
vector<const string*> *temp = tempStacks->back();
tempStacks->pop_back();
delete temp;
}
}
ch = ' '; // needed due to cases such as '}else{', so that headers ('else' tn tih case) will be identified...
} // ch == '}'
/*
* Create a temporary snapshot of the current block's header-list in the
* uppermost inner stack in tempStacks, and clear the headerStack up to
* the begining of the block.
* Thus, the next future statement will think it comes one indent past
* the block's '{' unless it specifically checks for a companion-header
* (such as a previous 'if' for an 'else' header) within the tempStacks,
* and recreates the temporary snapshot by manipulating the tempStacks.
*/
if (!tempStacks->back()->empty())
while (!tempStacks->back()->empty())
tempStacks->back()->pop_back();
while (!headerStack->empty() && headerStack->back() != &AS_OPEN_BRACKET)
{
tempStacks->back()->push_back(headerStack->back());
headerStack->pop_back();
}
if (parenDepth == 0 && ch == ';')
isInStatement = false;
previousLastLineHeader = NULL;
isInClassInitializer = false;
isInEnum = false;
isInQuestion = false;
foundPreCommandHeader = false;
continue;
}
if (isPotentialHeader)
{
// check for preBlockStatements in C/C++ ONLY if not within parenthesies
// (otherwise 'struct XXX' statements would be wrongly interpreted...)
if (!isInTemplate && !(isCStyle() && parenDepth > 0))
{
const string* newHeader = findHeader(line, i, preBlockStatements);
if (newHeader != NULL
&& !(isCStyle() && newHeader == &AS_CLASS && isInEnum)) // is it 'enum class'
{
isInClassInitializer = true;
if (!isSharpStyle())
headerStack->push_back(newHeader);
// do not need 'where' in the headerStack
// do not need second 'class' statement in a row
else if (!(newHeader == &AS_WHERE
|| (newHeader == &AS_CLASS
&& !headerStack->empty()
&& headerStack->back() == &AS_CLASS)))
headerStack->push_back(newHeader);
i += newHeader->length() - 1;
continue;
}
}
const string* foundIndentableHeader = findHeader(line, i, indentableHeaders);
if (foundIndentableHeader != NULL)
{
// must bypass the header before registering the in statement
i += foundIndentableHeader->length() - 1;
if (!isInOperator && !isInTemplate && !isNonInStatementArray)
{
registerInStatementIndent(line, i, spaceIndentCount, tabIncrementIn, 0, false);
isInStatement = true;
}
continue;
}
if (isCStyle() && findKeyword(line, i, AS_OPERATOR))
isInOperator = true;
if (isCStyle() && preprocessorCppExternCBracket == 1 && findKeyword(line, i, AS_EXTERN))
++preprocessorCppExternCBracket;
// "new" operator is a pointer, not a calculation
if (findKeyword(line, i, AS_NEW))
{
if (isInStatement && !inStatementIndentStack->empty())
{
if (prevNonSpaceCh == '=' && isInStatement && !inStatementIndentStack->empty())
inStatementIndentStack->back() = 0;
}
}
if (isCStyle())
{
if (findKeyword(line, i, AS_ASM)
|| findKeyword(line, i, AS__ASM__))
{
isInAsm = true;
}
else if (findKeyword(line, i, AS_MS_ASM) // microsoft specific
|| findKeyword(line, i, AS_MS__ASM))
{
int index = 4;
if (peekNextChar(line, i) == '_') // check for __asm
index = 5;
char peekedChar = ASBase::peekNextChar(line, i + index);
if (peekedChar == '{' || peekedChar == ' ')
isInAsmBlock = true;
else
isInAsmOneLine = true;
}
}
// bypass the entire name for all others
string name = getCurrentWord(line, i);
i += name.length() - 1;
continue;
}
// Handle operators
bool isPotentialOperator = isCharPotentialOperator(ch);
if (isPotentialOperator)
{
// Check if an operator has been reached.
const string* foundAssignmentOp = findOperator(line, i, assignmentOperators);
const string* foundNonAssignmentOp = findOperator(line, i, nonAssignmentOperators);
if (isInTemplate && foundNonAssignmentOp == &AS_GR_GR)
foundNonAssignmentOp = NULL;
// Since findHeader's boundry checking was not used above, it is possible
// that both an assignment op and a non-assignment op where found,
// e.g. '>>' and '>>='. If this is the case, treat the LONGER one as the
// found operator.
if (foundAssignmentOp != NULL && foundNonAssignmentOp != NULL)
{
if (foundAssignmentOp->length() < foundNonAssignmentOp->length())
foundAssignmentOp = NULL;
else
foundNonAssignmentOp = NULL;
}
if (foundNonAssignmentOp != NULL)
{
if (foundNonAssignmentOp->length() > 1)
i += foundNonAssignmentOp->length() - 1;
// For C++ input/output, operator<< and >> should be
// aligned, if we are not in a statement already and
// also not in the "operator<<(...)" header line
if (!isInOperator
&& inStatementIndentStack->empty()
&& isCStyle()
&& (foundNonAssignmentOp == &AS_GR_GR ||
foundNonAssignmentOp == &AS_LS_LS))
{
// this will be true if the line begins with the operator
if (i < 2 && spaceIndentCount == 0)
spaceIndentCount += 2 * indentLength;
// align to the beginning column of the operator
registerInStatementIndent(line, i - foundNonAssignmentOp->length(), spaceIndentCount, tabIncrementIn, 0, false);
}
}
else if (foundAssignmentOp != NULL)
{
foundPreCommandHeader = false; // clears this for array assignments
if (foundAssignmentOp->length() > 1)
i += foundAssignmentOp->length() - 1;
if (!isInOperator && !isInTemplate && !isNonInStatementArray)
{
// if multiple assignments, align on the previous word
if (foundAssignmentOp == &AS_ASSIGN
&& prevNonSpaceCh != ']' // an array
&& statementEndsWithComma(line, i))
{
if (!haveAssignmentThisLine) // only one assignment indent per line
{
// register indent at previous word
haveAssignmentThisLine = true;
int prevWordIndex = getInStatementIndentAssign(line, i);
int inStatementIndent = prevWordIndex + spaceIndentCount + tabIncrementIn;
inStatementIndentStack->push_back(inStatementIndent);
}
}
else
{
if (i == 0 && spaceIndentCount == 0)
spaceIndentCount += indentLength;
registerInStatementIndent(line, i, spaceIndentCount, tabIncrementIn, 0, false);
}
isInStatement = true;
}
}
}
} // end of for loop * end of for loop * end of for loop * end of for loop * end of for loop *
}
} // end namespace astyle