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/ASBeautifier.cpp

1934 lines
51 KiB

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* ASBeautifier.cpp
*
* This file is a part of "Artistic Style" - an indentation and
* reformatting tool for C, C++, C# and Java source files.
* http://astyle.sourceforge.net
*
* The "Artistic Style" project, including all files needed to
* compile it, is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this project; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*/
#include "astyle.h"
#include <algorithm>
#include <iostream>
#define INIT_CONTAINER(container, value) {if ( (container) != NULL ) delete (container); (container) = (value); }
#define DELETE_CONTAINER(container) {if ( (container) != NULL ) delete (container); }
namespace astyle
{
vector<const string*> ASBeautifier::headers;
vector<const string*> ASBeautifier::nonParenHeaders;
vector<const string*> ASBeautifier::preBlockStatements;
vector<const string*> ASBeautifier::assignmentOperators;
vector<const string*> ASBeautifier::nonAssignmentOperators;
/*
* initialize the static vars
*/
void ASBeautifier::initStatic()
{
static int beautifierFileType = 9; // initialized with an invalid type
if (fileType == beautifierFileType) // don't build unless necessary
return;
beautifierFileType = fileType;
headers.clear();
nonParenHeaders.clear();
assignmentOperators.clear();
nonAssignmentOperators.clear();
preBlockStatements.clear();
ASResource::buildHeaders(headers, fileType, true);
ASResource::buildNonParenHeaders(nonParenHeaders, fileType, true);
ASResource::buildAssignmentOperators(assignmentOperators);
ASResource::buildNonAssignmentOperators(nonAssignmentOperators);
ASResource::buildPreBlockStatements(preBlockStatements);
// cout << "beaut" << endl;
}
/**
* ASBeautifier's constructor
*/
ASBeautifier::ASBeautifier()
{
waitingBeautifierStack = NULL;
activeBeautifierStack = NULL;
waitingBeautifierStackLengthStack = NULL;
activeBeautifierStackLengthStack = NULL;
headerStack = NULL;
tempStacks = NULL;
blockParenDepthStack = NULL;
blockStatementStack = NULL;
parenStatementStack = NULL;
bracketBlockStateStack = NULL;
inStatementIndentStack = NULL;
inStatementIndentStackSizeStack = NULL;
parenIndentStack = NULL;
sourceIterator = NULL;
isMinimalConditinalIndentSet = false;
shouldForceTabIndentation = false;
setSpaceIndentation(4);
setMaxInStatementIndentLength(40);
setClassIndent(false);
setSwitchIndent(false);
setCaseIndent(false);
setBlockIndent(false);
setBracketIndent(false);
setNamespaceIndent(false);
setLabelIndent(false);
setEmptyLineFill(false);
fileType = C_TYPE;
setCStyle();
setPreprocessorIndent(false);
}
/**
* ASBeautifier's copy constructor
*/
ASBeautifier::ASBeautifier(const ASBeautifier &other)
{
waitingBeautifierStack = NULL;
activeBeautifierStack = NULL;
waitingBeautifierStackLengthStack = NULL;
activeBeautifierStackLengthStack = NULL;
headerStack = new vector<const string*>;
*headerStack = *other.headerStack;
tempStacks = new vector<vector<const string*>*>;
vector<vector<const string*>*>::iterator iter;
for (iter = other.tempStacks->begin();
iter != other.tempStacks->end();
++iter)
{
vector<const string*> *newVec = new vector<const string*>;
*newVec = **iter;
tempStacks->push_back(newVec);
}
blockParenDepthStack = new vector<int>;
*blockParenDepthStack = *other.blockParenDepthStack;
blockStatementStack = new vector<bool>;
*blockStatementStack = *other.blockStatementStack;
parenStatementStack = new vector<bool>;
*parenStatementStack = *other.parenStatementStack;
bracketBlockStateStack = new vector<bool>;
*bracketBlockStateStack = *other.bracketBlockStateStack;
inStatementIndentStack = new vector<int>;
*inStatementIndentStack = *other.inStatementIndentStack;
inStatementIndentStackSizeStack = new vector<int>;
*inStatementIndentStackSizeStack = *other.inStatementIndentStackSizeStack;
parenIndentStack = new vector<int>;
*parenIndentStack = *other.parenIndentStack;
sourceIterator = other.sourceIterator;
// protected variables
fileType = other.fileType;
isCStyle = other.isCStyle;
isJavaStyle = other.isJavaStyle;
isSharpStyle = other.isSharpStyle;
// variables set by ASFormatter
// must also be updated in preprocessor
inLineNumber = other.inLineNumber;
outLineNumber = other.outLineNumber;
lineCommentNoBeautify = other.lineCommentNoBeautify;
isNonInStatementArray = other.isNonInStatementArray;
// private variables
indentString = other.indentString;
currentHeader = other.currentHeader;
previousLastLineHeader = other.previousLastLineHeader;
immediatelyPreviousAssignmentOp = other.immediatelyPreviousAssignmentOp;
probationHeader = other.probationHeader;
isInQuote = other.isInQuote;
isInComment = other.isInComment;
isInCase = other.isInCase;
isInQuestion = other.isInQuestion;
isInStatement = other.isInStatement;
isInHeader = other.isInHeader;
isInOperator = other.isInOperator;
isInTemplate = other.isInTemplate;
isInDefine = other.isInDefine;
isInDefineDefinition = other.isInDefineDefinition;
classIndent = other.classIndent;
isInClassHeader = other.isInClassHeader;
isInClassHeaderTab = other.isInClassHeaderTab;
switchIndent = other.switchIndent;
caseIndent = other.caseIndent;
namespaceIndent = other.namespaceIndent;
bracketIndent = other.bracketIndent;
blockIndent = other.blockIndent;
labelIndent = other.labelIndent;
preprocessorIndent = other.preprocessorIndent;
isInConditional = other.isInConditional;
isMinimalConditinalIndentSet = other.isMinimalConditinalIndentSet;
shouldForceTabIndentation = other.shouldForceTabIndentation;
emptyLineFill = other.emptyLineFill;
backslashEndsPrevLine = other.backslashEndsPrevLine;
blockCommentNoIndent = other.blockCommentNoIndent;
blockCommentNoBeautify = other.blockCommentNoBeautify;
previousLineProbationTab = other.previousLineProbationTab;
minConditionalIndent = other.minConditionalIndent;
parenDepth = other.parenDepth;
indentLength = other.indentLength;
blockTabCount = other.blockTabCount;
leadingWhiteSpaces = other.leadingWhiteSpaces;
maxInStatementIndent = other.maxInStatementIndent;
templateDepth = other.templateDepth;
prevFinalLineSpaceTabCount = other.prevFinalLineSpaceTabCount;
prevFinalLineTabCount = other.prevFinalLineTabCount;
defineTabCount = other.defineTabCount;
quoteChar = other.quoteChar;
prevNonSpaceCh = other.prevNonSpaceCh;
currentNonSpaceCh = other.currentNonSpaceCh;
currentNonLegalCh = other.currentNonLegalCh;
prevNonLegalCh = other.prevNonLegalCh;
}
/**
* ASBeautifier's destructor
*/
ASBeautifier::~ASBeautifier()
{
DELETE_CONTAINER(headerStack);
DELETE_CONTAINER(tempStacks);
DELETE_CONTAINER(blockParenDepthStack);
DELETE_CONTAINER(blockStatementStack);
DELETE_CONTAINER(parenStatementStack);
DELETE_CONTAINER(bracketBlockStateStack);
DELETE_CONTAINER(inStatementIndentStack);
DELETE_CONTAINER(inStatementIndentStackSizeStack);
DELETE_CONTAINER(parenIndentStack);
}
/**
* initialize the ASBeautifier.
*
* init() should be called every time a ABeautifier object is to start
* beautifying a NEW source file.
* init() recieves a pointer to a DYNAMICALLY CREATED ASSourceIterator object
* that will be used to iterate through the source code. This object will be
* deleted during the ASBeautifier's destruction, and thus should not be
* deleted elsewhere.
*
* @param iter a pointer to the DYNAMICALLY CREATED ASSourceIterator object.
*/
void ASBeautifier::init(ASSourceIterator *iter)
{
sourceIterator = iter;
init();
}
/**
* initialize the ASBeautifier.
*/
void ASBeautifier::init()
{
initStatic();
INIT_CONTAINER(waitingBeautifierStack, new vector<ASBeautifier*>);
INIT_CONTAINER(activeBeautifierStack, new vector<ASBeautifier*>);
INIT_CONTAINER(waitingBeautifierStackLengthStack, new vector<int>);
INIT_CONTAINER(activeBeautifierStackLengthStack, new vector<int>);
INIT_CONTAINER(headerStack, new vector<const string*>);
INIT_CONTAINER(tempStacks, new vector<vector<const string*>*>);
tempStacks->push_back(new vector<const string*>);
INIT_CONTAINER(blockParenDepthStack, new vector<int>);
INIT_CONTAINER(blockStatementStack, new vector<bool>);
INIT_CONTAINER(parenStatementStack, new vector<bool>);
INIT_CONTAINER(bracketBlockStateStack, new vector<bool>);
bracketBlockStateStack->push_back(true);
INIT_CONTAINER(inStatementIndentStack, new vector<int>);
INIT_CONTAINER(inStatementIndentStackSizeStack, new vector<int>);
inStatementIndentStackSizeStack->push_back(0);
INIT_CONTAINER(parenIndentStack, new vector<int>);
immediatelyPreviousAssignmentOp = NULL;
previousLastLineHeader = NULL;
currentHeader = NULL;
isInQuote = false;
isInComment = false;
isInStatement = false;
isInCase = false;
isInQuestion = false;
isInClassHeader = false;
isInClassHeaderTab = false;
isInHeader = false;
isInOperator = false;
isInTemplate = false;
isInConditional = false;
templateDepth = 0;
parenDepth = 0;
blockTabCount = 0;
leadingWhiteSpaces = 0;
prevNonSpaceCh = '{';
currentNonSpaceCh = '{';
prevNonLegalCh = '{';
currentNonLegalCh = '{';
quoteChar = ' ';
prevFinalLineSpaceTabCount = 0;
prevFinalLineTabCount = 0;
probationHeader = NULL;
backslashEndsPrevLine = false;
isInDefine = false;
isInDefineDefinition = false;
defineTabCount = 0;
lineCommentNoBeautify = false;
blockCommentNoIndent = false;
blockCommentNoBeautify = false;
previousLineProbationTab = false;
isNonInStatementArray = false;
inLineNumber = -1; // for debugging
outLineNumber = 0; // for debugging
}
/**
* set indentation style to C/C++.
*/
void ASBeautifier::setCStyle()
{
fileType = C_TYPE;
isCStyle = true;
isJavaStyle = false;
isSharpStyle = false;
}
/**
* set indentation style to Java.
*/
void ASBeautifier::setJavaStyle()
{
fileType = JAVA_TYPE;
isJavaStyle = true;
isCStyle = false;
isSharpStyle = false;
}
/**
* set indentation style to C#.
*/
void ASBeautifier::setSharpStyle()
{
fileType = SHARP_TYPE;
isSharpStyle = true;
isCStyle = false;
isJavaStyle = false;
}
/**
* indent using one tab per indentation
*/
void ASBeautifier::setTabIndentation(int length, bool forceTabs)
{
indentString = "\t";
indentLength = length;
shouldForceTabIndentation = forceTabs;
if (!isMinimalConditinalIndentSet)
minConditionalIndent = indentLength * 2;
}
/**
* indent using a number of spaces per indentation.
*
* @param length number of spaces per indent.
*/
void ASBeautifier::setSpaceIndentation(int length)
{
indentString = string(length, ' ');
indentLength = length;
if (!isMinimalConditinalIndentSet)
minConditionalIndent = indentLength * 2;
}
/**
* set the maximum indentation between two lines in a multi-line statement.
*
* @param max maximum indentation length.
*/
void ASBeautifier::setMaxInStatementIndentLength(int max)
{
maxInStatementIndent = max;
}
/**
* set the minimum indentation between two lines in a multi-line condition.
*
* @param min minimal indentation length.
*/
void ASBeautifier::setMinConditionalIndentLength(int min)
{
minConditionalIndent = min;
isMinimalConditinalIndentSet = true;
}
/**
* set the state of the bracket indentation option. If true, brackets will
* be indented one additional indent.
*
* @param state state of option.
*/
void ASBeautifier::setBracketIndent(bool state)
{
bracketIndent = state;
}
/**
* set the state of the block indentation option. If true, entire blocks
* will be indented one additional indent, similar to the GNU indent style.
*
* @param state state of option.
*/
void ASBeautifier::setBlockIndent(bool state)
{
if (state)
setBracketIndent(false); // so that we don't have both bracket and block indent
blockIndent = state;
}
/**
* set the state of the class indentation option. If true, C++ class
* definitions will be indented one additional indent.
*
* @param state state of option.
*/
void ASBeautifier::setClassIndent(bool state)
{
classIndent = state;
}
/**
* set the state of the switch indentation option. If true, blocks of 'switch'
* statements will be indented one additional indent.
*
* @param state state of option.
*/
void ASBeautifier::setSwitchIndent(bool state)
{
switchIndent = state;
}
/**
* set the state of the case indentation option. If true, lines of 'case'
* statements will be indented one additional indent.
*
* @param state state of option.
*/
void ASBeautifier::setCaseIndent(bool state)
{
caseIndent = state;
}
/**
* set the state of the namespace indentation option.
* If true, blocks of 'namespace' statements will be indented one
* additional indent. Otherwise, NO indentation will be added.
*
* @param state state of option.
*/
void ASBeautifier::setNamespaceIndent(bool state)
{
namespaceIndent = state;
}
/**
* set the state of the label indentation option.
* If true, labels will be indented one indent LESS than the
* current indentation level.
* If false, labels will be flushed to the left with NO
* indent at all.
*
* @param state state of option.
*/
void ASBeautifier::setLabelIndent(bool state)
{
labelIndent = state;
}
/**
* set the state of the preprocessor indentation option.
* If true, multiline #define statements will be indented.
*
* @param state state of option.
*/
void ASBeautifier::setPreprocessorIndent(bool state)
{
preprocessorIndent = state;
}
/**
* set the state of the empty line fill option.
* If true, empty lines will be filled with the whitespace.
* of their previous lines.
* If false, these lines will remain empty.
*
* @param state state of option.
*/
void ASBeautifier::setEmptyLineFill(bool state)
{
emptyLineFill = state;
}
/**
* get the number of spaces per indent
*
* @return value of indentLength option.
*/
int ASBeautifier::getIndentLength(void)
{
return indentLength;
}
/**
* get the char used for indentation, space or tab
*
* @return the char used for indentation.
*/
string ASBeautifier::getIndentString(void)
{
return indentString;
}
/**
* get the state of the case indentation option. If true, lines of 'case'
* statements will be indented one additional indent.
*
* @return state of caseIndent option.
*/
bool ASBeautifier::getCaseIndent(void)
{
return caseIndent;
}
/**
* get C style identifier.
* If true, a C source is being indented.
*
* @return state of isCStyle option.
*/
bool ASBeautifier::getCStyle(void)
{
return isCStyle;
}
/**
* get Java style identifier.
* If true, a Java source is being indented.
*
* @return state of isJavaStyle option.
*/
bool ASBeautifier::getJavaStyle(void)
{
return isJavaStyle;
}
/**
* get C# style identifier.
* If true, a C# source is being indented.
*
* @return state of isSharpStyle option.
*/
bool ASBeautifier::getSharpStyle(void)
{
return isSharpStyle;
}
/**
* get the state of the empty line fill option.
* If true, empty lines will be filled with the whitespace.
* of their previous lines.
* If false, these lines will remain empty.
*
* @return state of emptyLineFill option.
*/
bool ASBeautifier::getEmptyLineFill(void)
{
return emptyLineFill;
}
/**
* check if there are any indented lines ready to be read by nextLine()
*
* @return are there any indented lines ready?
*/
bool ASBeautifier::hasMoreLines() const
{
return sourceIterator->hasMoreLines();
}
/**
* get the next indented line.
*
* @return indented line.
*/
string ASBeautifier::nextLine()
{
return beautify(sourceIterator->nextLine());
}
/**
* beautify a line of source code.
* every line of source code in a source code file should be sent
* one after the other to the beautify method.
*
* @return the indented line.
* @param originalLine the original unindented line.
*/
string ASBeautifier::beautify(const string &originalLine)
{
string line;
bool isInLineComment = false;
bool lineStartsInComment = false;
bool isInClass = false;
bool isInSwitch = false;
bool isImmediatelyAfterConst = false;
bool isSpecialChar = false;
char ch = ' ';
char prevCh;
string outBuffer; // the newly idented line is bufferd here
int tabCount = 0;
const string *lastLineHeader = NULL;
bool closingBracketReached = false;
int spaceTabCount = 0;
char tempCh;
size_t headerStackSize = headerStack->size();
bool shouldIndentBrackettedLine = true;
int lineOpeningBlocksNum = 0;
int lineClosingBlocksNum = 0;
bool previousLineProbation = (probationHeader != NULL);
int i;
currentHeader = NULL;
lineStartsInComment = isInComment;
blockCommentNoBeautify = blockCommentNoIndent;
previousLineProbationTab = false;
outLineNumber++;
// handle and remove white spaces around the line:
// If not in comment, first find out size of white space before line,
// so that possible comments starting in the line continue in
// relation to the preliminary white-space.
if (!isInComment)
{
int strlen = originalLine.length();
leadingWhiteSpaces = 0;
for (int j = 0; j < strlen && isWhiteSpace(originalLine[j]); j++)
{
if (originalLine[j] == '\t')
leadingWhiteSpaces += indentLength;
else
leadingWhiteSpaces++;
}
line = trim(originalLine);
}
else
{
// convert leading tabs to spaces
string spaceTabs(indentLength, ' ');
string newLine = originalLine;
int strlen = newLine.length();
for (int j=0; j < leadingWhiteSpaces && j < strlen; j++)
{
if (newLine[j] == '\t')
{
newLine.replace(j, 1, spaceTabs);
strlen = newLine.length();
}
}
// trim the comment leaving the new leading whitespace
int trimSize = 0;
strlen = newLine.length();
while (trimSize < strlen
&& trimSize < leadingWhiteSpaces
&& isWhiteSpace(newLine[trimSize]))
trimSize++;
while (trimSize < strlen && isWhiteSpace(newLine[strlen-1]))
strlen--;
line = newLine.substr(trimSize, strlen);
size_t trimEnd = line.find_last_not_of(" \t");
if (trimEnd != string::npos)
{
int spacesToDelete = line.length() - 1 - trimEnd;
if (spacesToDelete > 0)
line.erase(trimEnd + 1, spacesToDelete);
}
}
if (line.length() == 0)
{
if (backslashEndsPrevLine) // must continue to clear variables
line = ' ';
else if (emptyLineFill)
return preLineWS(prevFinalLineSpaceTabCount, prevFinalLineTabCount);
else
return line;
}
// handle preprocessor commands
if (isCStyle && !isInComment && (line[0] == '#' || backslashEndsPrevLine))
{
if (line[0] == '#')
{
string preproc = trim(string(line.c_str() + 1));
// When finding a multi-lined #define statement, the original beautifier
// 1. sets its isInDefineDefinition flag
// 2. clones a new beautifier that will be used for the actual indentation
// of the #define. This clone is put into the activeBeautifierStack in order
// to be called for the actual indentation.
// The original beautifier will have isInDefineDefinition = true, isInDefine = false
// The cloned beautifier will have isInDefineDefinition = true, isInDefine = true
if (preprocessorIndent && preproc.compare(0, 6, "define") == 0 && line[line.length() - 1] == '\\')
{
if (!isInDefineDefinition)
{
ASBeautifier *defineBeautifier;
// this is the original beautifier
isInDefineDefinition = true;
// push a new beautifier into the active stack
// this beautifier will be used for the indentation of this define
defineBeautifier = new ASBeautifier(*this);
activeBeautifierStack->push_back(defineBeautifier);
}
else
{
// the is the cloned beautifier that is in charge of indenting the #define.
isInDefine = true;
}
}
else if (preproc.compare(0, 2, "if") == 0)
{
// push a new beautifier into the stack
waitingBeautifierStackLengthStack->push_back(waitingBeautifierStack->size());
activeBeautifierStackLengthStack->push_back(activeBeautifierStack->size());
waitingBeautifierStack->push_back(new ASBeautifier(*this));
}
else if (preproc.compare(0, 4/*2*/, "else") == 0)
{
if (waitingBeautifierStack && !waitingBeautifierStack->empty())
{
// MOVE current waiting beautifier to active stack.
activeBeautifierStack->push_back(waitingBeautifierStack->back());
waitingBeautifierStack->pop_back();
}
}
else if (preproc.compare(0, 4, "elif") == 0)
{
if (waitingBeautifierStack && !waitingBeautifierStack->empty())
{
// append a COPY current waiting beautifier to active stack, WITHOUT deleting the original.
activeBeautifierStack->push_back(new ASBeautifier(*(waitingBeautifierStack->back())));
}
}
else if (preproc.compare(0, 5, "endif") == 0)
{
int stackLength;
ASBeautifier *beautifier;
if (waitingBeautifierStackLengthStack && !waitingBeautifierStackLengthStack->empty())
{
stackLength = waitingBeautifierStackLengthStack->back();
waitingBeautifierStackLengthStack->pop_back();
while ((int) waitingBeautifierStack->size() > stackLength)
{
beautifier = waitingBeautifierStack->back();
waitingBeautifierStack->pop_back();
delete beautifier;
}
}
if (!activeBeautifierStackLengthStack->empty())
{
stackLength = activeBeautifierStackLengthStack->back();
activeBeautifierStackLengthStack->pop_back();
while ((int) activeBeautifierStack->size() > stackLength)
{
beautifier = activeBeautifierStack->back();
activeBeautifierStack->pop_back();
delete beautifier;
}
}
}
}
// check if the last char is a backslash
if (line.length() > 0)
backslashEndsPrevLine = (line[line.length() - 1] == '\\');
else
backslashEndsPrevLine = false;
// check if this line ends a multi-line #define
// if so, use the #define's cloned beautifier for the line's indentation
// and then remove it from the active beautifier stack and delete it.
if (!backslashEndsPrevLine && isInDefineDefinition && !isInDefine)
{
string beautifiedLine;
ASBeautifier *defineBeautifier;
isInDefineDefinition = false;
defineBeautifier = activeBeautifierStack->back();
activeBeautifierStack->pop_back();
beautifiedLine = defineBeautifier->beautify(line);
delete defineBeautifier;
return beautifiedLine;
}
// unless this is a multi-line #define, return this precompiler line as is.
if (!isInDefine && !isInDefineDefinition)
return originalLine;
}
// if there exists any worker beautifier in the activeBeautifierStack,
// then use it instead of me to indent the current line.
// variables set by ASFormatter must be updated.
if (!isInDefine && activeBeautifierStack != NULL && !activeBeautifierStack->empty())
{
activeBeautifierStack->back()->inLineNumber = inLineNumber;
activeBeautifierStack->back()->outLineNumber = outLineNumber;
activeBeautifierStack->back()->lineCommentNoBeautify = lineCommentNoBeautify;
activeBeautifierStack->back()->isNonInStatementArray = isNonInStatementArray;
return activeBeautifierStack->back()->beautify(line);
}
// calculate preliminary indentation based on data from past lines
if (!inStatementIndentStack->empty())
spaceTabCount = inStatementIndentStack->back();
for (i = 0; i < (int) headerStackSize; i++)
{
isInClass = false;
if (blockIndent || (!(i > 0 && (*headerStack)[i-1] != &AS_OPEN_BRACKET
&& (*headerStack)[i] == &AS_OPEN_BRACKET)))
++tabCount;
if (!isJavaStyle && !namespaceIndent && i >= 1
&& (*headerStack)[i-1] == &AS_NAMESPACE
&& (*headerStack)[i] == &AS_OPEN_BRACKET)
--tabCount;
if (isCStyle && i >= 1
&& (*headerStack)[i-1] == &AS_CLASS
&& (*headerStack)[i] == &AS_OPEN_BRACKET)
{
if (classIndent)
++tabCount;
isInClass = true;
}
// is the switchIndent option is on, indent switch statements an additional indent.
else if (switchIndent && i > 1 &&
(*headerStack)[i-1] == &AS_SWITCH &&
(*headerStack)[i] == &AS_OPEN_BRACKET
)
{
++tabCount;
isInSwitch = true;
}
}
if (!lineStartsInComment
&& isCStyle
&& isInClass
&& classIndent
&& headerStackSize >= 2
&& (*headerStack)[headerStackSize-2] == &AS_CLASS
&& (*headerStack)[headerStackSize-1] == &AS_OPEN_BRACKET
&& line[0] == '}')
--tabCount;
else if (!lineStartsInComment
&& isInSwitch
&& switchIndent
&& headerStackSize >= 2
&& (*headerStack)[headerStackSize-2] == &AS_SWITCH
&& (*headerStack)[headerStackSize-1] == &AS_OPEN_BRACKET
&& line[0] == '}')
--tabCount;
if (isInClassHeader)
{
isInClassHeaderTab = true;
tabCount += 2;
}
if (isInConditional)
{
--tabCount;
}
// parse characters in the current line.
for (i = 0; i < (int) line.length(); i++)
{
tempCh = line[i];
prevCh = ch;
ch = tempCh;
outBuffer.append(1, ch);
if (isWhiteSpace(ch))
continue;
// check for utf8 characters
// isalnum() will display an assert message in debug if not bypassed here
if (ch < 0)
continue;
// handle special characters (i.e. backslash+character such as \n, \t, ...)
if (isSpecialChar)
{
isSpecialChar = false;
continue;
}
if (!(isInComment || isInLineComment) && line.compare(i, 2, "\\\\") == 0)
{
outBuffer.append(1, '\\');
i++;
continue;
}
if (!(isInComment || isInLineComment) && ch == '\\')
{
isSpecialChar = true;
continue;
}
// handle quotes (such as 'x' and "Hello Dolly")
if (!(isInComment || isInLineComment) && (ch == '"' || ch == '\''))
if (!isInQuote)
{
quoteChar = ch;
isInQuote = true;
}
else if (quoteChar == ch)
{
isInQuote = false;
isInStatement = true;
continue;
}
if (isInQuote)
continue;
// handle comments
if (!(isInComment || isInLineComment) && line.compare(i, 2, "//") == 0)
{
isInLineComment = true;
outBuffer.append(1, '/');
i++;
continue;
}
else if (!(isInComment || isInLineComment) && line.compare(i, 2, "/*") == 0)
{
isInComment = true;
outBuffer.append(1, '*');
i++;
size_t j = line.find_first_not_of(" \t");
if (!line.compare(j, 2, "/*") == 0) // does line start with comment?
blockCommentNoIndent = true; // if no, cannot indent continuation lines
continue;
}
else if ((isInComment || isInLineComment) && line.compare(i, 2, "*/") == 0)
{
isInComment = false;
outBuffer.append(1, '/');
i++;
blockCommentNoIndent = false; // ok to indent next comment
continue;
}
if (isInComment || isInLineComment)
continue;
// if we have reached this far then we are NOT in a comment or string of special character...
if (probationHeader != NULL)
{
if (((probationHeader == &AS_STATIC || probationHeader == &AS_CONST) && ch == '{')
|| (probationHeader == &AS_SYNCHRONIZED && ch == '('))
{
// insert the probation header as a new header
isInHeader = true;
headerStack->push_back(probationHeader);
// handle the specific probation header
isInConditional = (probationHeader == &AS_SYNCHRONIZED);
if (probationHeader == &AS_CONST)
isImmediatelyAfterConst = true;
isInStatement = false;
// if the probation comes from the previous line, then indent by 1 tab count.
if (previousLineProbation && ch == '{')
{
tabCount++;
previousLineProbationTab = true;
}
previousLineProbation = false;
}
// dismiss the probation header
probationHeader = NULL;
}
prevNonSpaceCh = currentNonSpaceCh;
currentNonSpaceCh = ch;
if (!isLegalNameChar(ch) && ch != ',' && ch != ';')
{
prevNonLegalCh = currentNonLegalCh;
currentNonLegalCh = ch;
}
if (isInHeader)
{
isInHeader = false;
currentHeader = headerStack->back();
}
else
currentHeader = NULL;
if (isCStyle && isInTemplate
&& (ch == '<' || ch == '>')
&& findHeader(line, i, nonAssignmentOperators) == NULL)
{
if (ch == '<')
{
++templateDepth;
}
else if (ch == '>')
{
if (--templateDepth <= 0)
{
if (isInTemplate)
ch = ';';
else
ch = 't';
isInTemplate = false;
templateDepth = 0;
}
}
}
// handle parenthesies
if (ch == '(' || ch == '[' || ch == ')' || ch == ']')
{
if (ch == '(' || ch == '[')
{
if (parenDepth == 0)
{
parenStatementStack->push_back(isInStatement);
isInStatement = true;
}
parenDepth++;
inStatementIndentStackSizeStack->push_back(inStatementIndentStack->size());
if (currentHeader != NULL)
registerInStatementIndent(line, i, spaceTabCount, minConditionalIndent/*indentLength*2*/, true);
else
registerInStatementIndent(line, i, spaceTabCount, 0, true);
}
else if (ch == ')' || ch == ']')
{
parenDepth--;
if (parenDepth == 0)
{
isInStatement = parenStatementStack->back();
parenStatementStack->pop_back();
ch = ' ';
isInConditional = false;
}
if (!inStatementIndentStackSizeStack->empty())
{
int previousIndentStackSize = inStatementIndentStackSizeStack->back();
inStatementIndentStackSizeStack->pop_back();
while (previousIndentStackSize < (int) inStatementIndentStack->size())
inStatementIndentStack->pop_back();
if (!parenIndentStack->empty())
{
int poppedIndent = parenIndentStack->back();
parenIndentStack->pop_back();
if (i == 0)
spaceTabCount = poppedIndent;
}
}
}
continue;
}
if (ch == '{')
{
bool isBlockOpener;
// first, check if '{' is a block-opener or an static-array opener
isBlockOpener = ((prevNonSpaceCh == '{' && bracketBlockStateStack->back())
|| prevNonSpaceCh == '}'
|| prevNonSpaceCh == ')'
|| prevNonSpaceCh == ';'
|| peekNextChar(line, i) == '{'
|| isNonInStatementArray
|| isInClassHeader
// || isBlockOpener
|| isImmediatelyAfterConst
|| (isInDefine &&
(prevNonSpaceCh == '('
|| prevNonSpaceCh == '_'
|| isalnum(prevNonSpaceCh))));
isInClassHeader = false;
if (!isBlockOpener && currentHeader != NULL)
{
for (size_t n = 0; n < nonParenHeaders.size(); n++)
if (currentHeader == nonParenHeaders[n])
{
isBlockOpener = true;
break;
}
}
bracketBlockStateStack->push_back(isBlockOpener);
if (!isBlockOpener)
{
inStatementIndentStackSizeStack->push_back(inStatementIndentStack->size());
registerInStatementIndent(line, i, spaceTabCount, 0, true);
parenDepth++;
if (i == 0)
shouldIndentBrackettedLine = false;
continue;
}
// this bracket is a block opener...
++lineOpeningBlocksNum;
// if (isInClassHeader)
// isInClassHeader = false;
if (isInClassHeaderTab)
{
isInClassHeaderTab = false;
// decrease tab count if bracket is broken
size_t firstChar = line.find_first_not_of(" \t");
if (firstChar != string::npos)
if (line[firstChar] == '{' && (int) firstChar == i)
tabCount -= 2;
}
// do not allow inStatementIndent - should occur for Java files only
if (inStatementIndentStack->size() > 0)
{
spaceTabCount = 0;
inStatementIndentStack->back() = 0;
}
blockParenDepthStack->push_back(parenDepth);
blockStatementStack->push_back(isInStatement);
inStatementIndentStackSizeStack->push_back(inStatementIndentStack->size());
if (inStatementIndentStack->size() > 0)
inStatementIndentStack->back() = 0;
blockTabCount += isInStatement ? 1 : 0;
parenDepth = 0;
isInStatement = false;
tempStacks->push_back(new vector<const string*>);
headerStack->push_back(&AS_OPEN_BRACKET);
lastLineHeader = &AS_OPEN_BRACKET;
continue;
}
//check if a header has been reached
if (isWhiteSpace(prevCh))
{
bool isIndentableHeader = true;
const string *newHeader = findHeader(line, i, headers);
if (newHeader != NULL)
{
// if we reached here, then this is a header...
isInHeader = true;
vector<const string*> *lastTempStack;
if (tempStacks->empty())
lastTempStack = NULL;
else
lastTempStack = tempStacks->back();
// if a new block is opened, push a new stack into tempStacks to hold the
// future list of headers in the new block.
// take care of the special case: 'else if (...)'
if (newHeader == &AS_IF && lastLineHeader == &AS_ELSE)
{
headerStack->pop_back();
}
// take care of 'else'
else if (newHeader == &AS_ELSE)
{
if (lastTempStack != NULL)
{
int indexOfIf = indexOf(*lastTempStack, &AS_IF);
if (indexOfIf != -1)
{
// recreate the header list in headerStack up to the previous 'if'
// from the temporary snapshot stored in lastTempStack.
int restackSize = lastTempStack->size() - indexOfIf - 1;
for (int r = 0; r < restackSize; r++)
{
headerStack->push_back(lastTempStack->back());
lastTempStack->pop_back();
}
if (!closingBracketReached)
tabCount += restackSize;
}
/*
* If the above if is not true, i.e. no 'if' before the 'else',
* then nothing beautiful will come out of this...
* I should think about inserting an Exception here to notify the caller of this...
*/
}
}
// check if 'while' closes a previous 'do'
else if (newHeader == &AS_WHILE)
{
if (lastTempStack != NULL)
{
int indexOfDo = indexOf(*lastTempStack, &AS_DO);
if (indexOfDo != -1)
{
// recreate the header list in headerStack up to the previous 'do'
// from the temporary snapshot stored in lastTempStack.
int restackSize = lastTempStack->size() - indexOfDo - 1;
for (int r = 0; r < restackSize; r++)
{
headerStack->push_back(lastTempStack->back());
lastTempStack->pop_back();
}
if (!closingBracketReached)
tabCount += restackSize;
}
}
}
// check if 'catch' closes a previous 'try' or 'catch'
else if (newHeader == &AS_CATCH || newHeader == &AS_FINALLY)
{
if (lastTempStack != NULL)
{
int indexOfTry = indexOf(*lastTempStack, &AS_TRY);
if (indexOfTry == -1)
indexOfTry = indexOf(*lastTempStack, &AS_CATCH);
if (indexOfTry != -1)
{
// recreate the header list in headerStack up to the previous 'try'
// from the temporary snapshot stored in lastTempStack.
int restackSize = lastTempStack->size() - indexOfTry - 1;
for (int r = 0; r < restackSize; r++)
{
headerStack->push_back(lastTempStack->back());
lastTempStack->pop_back();
}
if (!closingBracketReached)
tabCount += restackSize;
}
}
}
else if (newHeader == &AS_CASE)
{
isInCase = true;
--tabCount;
}
else if (newHeader == &AS_DEFAULT)
{
isInCase = true;
--tabCount;
}
else if (newHeader == &AS_STATIC
|| newHeader == &AS_SYNCHRONIZED
|| (newHeader == &AS_CONST && isCStyle))
{
if (!headerStack->empty() &&
(headerStack->back() == &AS_STATIC
|| headerStack->back() == &AS_SYNCHRONIZED
|| headerStack->back() == &AS_CONST))
{
isIndentableHeader = false;
}
else
{
isIndentableHeader = false;
probationHeader = newHeader;
}
}
else if (newHeader == &AS_CONST)
{
isIndentableHeader = false;
}
else if (newHeader == &AS_TEMPLATE)
{
if (isCStyle)
isInTemplate = true;
isIndentableHeader = false;
}
if (isIndentableHeader)
{
headerStack->push_back(newHeader);
isInStatement = false;
if (indexOf(nonParenHeaders, newHeader) == -1)
{
isInConditional = true;
}
lastLineHeader = newHeader;
}
else
isInHeader = false;
outBuffer.append(newHeader->substr(1));
i += newHeader->length() - 1;
continue;
}
}
if (isCStyle && !isalpha(prevCh)
&& line.compare(i, 8, "operator") == 0 && !isalnum(line[i+8]))
{
isInOperator = true;
outBuffer.append(AS_OPERATOR.substr(1));
i += 7;
continue;
}
// "new" operator is a pointer, not a calculation
if (!isalpha(prevCh)
&& line.compare(i, 3, "new") == 0 && !isalnum(line[i+3]))
{
if (prevNonSpaceCh == '=' && isInStatement && !inStatementIndentStack->empty())
inStatementIndentStack->back() = 0;
}
if (ch == '?')
isInQuestion = true;
// special handling of 'case' statements
if (ch == ':')
{
if ((int) line.length() > i + 1 && line[i+1] == ':') // look for ::
{
++i;
outBuffer.append(1, ':');
ch = ' ';
continue;
}
else if (isInQuestion)
{
isInQuestion = false;
}
else if (isCStyle && isInClass && prevNonSpaceCh != ')')
{
--tabCount;
// found a 'private:' or 'public:' inside a class definition
// so do nothing special
}
else if (!isJavaStyle && isInClassHeader)
{
// found a 'class A : public B' definition
// so do nothing special
}
else if (isJavaStyle && lastLineHeader == &AS_FOR)
{
// found a java for-each statement
// so do nothing special
}
else if (isCStyle && prevNonSpaceCh == ')')
{
isInClassHeader = true;
if (i == 0)
tabCount += 2;
}
else
{
currentNonSpaceCh = ';'; // so that brackets after the ':' will appear as block-openers
if (isInCase)
{
isInCase = false;
ch = ';'; // from here on, treat char as ';'
}
else // is in a label (e.g. 'label1:')
{
if (labelIndent)
--tabCount; // unindent label by one indent
else
tabCount = 0; // completely flush indent to left
}
}
}
if ((ch == ';' || (parenDepth > 0 && ch == ',')) && !inStatementIndentStackSizeStack->empty())
while ((int) inStatementIndentStackSizeStack->back() + (parenDepth > 0 ? 1 : 0)
< (int) inStatementIndentStack->size())
inStatementIndentStack->pop_back();
// handle ends of statements
if ((ch == ';' && parenDepth == 0) || ch == '}'/* || (ch == ',' && parenDepth == 0)*/)
{
if (ch == '}')
{
// first check if this '}' closes a previous block, or a static array...
if (!bracketBlockStateStack->empty())
{
bool bracketBlockState = bracketBlockStateStack->back();
bracketBlockStateStack->pop_back();
if (!bracketBlockState)
{
if (!inStatementIndentStackSizeStack->empty())
{
// this bracket is a static array
int previousIndentStackSize = inStatementIndentStackSizeStack->back();
inStatementIndentStackSizeStack->pop_back();
while (previousIndentStackSize < (int) inStatementIndentStack->size())
inStatementIndentStack->pop_back();
parenDepth--;
if (i == 0)
shouldIndentBrackettedLine = false;
if (!parenIndentStack->empty())
{
int poppedIndent = parenIndentStack->back();
parenIndentStack->pop_back();
if (i == 0)
spaceTabCount = poppedIndent;
}
}
continue;
}
}
// this bracket is block closer...
++lineClosingBlocksNum;
if (!inStatementIndentStackSizeStack->empty())
inStatementIndentStackSizeStack->pop_back();
if (!blockParenDepthStack->empty())
{
parenDepth = blockParenDepthStack->back();
blockParenDepthStack->pop_back();
isInStatement = blockStatementStack->back();
blockStatementStack->pop_back();
if (isInStatement)
blockTabCount--;
}
closingBracketReached = true;
int headerPlace = indexOf(*headerStack, &AS_OPEN_BRACKET);
if (headerPlace != -1)
{
const string *popped = headerStack->back();
while (popped != &AS_OPEN_BRACKET)
{
headerStack->pop_back();
popped = headerStack->back();
}
headerStack->pop_back();
if (!tempStacks->empty())
{
vector<const string*> *temp = tempStacks->back();
tempStacks->pop_back();
delete temp;
}
}
ch = ' '; // needed due to cases such as '}else{', so that headers ('else' tn tih case) will be identified...
}
/*
* Create a temporary snapshot of the current block's header-list in the
* uppermost inner stack in tempStacks, and clear the headerStack up to
* the begining of the block.
* Thus, the next future statement will think it comes one indent past
* the block's '{' unless it specifically checks for a companion-header
* (such as a previous 'if' for an 'else' header) within the tempStacks,
* and recreates the temporary snapshot by manipulating the tempStacks.
*/
if (!tempStacks->back()->empty())
while (!tempStacks->back()->empty())
tempStacks->back()->pop_back();
while (!headerStack->empty() && headerStack->back() != &AS_OPEN_BRACKET)
{
tempStacks->back()->push_back(headerStack->back());
headerStack->pop_back();
}
if (parenDepth == 0 && ch == ';')
isInStatement = false;
previousLastLineHeader = NULL;
isInClassHeader = false;
isInQuestion = false;
continue;
}
// check for preBlockStatements ONLY if not within parenthesies
// (otherwise 'struct XXX' statements would be wrongly interpreted...)
if (isWhiteSpace(prevCh) && !isInTemplate && parenDepth == 0)
{
const string *newHeader = findHeader(line, i, preBlockStatements);
if (newHeader != NULL)
{
isInClassHeader = true;
outBuffer.append(newHeader->substr(1));
i += newHeader->length() - 1;
headerStack->push_back(newHeader);
}
}
// Handle operators
immediatelyPreviousAssignmentOp = NULL;
// Check if an operator has been reached.
const string *foundAssignmentOp = findHeader(line, i, assignmentOperators, false);
if (foundAssignmentOp == &AS_RETURN)
foundAssignmentOp = findHeader(line, i, assignmentOperators, true);
const string *foundNonAssignmentOp = findHeader(line, i, nonAssignmentOperators, false);
// Since findHeader's boundry checking was not used above, it is possible
// that both an assignment op and a non-assignment op where found,
// e.g. '>>' and '>>='. If this is the case, treat the LONGER one as the
// found operator.
if (foundAssignmentOp != NULL && foundNonAssignmentOp != NULL)
if (foundAssignmentOp->length() < foundNonAssignmentOp->length())
foundAssignmentOp = NULL;
else
foundNonAssignmentOp = NULL;
if (foundNonAssignmentOp != NULL)
{
if (foundNonAssignmentOp->length() > 1)
{
outBuffer.append(foundNonAssignmentOp->substr(1));
i += foundNonAssignmentOp->length() - 1;
}
}
else if (foundAssignmentOp != NULL)
{
if (foundAssignmentOp->length() > 1)
{
outBuffer.append(foundAssignmentOp->substr(1));
i += foundAssignmentOp->length() - 1;
}
if (!isInOperator && !isInTemplate && !isNonInStatementArray)
{
registerInStatementIndent(line, i, spaceTabCount, 0, false);
immediatelyPreviousAssignmentOp = foundAssignmentOp;
isInStatement = true;
}
}
if (isInOperator)
isInOperator = false;
}
// handle special cases of unindentation:
/*
* if '{' doesn't follow an immediately previous '{' in the headerStack
* (but rather another header such as "for" or "if", then unindent it
* by one indentation relative to its block.
*/
if (!lineStartsInComment
&& !blockIndent
&& outBuffer.length() > 0
&& outBuffer[0] == '{'
&& !(lineOpeningBlocksNum > 0 && lineOpeningBlocksNum == lineClosingBlocksNum)
&& !(headerStack->size() > 1 && (*headerStack)[headerStack->size()-2] == &AS_OPEN_BRACKET)
&& shouldIndentBrackettedLine)
--tabCount;
else if (!lineStartsInComment
&& outBuffer.length() > 0
&& outBuffer[0] == '}'
&& shouldIndentBrackettedLine)
--tabCount;
// correctly indent one-line-blocks...
else if (!lineStartsInComment
&& outBuffer.length() > 0
&& lineOpeningBlocksNum > 0
&& lineOpeningBlocksNum == lineClosingBlocksNum
&& previousLineProbationTab)
--tabCount; //lineOpeningBlocksNum - (blockIndent ? 1 : 0);
if (tabCount < 0)
tabCount = 0;
// take care of extra bracket indentatation option...
if (bracketIndent && outBuffer.length() > 0 && shouldIndentBrackettedLine)
if (outBuffer[0] == '{' || outBuffer[0] == '}')
tabCount++;
if (isInDefine)
{
if (outBuffer[0] == '#')
{
string preproc = trim(string(outBuffer.c_str() + 1));
if (preproc.compare(0, 6, "define") == 0)
{
if (!inStatementIndentStack->empty()
&& inStatementIndentStack->back() > 0)
{
defineTabCount = tabCount;
}
else
{
defineTabCount = tabCount - 1;
tabCount--;
}
}
}
tabCount -= defineTabCount;
}
if (tabCount < 0)
tabCount = 0;
if (lineCommentNoBeautify || blockCommentNoBeautify)
tabCount = spaceTabCount = 0;
// finally, insert indentations into begining of line
prevFinalLineSpaceTabCount = spaceTabCount;
prevFinalLineTabCount = tabCount;
if (shouldForceTabIndentation)
{
tabCount += spaceTabCount / indentLength;
spaceTabCount = spaceTabCount % indentLength;
}
outBuffer = preLineWS(spaceTabCount, tabCount) + outBuffer;
if (lastLineHeader != NULL)
previousLastLineHeader = lastLineHeader;
return outBuffer;
}
string ASBeautifier::preLineWS(int spaceTabCount, int tabCount)
{
string ws;
for (int i = 0; i < tabCount; i++)
ws += indentString;
while ((spaceTabCount--) > 0)
ws += string(" ");
return ws;
}
/**
* register an in-statement indent.
*/
void ASBeautifier::registerInStatementIndent(const string &line, int i, int spaceTabCount,
int minIndent, bool updateParenStack)
{
int inStatementIndent;
int remainingCharNum = line.length() - i;
int nextNonWSChar = getNextProgramCharDistance(line, i);
// if indent is around the last char in the line, indent instead 2 spaces from the previous indent
if (nextNonWSChar == remainingCharNum)
{
int previousIndent = spaceTabCount;
if (!inStatementIndentStack->empty())
previousIndent = inStatementIndentStack->back();
inStatementIndentStack->push_back(/*2*/ indentLength + previousIndent);
if (updateParenStack)
parenIndentStack->push_back(previousIndent);
return;
}
if (updateParenStack)
parenIndentStack->push_back(i + spaceTabCount);
inStatementIndent = i + nextNonWSChar + spaceTabCount;
if (i + nextNonWSChar < minIndent)
inStatementIndent = minIndent + spaceTabCount;
if (i + nextNonWSChar > maxInStatementIndent)
inStatementIndent = indentLength * 2 + spaceTabCount;
if (!inStatementIndentStack->empty() &&
inStatementIndent < inStatementIndentStack->back())
inStatementIndent = inStatementIndentStack->back();
if (isNonInStatementArray)
inStatementIndent = 0;
inStatementIndentStack->push_back(inStatementIndent);
}
/**
* get distance to the next non-white sspace, non-comment character in the line.
* if no such character exists, return the length remaining to the end of the line.
*/
int ASBeautifier::getNextProgramCharDistance(const string &line, int i)
{
bool inComment = false;
int remainingCharNum = line.length() - i;
int charDistance;
char ch;
for (charDistance = 1; charDistance < remainingCharNum; charDistance++)
{
ch = line[i + charDistance];
if (inComment)
{
if (line.compare(i + charDistance, 2, "*/") == 0)
{
charDistance++;
inComment = false;
}
continue;
}
else if (isWhiteSpace(ch))
continue;
else if (ch == '/')
{
if (line.compare(i + charDistance, 2, "//") == 0)
return remainingCharNum;
else if (line.compare(i + charDistance, 2, "/*") == 0)
{
charDistance++;
inComment = true;
}
}
else
return charDistance;
}
return charDistance;
}
/**
* check if a specific line position contains a header, out of several possible headers.
*
* @return a pointer to the found header. if no header was found then return NULL.
*/
const string *ASBeautifier::findHeader(const string &line, int i, const vector<const string*> &possibleHeaders, bool checkBoundry)
{
int maxHeaders = possibleHeaders.size();
// const string *header = NULL;
int p;
for (p = 0; p < maxHeaders; p++)
{
const string *header = possibleHeaders[p];
if (line.compare(i, header->length(), header->c_str()) == 0)
{
// check that this is a header and not a part of a longer word
// (e.g. not at its begining, not at its middle...)
int lineLength = line.length();
int headerEnd = i + header->length();
char startCh = (*header)[0]; // first char of header
char endCh = 0; // char just after header
char prevCh = 0; // char just before header
if (headerEnd < lineLength)
{
endCh = line[headerEnd];
}
if (i > 0)
{
prevCh = line[i-1];
}
if (!checkBoundry)
{
return header;
}
else if (prevCh != 0
&& isLegalNameChar(startCh)
&& isLegalNameChar(prevCh))
{
return NULL;
}
else if (headerEnd >= lineLength
|| !isLegalNameChar(startCh)
|| !isLegalNameChar(endCh))
{
return header;
}
else
{
return NULL;
}
}
}
return NULL;
}
/**
* find the index number of a string element in a container of strings
*
* @return the index number of element in the ocntainer. -1 if element not found.
* @param container a vector of strings.
* @param element the element to find .
*/
int ASBeautifier::indexOf(vector<const string*> &container, const string *element)
{
vector<const string*>::const_iterator where;
where = find(container.begin(), container.end(), element);
if (where == container.end())
return -1;
else
return (int) (where - container.begin());
}
/**
* trim removes the white space surrounding a line.
*
* @return the trimmed line.
* @param str the line to trim.
*/
string ASBeautifier::trim(const string &str)
{
int start = 0;
int end = str.length() - 1;
while (start < end && isWhiteSpace(str[start]))
start++;
while (start <= end && isWhiteSpace(str[end]))
end--;
string returnStr(str, start, end + 1 - start);
return returnStr;
}
/**
* peek at the next unread character.
*
* @return the next unread character.
* @param line the line to check.
* @param i the current char position on the line.
*/
char ASBeautifier::peekNextChar(string &line, int i)
{
char ch = ' ';
size_t peekNum = line.find_first_not_of(" \t", i + 1);
if (peekNum == string::npos)
return ch;
ch = line[peekNum];
return ch;
}
} // end namespace astyle