Logo Search packages:      
Sourcecode: codeblocks version File versions  Download package

ASFormatter.cpp

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *
 *   ASFormatter.cpp
 *
 *   This file is a part of "Artistic Style" - an indentation and
 *   reformatting tool for C, C++, C# and Java source files.
 *   http://astyle.sourceforge.net
 *
 *   The "Artistic Style" project, including all files needed to
 *   compile it, is free software; you can redistribute it and/or
 *   modify it under the terms of the GNU Lesser General Public
 *   License as published by the Free Software Foundation; either
 *   version 2.1 of the License, or (at your option) any later
 *   version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU Lesser General Public License for more details.
 *
 *   You should have received a copy of the GNU Lesser General Public
 *   License along with this project; if not, write to the
 *   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 *   Boston, MA  02110-1301, USA.
 *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 */

#include "astyle.h"

#include <algorithm>
#include <fstream>
#include <iostream>
#ifdef __VMS
#include <assert>
#else
#include <cassert>
#endif

// can trace only if NDEBUG is not defined
#ifndef NDEBUG
// #define TRACEunpad
// #define TRACEcomment
// #define TRACEheader
// #define TRACEbracket
// #define TRACEarray
#if defined(TRACEunpad) || defined(TRACEcomment) || defined(TRACEheader) \
|| defined(TRACEbracket) || defined(TRACEarray)
ofstream *traceOutF;
#define TRACEF
#endif
#endif

#ifdef TRACEunpad
#define TRunpad(a,b,c)  if(b > 0 || c > 0) *traceOutF << outLineNumber << " " << b << a << c << endl
#else
#define TRunpad(a,b,c)  ((void)0)
#endif

#ifdef TRACEcomment
#define TRcomment(a)    *traceOutF << outLineNumber << " " << a << endl
#else
#define TRcomment(a)    ((void)0)
#endif

#ifdef TRACEheader
#define TRxtra(a)       *traceOutF << outLineNumber << " " << a << endl
#else
#define TRxtra(a)    ((void)0)
#endif

#ifdef TRACEbracket
#define TRbracket(a)       *traceOutF << outLineNumber << " " << a << endl
#else
#define TRbracket(a)    ((void)0)
#endif

#ifdef TRACEarray
#define TRarray(a)      *traceOutF << outLineNumber << " " << a << endl
#else
#define TRarray(a)      ((void)0)
#endif

#define INIT_CONTAINER(container, value)     {if ( (container) != NULL ) delete (container); (container) = (value); }
#define DELETE_CONTAINER(container)          {if ( (container) != NULL ) delete (container); }
#define IS_A(a,b)                            ( ((a) & (b)) == (b))

using namespace std;

namespace astyle
{
vector<const string*> ASFormatter::headers;
vector<const string*> ASFormatter::nonParenHeaders;
vector<const string*> ASFormatter::preDefinitionHeaders;
vector<const string*> ASFormatter::preCommandHeaders;
vector<const string*> ASFormatter::operators;
vector<const string*> ASFormatter::assignmentOperators;
vector<const string*> ASFormatter::castOperators;

/**
 * Constructor of ASFormatter
 */
ASFormatter::ASFormatter()
{
      preBracketHeaderStack = NULL;
      bracketTypeStack = NULL;
      parenStack = NULL;
      lineCommentNoIndent = false;
      sourceIterator = NULL;
      bracketFormatMode = NONE_MODE;
      shouldPadOperators = false;
      shouldPadParensOutside = false;
      shouldPadParensInside = false;
      shouldUnPadParens = false;
      shouldBreakOneLineBlocks = true;
      shouldBreakOneLineStatements = true;
      shouldConvertTabs = false;
      shouldBreakBlocks = false;
      shouldBreakClosingHeaderBlocks = false;
      shouldBreakClosingHeaderBrackets = false;
      shouldBreakElseIfs = false;
#ifdef TRACEF
      // create a trace text file
      string filename = "tracef.txt";
      char* env = getenv("HOME");
      if (env != NULL)
            filename = string(env) + string("/tracef.txt");
      else
      {
            env = getenv("USERPROFILE");
            if (env != NULL)
                  filename = string(env) + string("\\My Documents\\tracef.txt");
            else
            {
                  cout << "\nCould not open tracef.txt\n" << endl;
                  exit(1);
            }
      }
      traceOutF = new ofstream(filename.c_str());
#endif
}

/**
 * Destructor of ASFormatter
 */
ASFormatter::~ASFormatter()
{
      DELETE_CONTAINER(preBracketHeaderStack);
#ifdef TRACEF
      delete traceOutF;
#endif
}

/**
 * initialization of static data of ASFormatter.
 */
void ASFormatter::staticInit()
{
      static int formatterFileType = 9;      // initialized with an invalid type

      if (fileType == formatterFileType)     // don't build unless necessary
            return;

      formatterFileType = fileType;

      headers.clear();
      nonParenHeaders.clear();
      assignmentOperators.clear();
      operators.clear();
      preDefinitionHeaders.clear();
      preCommandHeaders.clear();
      castOperators.clear();

      ASResource::buildHeaders(headers, fileType);
      ASResource::buildNonParenHeaders(nonParenHeaders, fileType);
      ASResource::buildAssignmentOperators(assignmentOperators);
      ASResource::buildOperators(operators);
      ASResource::buildPreDefinitionHeaders(preDefinitionHeaders);
      ASResource::buildPreCommandHeaders(preCommandHeaders);
      ASResource::buildCastOperators(castOperators);
}

/**
 * initialize the ASFormatter.
 *
 * init() should be called every time a ASFormatter object is to start
 * formatting a NEW source file.
 * init() recieves a pointer to a DYNAMICALLY CREATED ASSourceIterator object
 * that will be used to iterate through the source code. This object will be
 * deleted during the ASFormatter's destruction, and thus should not be
 * deleted elsewhere.
 *
 * @param iter     a pointer to the DYNAMICALLY CREATED ASSourceIterator object.
 */
void ASFormatter::init(ASSourceIterator *si)
{
      staticInit();

      ASBeautifier::init(si);
      ASEnhancer::init(ASBeautifier::getIndentLength(),
                       ASBeautifier::getIndentString(),
                       ASBeautifier::getCStyle(),
                       ASBeautifier::getJavaStyle(),
                       ASBeautifier::getSharpStyle(),
                       ASBeautifier::getCaseIndent(),
                       ASBeautifier::getEmptyLineFill());
      sourceIterator = si;

      INIT_CONTAINER(preBracketHeaderStack, new vector<const string*>);
      INIT_CONTAINER(bracketTypeStack, new vector<BracketType>);
      bracketTypeStack->push_back(NULL_TYPE);
      INIT_CONTAINER(parenStack, new vector<int>);
      parenStack->push_back(0);

      currentHeader = NULL;
      currentLine = string("");
      readyFormattedLine = string("");
      formattedLine = "";
      currentChar = ' ';
      previousChar = ' ';
      previousCommandChar = ' ';
      previousNonWSChar = ' ';
      quoteChar = '"';
      charNum = 0;
      spacePadNum = 0;
      previousReadyFormattedLineLength = string::npos;
      templateDepth = 0;
      previousBracketType = NULL_TYPE;
      previousOperator = NULL;

      isVirgin = true;
      isInLineComment = false;
      isInComment = false;
      isInPreprocessor = false;
      doesLineStartComment = false;
      isInQuote = false;
      isSpecialChar = false;
      isNonParenHeader = true;
      foundNamespaceHeader = false;
      foundClassHeader = false;
      foundPreDefinitionHeader = false;
      foundPreCommandHeader = false;
      foundCastOperator = false;
      foundQuestionMark = false;
      isInLineBreak = false;
      endOfCodeReached = false;
      isLineReady = false;
      isPreviousBracketBlockRelated = true;
      isInPotentialCalculation = false;
      shouldReparseCurrentChar = false;
      passedSemicolon = false;
      passedColon = false;
      isInTemplate = false;
      isInBlParen = false;
      shouldBreakLineAfterComments = false;
      isImmediatelyPostComment = false;
      isImmediatelyPostLineComment = false;
      isImmediatelyPostEmptyBlock = false;
      isImmediatelyPostPreprocessor = false;

      isPrependPostBlockEmptyLineRequested = false;
      isAppendPostBlockEmptyLineRequested = false;
      prependEmptyLine = false;
      appendOpeningBracket = false;

      foundClosingHeader = false;
      previousReadyFormattedLineLength = 0;

      isImmediatelyPostHeader = false;
      isInHeader = false;
#ifdef TRACEF
      // fileName will be empty if ASTYLE_LIB is defined
      if (fileName.empty())
            *traceOutF << "new file" << endl;
      else
            *traceOutF << fileName << endl;
#endif
}

/**
 * get the next formatted line.
 *
 * @return    formatted line.
 */

string ASFormatter::nextLine()
{
      // these are reset with each new line
      const string *newHeader;
      bool isInVirginLine = isVirgin;
      isCharImmediatelyPostComment = false;
      isPreviousCharPostComment = false;
      isCharImmediatelyPostLineComment = false;
      isCharImmediatelyPostOpenBlock = false;
      isCharImmediatelyPostCloseBlock = false;
      isCharImmediatelyPostTemplate = false;

      while (!isLineReady)
      {
            if (shouldReparseCurrentChar)
                  shouldReparseCurrentChar = false;
            else if (!getNextChar())
            {
                  breakLine();
                  return beautify(readyFormattedLine);
            }
            else // stuff to do when reading a new character...
            {
                  // make sure that a virgin '{' at the begining ofthe file will be treated as a block...
                  if (isInVirginLine && currentChar == '{')
                        previousCommandChar = '{';
                  isPreviousCharPostComment = isCharImmediatelyPostComment;
                  isCharImmediatelyPostComment = false;
                  isCharImmediatelyPostTemplate = false;
            }

            //if (inLineNumber >= 185)
            //    int x = 1;

            if (isInLineComment)
            {
                  appendCurrentChar();

                  // explicitely break a line when a line comment's end is found.
                  if (charNum + 1 == (int) currentLine.length())
                  {
                        isInLineBreak = true;
                        isInLineComment = false;
                        isImmediatelyPostLineComment = true;
                        currentChar = 0;  //make sure it is a neutral char.
                  }
                  continue;
            }
            else if (isInComment)
            {
                  if (isSequenceReached("*/"))
                  {
                        isInComment = false;
                        isImmediatelyPostComment = true;
                        appendSequence(AS_CLOSE_COMMENT);
                        goForward(1);
                  }
                  else
                        appendCurrentChar();

                  continue;
            }

            // not in line comment or comment

            else if (isInQuote)
            {
                  if (isSpecialChar)
                  {
                        isSpecialChar = false;
                        appendCurrentChar();
                  }
                  else if (currentChar == '\\')
                  {
                        isSpecialChar = true;
                        appendCurrentChar();
                  }
                  else if (quoteChar == currentChar)
                  {
                        isInQuote = false;
                        appendCurrentChar();
                  }
                  else
                  {
                        appendCurrentChar();
                  }

                  continue;
            }

            // handle white space - needed to simplify the rest.
            if (isWhiteSpace(currentChar) || isInPreprocessor)
            {
                  appendCurrentChar();
                  continue;
            }

            /* not in MIDDLE of quote or comment or white-space of any type ... */

            if (isSequenceReached("//"))
            {
                  if (currentLine[charNum+2] == '\xf2')           // check for windows line marker
                        isAppendPostBlockEmptyLineRequested = false;
                  isInLineComment = true;
                  // do not indent if in column 1 or 2
                  if (lineCommentNoIndent == false)
                  {
                        if (charNum == 0)
                              lineCommentNoIndent = true;
                        else if (charNum == 1 && currentLine[0] == ' ')
                              lineCommentNoIndent = true;
                  }
                  // move comment if spaces were added or deleted
                  if (lineCommentNoIndent == false && spacePadNum != 0)
                        adjustComments();
                  formattedLineCommentNum = formattedLine.length();
                  appendSequence(AS_OPEN_LINE_COMMENT);
                  goForward(1);
                  // explicitely break a line when a line comment's end is found.
                  if (charNum + 1 == (int) currentLine.length())
                  {
                        isInLineBreak = true;
                        isInLineComment = false;
                        isImmediatelyPostLineComment = true;
                        currentChar = 0;  //make sure it is a neutral char.
                  }
                  continue;
            }
            else if (isSequenceReached("/*"))
            {
                  isInComment = true;
                  if (spacePadNum != 0)
                        adjustComments();
                  formattedLineCommentNum = formattedLine.length();
                  appendSequence(AS_OPEN_COMMENT);
                  goForward(1);
                  continue;
            }
            else if (currentChar == '"' || currentChar == '\'')
            {
                  isInQuote = true;
                  quoteChar = currentChar;
                  appendCurrentChar();
                  continue;
            }

            /* not in quote or comment or white-space of any type ... */

            // check if in preprocessor
            // ** isInPreprocessor will be automatically reset at the begining
            //    of a new line in getnextChar()
            if (currentChar == '#')
            {
                  isInPreprocessor = true;
                  appendCurrentChar();
                  continue;
            }

            /* not in preprocessor ... */

            if (isImmediatelyPostComment)
            {
                  isImmediatelyPostComment = false;
                  isCharImmediatelyPostComment = true;
            }

            if (isImmediatelyPostLineComment)
            {
                  isImmediatelyPostLineComment = false;
                  isCharImmediatelyPostLineComment = true;
            }

            if (shouldBreakLineAfterComments)
            {
                  shouldBreakLineAfterComments = false;
                  shouldReparseCurrentChar = true;
                  breakLine();
                  continue;
            }

            // reset isImmediatelyPostHeader information
            if (isImmediatelyPostHeader)
            {
                  isImmediatelyPostHeader = false;

                  // Make sure headers are broken from their succeeding blocks
                  // (e.g.
                  //     if (isFoo) DoBar();
                  //  should become
                  //     if (isFoo)
                  //         DoBar;
                  // )
                  // But treat else if() as a special case which should not be broken!
                  if (shouldBreakOneLineStatements)
                  {
                        // if may break 'else if()'s, then simply break the line

                        if (shouldBreakElseIfs)
                              isInLineBreak = true;
                  }
            }

            if (passedSemicolon)    // need to break the formattedLine
            {
                  passedSemicolon = false;
                  if (parenStack->back() == 0 && currentChar != ';') // allow ;;
                  {
                        // does a one-line statement have ending comments?
                        if (IS_A(bracketTypeStack->back(), SINGLE_LINE_TYPE))
                        {
                              size_t blockEnd = currentLine.rfind(AS_CLOSE_BRACKET);
                              assert(blockEnd != string::npos);
                              // move ending comments to this formattedLine
                              if (isBeforeLineEndComment(blockEnd))
                              {
                                    size_t commentStart = currentLine.find_first_not_of(" \t", blockEnd + 1);
                                    assert(commentStart != string::npos);
                                    assert((currentLine.compare(commentStart, 2, "//") == 0)
                                           || (currentLine.compare(commentStart, 2, "/*") == 0));
                                    size_t commentLength = currentLine.length() - commentStart;
                                    int tabCount = getIndentLength();
                                    appendSpacePad();
                                    for (int i=1; i<tabCount; i++)
                                          formattedLine.append(1, ' ');
                                    formattedLine.append(currentLine, commentStart, commentLength);
                                    currentLine.erase(commentStart, commentLength);
                              }
                        }
                        shouldReparseCurrentChar = true;
                        isInLineBreak = true;
                        continue;
                  }
            }

            if (passedColon)
            {
                  passedColon = false;
                  if (parenStack->back() == 0 && !isBeforeComment())
                  {
                        shouldReparseCurrentChar = true;
                        isInLineBreak = true;
                        continue;
                  }
            }

            // Check if in template declaration, e.g. foo<bar> or foo<bar,fig>
            // If so, set isInTemplate to true
            if (!isInTemplate && currentChar == '<')
            {
                  int maxTemplateDepth = 0;
                  templateDepth = 0;
                  const string *oper;
                  for (size_t i = charNum;
                          i < currentLine.length();
                          i += (oper ? oper->length() : 1))
                  {
                        oper = ASBeautifier::findHeader(currentLine, i, operators);

                        if (oper == &AS_LS)
                        {
                              templateDepth++;
                              maxTemplateDepth++;
                        }
                        else if (oper == &AS_GR)
                        {
                              templateDepth--;
                              if (templateDepth == 0)
                              {
                                    // this is a template!
                                    isInTemplate = true;
                                    templateDepth = maxTemplateDepth;
                                    break;
                              }
                        }
                        else if (oper == &AS_COMMA            // comma,     e.g. A<int, char>
                                 || oper == &AS_BIT_AND       // reference, e.g. A<int&>
                                 || oper == &AS_MULT          // pointer,   e.g. A<int*>
                                 || oper == &AS_COLON_COLON)  // ::,        e.g. std::string
                        {
                              continue;
                        }
                        else if (!isLegalNameChar(currentLine[i]) && !isWhiteSpace(currentLine[i]))
                        {
                              // this is not a template -> leave...
                              isInTemplate = false;
                              break;
                        }
                  }
            }

            // handle parenthesies
            if (currentChar == '(' || currentChar == '[' || (isInTemplate && currentChar == '<'))
            {
                  parenStack->back()++;
                  if (currentChar == '[')
                        isInBlParen = true;
            }
            else if (currentChar == ')' || currentChar == ']' || (isInTemplate && currentChar == '>'))
            {
                  parenStack->back()--;
                  if (isInTemplate && currentChar == '>')
                  {
                        templateDepth--;
                        if (templateDepth == 0)
                        {
                              isInTemplate = false;
                              isCharImmediatelyPostTemplate = true;
                        }
                  }

                  // check if this parenthesis closes a header, e.g. if (...), while (...)
                  if (isInHeader && parenStack->back() == 0)
                  {
                        isInHeader = false;
                        isImmediatelyPostHeader = true;
                  }
                  if (currentChar == ']')
                        isInBlParen = false;
                  if (currentChar == ')')
                        foundCastOperator = false;
            }

            // handle brackets
            if (currentChar == '{' || currentChar == '}')
            {
                  if (currentChar == '{')
                  {
                        BracketType newBracketType = getBracketType();
                        foundNamespaceHeader = false;
                        foundClassHeader = false;
                        foundPreDefinitionHeader = false;
                        foundPreCommandHeader = false;
                        isInPotentialCalculation = false;

                        bracketTypeStack->push_back(newBracketType);
                        preBracketHeaderStack->push_back(currentHeader);
                        currentHeader = NULL;

                        isPreviousBracketBlockRelated = !IS_A(newBracketType, ARRAY_TYPE);
                  }

                  // this must be done before the bracketTypeStack is popped
                  BracketType bracketType = bracketTypeStack->back();
                  bool isOpeningArrayBracket = (IS_A(bracketType, ARRAY_TYPE)
                                                && bracketTypeStack->size() >= 2
                                                && !IS_A((*bracketTypeStack)[bracketTypeStack->size()-2], ARRAY_TYPE)
                                               );

                  if (currentChar == '}')
                  {
                        // if a request has been made to append a post block empty line,
                        // but the block exists immediately before a closing bracket,
                        // then there is not need for the post block empty line.
                        //
                        isAppendPostBlockEmptyLineRequested = false;

                        if (!bracketTypeStack->empty())
                        {
                              previousBracketType = bracketTypeStack->back();
                              bracketTypeStack->pop_back();
                              isPreviousBracketBlockRelated = !IS_A(bracketType, ARRAY_TYPE);
                        }

                        if (!preBracketHeaderStack->empty())
                        {
                              currentHeader = preBracketHeaderStack->back();
                              preBracketHeaderStack->pop_back();
                        }
                        else
                              currentHeader = NULL;
                  }

                  // format brackets
                  if (IS_A(bracketType, ARRAY_TYPE))
                        formatArrayBrackets(bracketType, isOpeningArrayBracket);
                  else
                        formatBrackets(bracketType);
                  continue;
            }

            if (((previousCommandChar == '{' && isPreviousBracketBlockRelated)
                    || (previousCommandChar == '}'
                        && bracketFormatMode != NONE_MODE
                        && !isImmediatelyPostEmptyBlock
                        && isPreviousBracketBlockRelated
                        && !isPreviousCharPostComment       // Fixes wrongly appended newlines after '}' immediately after comments
                        && peekNextChar() != ' '
                        && !IS_A(previousBracketType,  DEFINITION_TYPE)
                        && !(ASBeautifier::isJavaStyle && currentChar == ')'))
                    && !IS_A(bracketTypeStack->back(),  DEFINITION_TYPE))
                    && (shouldBreakOneLineBlocks
                        || !IS_A(bracketTypeStack->back(),  SINGLE_LINE_TYPE)))
            {
                  isCharImmediatelyPostOpenBlock = (previousCommandChar == '{');
                  isCharImmediatelyPostCloseBlock = (previousCommandChar == '}');

                  //if (bracketFormatMode != NONE_MODE)
                  //{
                  previousCommandChar = ' ';
                  isInLineBreak = true;
                  //}
            }

            // reset block handling flags
            isImmediatelyPostEmptyBlock = false;

            // look for headers
            if (!isInTemplate)
            {
                  if ((newHeader = findHeader(headers)) != NULL)
                  {
                        foundClosingHeader = false;
                        const string *previousHeader;

                        // recognize closing headers of do..while, if..else, try..catch..finally
                        if ((newHeader == &AS_ELSE && currentHeader == &AS_IF)
                                || (newHeader == &AS_WHILE && currentHeader == &AS_DO)
                                || (newHeader == &AS_CATCH && currentHeader == &AS_TRY)
                                || (newHeader == &AS_CATCH && currentHeader == &AS_CATCH)
                                || (newHeader == &AS_FINALLY && currentHeader == &AS_TRY)
                                || (newHeader == &AS_FINALLY && currentHeader == &AS_CATCH))
                              foundClosingHeader = true;

                        previousHeader = currentHeader;
                        currentHeader = newHeader;

                        // If in ATTACH or LINUX bracket modes, attach closing headers (e.g. 'else', 'catch')
                        // to their preceding bracket,
                        // But do not perform the attachment if the shouldBreakClosingHeaderBrackets is set!
                        if (!shouldBreakClosingHeaderBrackets
                                && foundClosingHeader
                                && (bracketFormatMode == ATTACH_MODE || bracketFormatMode == BDAC_MODE)
                                && (shouldBreakOneLineBlocks || !IS_A(previousBracketType,  SINGLE_LINE_TYPE))
                                && previousNonWSChar == '}')
                        {
                              spacePadNum = 0;                // don't count as padding

                              size_t firstChar = formattedLine.find_first_not_of(" \t");
                              if (firstChar != string::npos)            // if a blank line does not preceed this
                              {
                                    isInLineBreak = false;
                                    appendSpacePad();
                              }

                              if (shouldBreakBlocks)
                                    isAppendPostBlockEmptyLineRequested = false;
                        }

                        // If NONE bracket mode, leave closing headers as they are (e.g. 'else', 'catch')
                        if (foundClosingHeader && bracketFormatMode == NONE_MODE && previousCommandChar == '}')
                        {
                              if (lineBeginsWith('}'))                    // is closing bracket broken?
                              {
                                    isInLineBreak = false;
                                    appendSpacePad();
                              }

                              if (shouldBreakBlocks)
                                    isAppendPostBlockEmptyLineRequested = false;
                        }

                        if (foundClosingHeader && bracketFormatMode == BREAK_MODE && previousCommandChar == '}')
                              breakLine();

                        //Check if a template definition as been reached, e.g. template<class A>
                        //if (newHeader == &AS_TEMPLATE)
                        //{
                        //    isInTemplate = true;
                        //}

                        // check if the found header is non-paren header
                        isNonParenHeader = (find(nonParenHeaders.begin(), nonParenHeaders.end(),
                                                 newHeader) != nonParenHeaders.end());

                        appendSequence(*currentHeader);
                        goForward(currentHeader->length() - 1);
                        // if a paren-header is found add a space after it, if needed
                        // this checks currentLine, appendSpacePad() checks formattedLine
                        if (!isNonParenHeader && charNum < (int) currentLine.length() && !isWhiteSpace(currentLine[charNum+1]))
                              appendSpacePad();

                        // Signal that a header has been reached
                        // *** But treat a closing while() (as in do...while)
                        //     as if it where NOT a header since a closing while()
                        //     should never have a block after it!
                        if (!(foundClosingHeader && currentHeader == &AS_WHILE))
                        {
                              isInHeader = true;
                              if (isNonParenHeader)
                              {
                                    isImmediatelyPostHeader = true;
                                    isInHeader = false;
                              }
                        }

                        if (currentHeader == &AS_IF && previousHeader == &AS_ELSE)
                              isInLineBreak = false;

                        if (shouldBreakBlocks)
                        {
                              if (previousHeader == NULL
                                      && !foundClosingHeader
                                      && !isCharImmediatelyPostOpenBlock)
                              {
                                    isPrependPostBlockEmptyLineRequested = true;
                              }

                              if (currentHeader == &AS_ELSE
                                      || currentHeader == &AS_CATCH
                                      || currentHeader == &AS_FINALLY
                                      || foundClosingHeader)
                              {
                                    isPrependPostBlockEmptyLineRequested = false;
                              }

                              if (shouldBreakClosingHeaderBlocks
                                      &&  isCharImmediatelyPostCloseBlock)
                              {
                                    isPrependPostBlockEmptyLineRequested = true;
                              }

                        }

                        continue;
                  }
                  else if ((newHeader = findHeader(preDefinitionHeaders)) != NULL
                           && parenStack->back() == 0)
                  {
                        if (newHeader == &AS_NAMESPACE)
                              foundNamespaceHeader = true;
                        if (newHeader == &AS_CLASS)
                              foundClassHeader = true;
                        foundPreDefinitionHeader = true;
                        appendSequence(*newHeader);
                        goForward(newHeader->length() - 1);

                        if (shouldBreakBlocks)
                              isPrependPostBlockEmptyLineRequested = true;

                        continue;
                  }
                  else if ((newHeader = findHeader(preCommandHeaders)) != NULL)
                  {
                        if (ASBeautifier::isJavaStyle
                                || (*newHeader == AS_CONST && previousCommandChar == ')') // 'const' member functions is a command bracket
                                || *newHeader == AS_EXTERN)
                              foundPreCommandHeader = true;
                        appendSequence(*newHeader);
                        goForward(newHeader->length() - 1);

                        continue;
                  }
                  else if ((newHeader = findHeader(castOperators)) != NULL)
                  {
                        foundCastOperator = true;
                        appendSequence(*newHeader);
                        goForward(newHeader->length() - 1);

                        continue;
                  }

            }

            if (isInLineBreak)          // OK to break line here
                  breakLine();

            if (previousNonWSChar == '}' || currentChar == ';')
            {
                  if (shouldBreakOneLineStatements && currentChar == ';'
                          && (shouldBreakOneLineBlocks || !IS_A(bracketTypeStack->back(),  SINGLE_LINE_TYPE))
                          //&& (! bracketFormatMode == NONE_MODE)
                     )
                  {
                        passedSemicolon = true;
                  }

                  if (shouldBreakBlocks && currentHeader != NULL && parenStack->back() == 0)
                  {
                        isAppendPostBlockEmptyLineRequested = true;
                  }

                  if (currentChar != ';')
                        currentHeader = NULL;

                  foundQuestionMark = false;
                  foundNamespaceHeader = false;
                  foundClassHeader = false;
                  foundPreDefinitionHeader = false;
                  foundPreCommandHeader = false;
                  foundCastOperator = false;
                  isInPotentialCalculation = false;
                  isNonInStatementArray = false;
            }

            if (currentChar == ':'
                    && shouldBreakOneLineStatements
                    && !foundQuestionMark           // not in a ... ? ... : ... sequence
                    && !foundPreDefinitionHeader    // not in a definition block (e.g. class foo : public bar
                    && previousCommandChar != ')'   // not immediately after closing paren of a method header, e.g. ASFormatter::ASFormatter(...) : ASBeautifier(...)
                    && previousChar != ':'          // not part of '::'
                    && peekNextChar() != ':')       // not part of '::'
            {
                  passedColon = true;
                  if (shouldBreakBlocks)
                        isPrependPostBlockEmptyLineRequested = true;
            }

            if (currentChar == '?')
                  foundQuestionMark = true;

            // determine if this is a potential calculation
            newHeader = findHeader(operators);

            if (newHeader != NULL)
            {
                  if (!isInPotentialCalculation)
                  {
                        if (find(assignmentOperators.begin(), assignmentOperators.end(), newHeader)
                                != assignmentOperators.end())
                        {
                              char peekedChar = peekNextChar();
                              isInPotentialCalculation = (newHeader != &AS_RETURN
                                                          && !(newHeader == &AS_EQUAL && peekedChar == '*')
                                                          && !(newHeader == &AS_EQUAL && peekedChar == '&'));
                        }
                  }
            }
            else
            {
                  // the following are not calculations
                  if (currentLine.compare(charNum, 3, "new") == 0 && !isLegalNameChar(currentLine[charNum+3]))
                        isInPotentialCalculation = false;
            }

            if (shouldPadOperators && newHeader != NULL)
            {
                  padOperators(newHeader);
                  continue;
            }

            if ((shouldPadParensOutside || shouldPadParensInside || shouldUnPadParens)
                    && (currentChar == '(' || currentChar == ')'))
            {
                  padParens();
                  continue;
            }

            appendCurrentChar();
      }   // end of while loop  *  end of while loop  *  end of while loop  *  end of while loop

      // return a beautified (i.e. correctly indented) line.

      string beautifiedLine;
      size_t readyFormattedLineLength = trim(readyFormattedLine).length();

      if (prependEmptyLine                // prepend a blank line before this formatted line
              && readyFormattedLineLength > 0
              && previousReadyFormattedLineLength > 0)
      {
            isLineReady = true;             // signal that a readyFormattedLine is still waiting
            beautifiedLine = beautify("");
            previousReadyFormattedLineLength = 0;
      }
      else                                            // format the current formatted line
      {
            isLineReady = false;
            beautifiedLine = beautify(readyFormattedLine);
            previousReadyFormattedLineLength = readyFormattedLineLength;
            lineCommentNoBeautify = lineCommentNoIndent;
            lineCommentNoIndent = false;
            if (appendOpeningBracket)       // insert bracket after this formatted line
            {
                  appendOpeningBracket = false;
                  isLineReady = true;         // signal that a readyFormattedLine is still waiting
                  readyFormattedLine = "{";
                  isPrependPostBlockEmptyLineRequested = false;   // next line should not be empty
            }
      }

      prependEmptyLine = false;
      enhance(beautifiedLine);                // call the enhancer function
      return beautifiedLine;
}


/**
* check if there are any indented lines ready to be read by nextLine()
*
* @return    are there any indented lines ready?
*/
bool ASFormatter::hasMoreLines() const
{
      return !endOfCodeReached;
}

/**
 * set the bracket formatting mode.
 * options:
 *    astyle::NONE_MODE     no formatting of brackets.
 *    astyle::ATTACH_MODE   Java, K&R style bracket placement.
 *    astyle::BREAK_MODE    ANSI C/C++ style bracket placement.
 *
 * @param mode         the bracket formatting mode.
 */
void ASFormatter::setBracketFormatMode(BracketMode mode)
{
      bracketFormatMode = mode;
}

/**
 * set closing header bracket breaking mode
 * options:
 *    true     brackets just before closing headers (e.g. 'else', 'catch')
 *             will be broken, even if standard brackets are attached.
 *    false    closing header brackets will be treated as standard brackets.
 *
 * @param state         the closing header bracket breaking mode.
 */
void ASFormatter::setBreakClosingHeaderBracketsMode(bool state)
{
      shouldBreakClosingHeaderBrackets = state;
}

/**
 * set 'else if()' breaking mode
 * options:
 *    true     'else' headers will be broken from their succeeding 'if' headers.
 *    false    'else' headers will be attached to their succeeding 'if' headers.
 *
 * @param state         the 'else if()' breaking mode.
 */
void ASFormatter::setBreakElseIfsMode(bool state)
{
      shouldBreakElseIfs = state;
}

/**
 * set operator padding mode.
 * options:
 *    true     statement operators will be padded with spaces around them.
 *    false    statement operators will not be padded.
 *
 * @param state         the padding mode.
 */
void ASFormatter::setOperatorPaddingMode(bool state)
{
      shouldPadOperators = state;
}

/**
* set parenthesis outside padding mode.
* options:
*    true     statement parenthesiss will be padded with spaces around them.
*    false    statement parenthesiss will not be padded.
*
* @param state         the padding mode.
*/
void ASFormatter::setParensOutsidePaddingMode(bool state)
{
      shouldPadParensOutside = state;
}

/**
* set parenthesis inside padding mode.
* options:
*    true     statement parenthesis will be padded with spaces around them.
*    false    statement parenthesis will not be padded.
*
* @param state         the padding mode.
*/
void ASFormatter::setParensInsidePaddingMode(bool state)
{
      shouldPadParensInside = state;
}

/**
* set parenthesis unpadding mode.
* options:
*    true     statement parenthesis will be unpadded with spaces removed around them.
*    false    statement parenthesis will not be unpadded.
*
* @param state         the padding mode.
*/
void ASFormatter::setParensUnPaddingMode(bool state)
{
      shouldUnPadParens = state;
}

/**
 * set option to break/not break one-line blocks
 *
 * @param state        true = break, false = don't break.
 */
void ASFormatter::setBreakOneLineBlocksMode(bool state)
{
      shouldBreakOneLineBlocks = state;
}

/**
 * set option to break/not break lines consisting of multiple statements.
 *
 * @param state        true = break, false = don't break.
 */
void ASFormatter::setSingleStatementsMode(bool state)
{
      shouldBreakOneLineStatements = state;
}

/**
 * set option to convert tabs to spaces.
 *
 * @param state        true = convert, false = don't convert.
 */
void ASFormatter::setTabSpaceConversionMode(bool state)
{
      shouldConvertTabs = state;
}


/**
 * set option to break unrelated blocks of code with empty lines.
 *
 * @param state        true = convert, false = don't convert.
 */
void ASFormatter::setBreakBlocksMode(bool state)
{
      shouldBreakBlocks = state;
}

/**
 * set option to break closing header blocks of code (such as 'else', 'catch', ...) with empty lines.
 *
 * @param state        true = convert, false = don't convert.
 */
void ASFormatter::setBreakClosingHeaderBlocksMode(bool state)
{
      shouldBreakClosingHeaderBlocks = state;
}

/**
 * jump over several characters.
 *
 * @param i       the number of characters to jump over.
 */
void ASFormatter::goForward(int i)
{
      while (--i >= 0)
            getNextChar();
}

/**
* peek at the next unread character.
*
* @return     the next unread character.
*/
char ASFormatter::peekNextChar() const
{
      char ch = ' ';
      size_t peekNum = currentLine.find_first_not_of(" \t", charNum + 1);

      if (peekNum == string::npos)
            return ch;

      ch = currentLine[peekNum];

//    if (shouldConvertTabs && ch == '\t')
//          ch = ' ';

      return ch;
}

/**
* check if current placement is before a comment or line-comment
*
* @return     is before a comment or line-comment.
*/
bool ASFormatter::isBeforeComment() const
{
      bool foundComment = false;
      size_t peekNum = currentLine.find_first_not_of(" \t", charNum + 1);

      if (peekNum == string::npos)
            return foundComment;

      foundComment = (currentLine.compare(peekNum, 2, "/*") == 0
                      || currentLine.compare(peekNum, 2, "//") == 0);

      return foundComment;
}

/**
* check if current placement is before a comment or line-comment
* if a block comment it must be at the end of the line
*
* @return     is before a comment or line-comment.
*/
bool ASFormatter::isBeforeLineEndComment(int startPos) const
{
      bool foundLineEndComment = false;
      size_t peekNum = currentLine.find_first_not_of(" \t", startPos + 1);

      if (peekNum != string::npos)
      {
            if (currentLine.compare(peekNum, 2, "//") == 0)
                  foundLineEndComment = true;
            else if (currentLine.compare(peekNum, 2, "/*") == 0)
            {
                  // comment must be closed on this line with nothing after it
                  size_t endNum = currentLine.find("*/", peekNum + 2);
                  if (endNum != string::npos)
                        if (currentLine.find_first_not_of(" \t", endNum + 2) == string::npos)
                              foundLineEndComment = true;
            }
      }
      return foundLineEndComment;
}


/**
* get the next character, increasing the current placement in the process.
* the new character is inserted into the variable currentChar.
*
* @return   whether succeded to recieve the new character.
*/
bool ASFormatter::getNextChar()
{
      isInLineBreak = false;
      previousChar = currentChar;

      if (!isWhiteSpace(currentChar))
      {
            previousNonWSChar = currentChar;
            if (!isInComment && !isInLineComment && !isInQuote
                    && !isImmediatelyPostComment
                    && !isImmediatelyPostLineComment
                    && !isSequenceReached("/*")
                    && !isSequenceReached("//"))
                  previousCommandChar = previousNonWSChar;
      }

      int currentLineLength = currentLine.length();

      if (charNum + 1 < currentLineLength
              && (!isWhiteSpace(peekNextChar()) || isInComment || isInLineComment))
      {
            currentChar = currentLine[++charNum];

            if (shouldConvertTabs && currentChar == '\t')
                  currentChar = ' ';

            return true;
      }
      else        // end of line has been reached
      {
            if (sourceIterator->hasMoreLines())
            {
                  currentLine = sourceIterator->nextLine();
                  spacePadNum = 0;
                  inLineNumber++;

                  if (currentLine.length() == 0)
                  {
                        currentLine = string(" ");        // a null is inserted if this is not done
                  }

                  // unless reading in the first line of the file,
                  // break a new line.
                  if (!isVirgin)
                        isInLineBreak = true;
                  else
                        isVirgin = false;

                  if (isInLineComment)
                        isImmediatelyPostLineComment = true;
                  isInLineComment = false;

                  // check if is in preprocessor before line trimming
                  isImmediatelyPostPreprocessor = isInPreprocessor;
                  if (previousNonWSChar != '\\')
                        isInPreprocessor = false;

                  trimNewLine();
                  currentChar = currentLine[charNum];

                  if (shouldConvertTabs && currentChar == '\t')
                        currentChar = ' ';

                  return true;
            }
            else
            {
                  endOfCodeReached = true;
                  return false;
            }
      }
}

/**
* jump over the leading white space in the current line,
* IF the line does not begin a comment or is in a preprocessor definition.
*/
void ASFormatter::trimNewLine()
{
      int len = currentLine.length();
      charNum = 0;

      if (isInComment || isInPreprocessor)
            return;

      while (isWhiteSpace(currentLine[charNum]) && charNum + 1 < len)
            ++charNum;

      doesLineStartComment = false;
      if (isSequenceReached("/*"))
      {
            charNum = 0;
            doesLineStartComment = true;
      }
}

/**
 * append a character to the current formatted line.
 * Unless disabled (via canBreakLine == false), first check if a
 * line-break has been registered, and if so break the
 * formatted line, and only then append the character into
 * the next formatted line.
 *
 * @param ch               the character to append.
 * @param canBreakLine     if true, a registered line-break
 */
void ASFormatter::appendChar(char ch, bool canBreakLine)
{
      if (canBreakLine && isInLineBreak)
            breakLine();
      formattedLine.append(1, ch);
}

/**
 * append a string sequence to the current formatted line.
 * Unless disabled (via canBreakLine == false), first check if a
 * line-break has been registered, and if so break the
 * formatted line, and only then append the sequence into
 * the next formatted line.
 *
 * @param sequence         the sequence to append.
 * @param canBreakLine     if true, a registered line-break
 */
void ASFormatter::appendSequence(const string &sequence, bool canBreakLine)
{
      if (canBreakLine && isInLineBreak)
            breakLine();
      formattedLine.append(sequence);
}

/**
 * append a space to the current formattedline, UNLESS the
 * last character is already a white-space character.
 */
void ASFormatter::appendSpacePad()
{
      int len = formattedLine.length();
      if (len > 0 && !isWhiteSpace(formattedLine[len-1]))
      {
            formattedLine.append(1, ' ');
            spacePadNum++;
      }
}

/**
 * append a space to the current formattedline, UNLESS the
 * next character is already a white-space character.
 */
void ASFormatter::appendSpaceAfter()
{
      int len = currentLine.length();
      if (charNum + 1 < len && !isWhiteSpace(currentLine[charNum+1]))
      {
            formattedLine.append(1, ' ');
            spacePadNum++;
      }
}

/**
 * register a line break for the formatted line.
 */
void ASFormatter::breakLine()
{
      isLineReady = true;
      isInLineBreak = false;
      spacePadNum = 0;
      formattedLineCommentNum = string::npos;

      // queue an empty line prepend request if one exists
      prependEmptyLine = isPrependPostBlockEmptyLineRequested;

      readyFormattedLine =  formattedLine;
      if (isAppendPostBlockEmptyLineRequested)
      {
            isAppendPostBlockEmptyLineRequested = false;
            isPrependPostBlockEmptyLineRequested = true;
      }
      else
      {
            isPrependPostBlockEmptyLineRequested = false;
      }

      formattedLine = "";
}

/**
 * check if the currently reached open-bracket (i.e. '{')
 * opens a:
 * - a definition type block (such as a class or namespace),
 * - a command block (such as a method block)
 * - a static array
 * this method takes for granted that the current character
 * is an opening bracket.
 *
 * @return    the type of the opened block.
 */
BracketType ASFormatter::getBracketType() const
{
      BracketType returnVal;

      if (foundPreDefinitionHeader)
      {
            returnVal = DEFINITION_TYPE;
            if (foundNamespaceHeader)
                  returnVal = (BracketType)(returnVal | NAMESPACE_TYPE);
            else if (foundClassHeader)
                  returnVal = (BracketType)(returnVal | CLASS_TYPE);
      }
      else
      {
            bool isCommandType = false;

            if (previousNonWSChar != '=')
                  isCommandType = (foundPreCommandHeader
                                   || (currentHeader != NULL && isNonParenHeader)
                                   || (previousCommandChar == ')')
                                   || (previousCommandChar == ':' && !foundQuestionMark)
                                   || (previousCommandChar == ';')
                                   || ((previousCommandChar == '{' ||  previousCommandChar == '}')
                                       && isPreviousBracketBlockRelated));

            returnVal = (isCommandType ? COMMAND_TYPE : ARRAY_TYPE);
      }

      if (isOneLineBlockReached())
            returnVal = (BracketType)(returnVal | SINGLE_LINE_TYPE);

      TRbracket(returnVal);
      return returnVal;
}

/**
 * check if the currently reached  '*' or '&' character is
 * a pointer-or-reference symbol, or another operator.
 * this method takes for granted that the current character
 * is either a '*' or '&'.
 *
 * @return        whether current character is a reference-or-pointer
 */
bool ASFormatter::isPointerOrReference() const
{
      bool isPR;
      isPR = (!isInPotentialCalculation
              || IS_A(bracketTypeStack->back(), DEFINITION_TYPE)
              || (!isLegalNameChar(previousNonWSChar)
                  && previousNonWSChar != ')'
                  && previousNonWSChar != ']')
             );

      if (!isPR)
      {
            char nextChar = peekNextChar();
            isPR |= (!isWhiteSpace(nextChar)
                     && nextChar != '-'
                     && nextChar != '('
                     && nextChar != '['
                     && !isLegalNameChar(nextChar));
      }

      return isPR;
}


/**
 * check if the currently reached '-' character is
 * a unary minus
 * this method takes for granted that the current character
 * is a '-'.
 *
 * @return        whether the current '-' is a unary minus.
 */
bool ASFormatter::isUnaryMinus() const
{
      return ((previousOperator == &AS_RETURN || !isalnum(previousCommandChar))
              && previousCommandChar != '.'
              && previousCommandChar != ')'
              && previousCommandChar != ']');
}


/**
 * check if the currently reached '-' or '+' character is
 * part of an exponent, i.e. 0.2E-5.
 * this method takes for granted that the current character
 * is a '-' or '+'.
 *
 * @return        whether the current '-' is in an exponent.
 */
bool ASFormatter::isInExponent() const
{
      int formattedLineLength = formattedLine.length();
      if (formattedLineLength >= 2)
      {
            char prevPrevFormattedChar = formattedLine[formattedLineLength - 2];
            char prevFormattedChar = formattedLine[formattedLineLength - 1];

            return ((prevFormattedChar == 'e' || prevFormattedChar == 'E')
                    && (prevPrevFormattedChar == '.' || isdigit(prevPrevFormattedChar)));
      }
      else
            return false;
}

/**
 * check if a one-line bracket has been reached,
 * i.e. if the currently reached '{' character is closed
 * with a complimentry '}' elsewhere on the current line,
 *.
 * @return        has a one-line bracket been reached?
 */
bool ASFormatter::isOneLineBlockReached() const
{
      bool isInComment = false;
      bool isInQuote = false;
      int bracketCount = 1;
      int currentLineLength = currentLine.length();
      char quoteChar = ' ';

      for (int i = charNum + 1; i < currentLineLength; ++i)
      {
            char ch = currentLine[i];

            if (isInComment)
            {
                  if (currentLine.compare(i, 2, "*/") == 0)
                  {
                        isInComment = false;
                        ++i;
                  }
                  continue;
            }

            if (ch == '\\')
            {
                  ++i;
                  continue;
            }

            if (isInQuote)
            {
                  if (ch == quoteChar)
                        isInQuote = false;
                  continue;
            }

            if (ch == '"' || ch == '\'')
            {
                  isInQuote = true;
                  quoteChar = ch;
                  continue;
            }

            if (currentLine.compare(i, 2, "//") == 0)
                  break;

            if (currentLine.compare(i, 2, "/*") == 0)
            {
                  isInComment = true;
                  ++i;
                  continue;
            }

            if (ch == '{')
                  ++bracketCount;
            else if (ch == '}')
                  --bracketCount;

            if (bracketCount == 0)
                  return true;
      }

      return false;
}

/**
 * check if one of a set of headers has been reached in the
 * current position of the current line.
 *
 * @return             a pointer to the found header. Or a NULL if no header has been reached.
 * @param headers      a vector of headers.
 * @param checkBoundry
 */
const string *ASFormatter::findHeader(const vector<const string*> &headers, bool checkBoundry)
{
      return ASBeautifier::findHeader(currentLine, charNum, headers, checkBoundry);
}

/**
 * check if a line begins with the specified character
 * i.e. if the current line begins with a open bracket.
 *
 * @return        true or false
 */
bool ASFormatter::lineBeginsWith(char charToCheck) const
{
      bool beginsWith = false;
      size_t i = currentLine.find_first_not_of(" \t");

      if (i != string::npos)
            if (currentLine[i] == charToCheck && (int) i == charNum)
                  beginsWith = true;

      return beginsWith;
}

/**
 * adjust comment position because of adding or deleting spaces
 * the spaces are added or deleted to formattedLine
 * spacePadNum contains the adjustment
 */
void ASFormatter::adjustComments(void)
{
      assert(spacePadNum != 0);
      assert(currentLine.compare(charNum, 2, "//") == 0
             || currentLine.compare(charNum, 2, "/*") == 0);


      // block comment must be closed on this line with nothing after it
      if (currentLine.compare(charNum, 2, "/*") == 0)
      {
            size_t endNum = currentLine.find("*/", charNum + 2);
            if (endNum == string::npos)
                  return;
            if (currentLine.find_first_not_of(" \t", endNum + 2) != string::npos)
                  return;
      }

      size_t len = formattedLine.length();
      // if spaces were removed, need to add spaces before the comment
      if (spacePadNum < 0)
      {
            int adjust = -spacePadNum;          // make the number positive
            if (formattedLine[len-1] != '\t')   // don't adjust if a tab
                  formattedLine.append(adjust, ' ');
//          else                                            // comment out to avoid compiler warning
//                adjust = 0;
//          TRcomment(adjust);                  // trace macro
      }
      // if spaces were added, need to delete spaces before the comment, if possible
      else if (spacePadNum > 0)
      {
            int adjust = spacePadNum;
            if (formattedLine.find_last_not_of(' ') < len - adjust - 1
                    && formattedLine[len-1] != '\t')    // don't adjust a tab
                  formattedLine.resize(len - adjust);
            // the following are commented out to avoid a Borland compiler warning
            //else
            //    adjust = 0;
            TRcomment(-adjust);                 // trace macro
      }
}

/**
 * append the current bracket inside the end of line comments
 * currentChar contains the bracket, it will be appended to formattedLine
 * formattedLineCommentNum is the comment location on formattedLine
 */
void ASFormatter::appendCharInsideComments(void)
{
      if (formattedLineCommentNum == string::npos           // does the comment start on the previous line?
              || isBeforeComment())                         // does a comment follow on this line?
      {
            appendCurrentChar(true);                  // don't attach
            return;
      }
      assert(formattedLine.compare(formattedLineCommentNum, 2, "//") == 0
             || formattedLine.compare(formattedLineCommentNum, 2, "/*") == 0);

      // find the previous non space char
      size_t end = formattedLineCommentNum;
      size_t beg = formattedLine.find_last_not_of(" \t", end-1);
      if (beg == string::npos)                        // is the previous line comment only?
      {
            appendCurrentChar(true);                  // don't attach
            return;
      }
      beg++;

      // insert the bracket
      if (end - beg < 3)                                    // is there room to insert?
            formattedLine.insert(beg, 3-end+beg, ' ');
      if (formattedLine[beg] == '\t')                 // don't pad with a tab
            formattedLine.insert(beg, 1, ' ');
      formattedLine[beg+1] = currentChar;
}

/**
 * add or remove space padding to operators
 * currentChar contains the paren
 * the operators and necessary padding will be appended to formattedLine
 * the calling function should have a continue statement after calling this method
 *
 * @param *newOperator     the operator to be padded
 */
void ASFormatter::padOperators(const string *newOperator)
{
      assert (shouldPadOperators);
      assert(newOperator != NULL);

      bool shouldPad = (newOperator != &AS_COLON_COLON
                        && newOperator != &AS_PAREN_PAREN
                        && newOperator != &AS_BLPAREN_BLPAREN
                        && newOperator != &AS_PLUS_PLUS
                        && newOperator != &AS_MINUS_MINUS
                        && newOperator != &AS_NOT
                        && newOperator != &AS_BIT_NOT
                        && newOperator != &AS_ARROW
                        && newOperator != &AS_OPERATOR
                        && newOperator != &AS_RETURN
                        && !(newOperator == &AS_MINUS && isInExponent())
                        && !(newOperator == &AS_MINUS             // check for negative number
                             && (previousNonWSChar == '(' 
                                 || previousNonWSChar == '=' 
                                 || previousNonWSChar == ',')) 
                      && !(newOperator == &AS_PLUS && isInExponent())
                      && previousOperator != &AS_OPERATOR
                      && !((newOperator == &AS_MULT || newOperator == &AS_BIT_AND)
                           && isPointerOrReference())
                      && !(newOperator == &AS_MULT
                           && (previousNonWSChar == '.'
                               || previousNonWSChar == '>'))      // check for ->
                      && !((isInTemplate || isCharImmediatelyPostTemplate)
                           && (newOperator == &AS_LS || newOperator == &AS_GR))
                     );
      // pad before operator
      if (shouldPad
              && !isInBlParen
              && !(newOperator == &AS_COLON && !foundQuestionMark)
              && newOperator != &AS_SEMICOLON
              && newOperator != &AS_COMMA)
            appendSpacePad();
      appendSequence(*newOperator);
      goForward(newOperator->length() - 1);

      // since this block handles '()' and '[]',
      // the parenStack must be updated here accordingly!
      if (newOperator == &AS_PAREN_PAREN
              || newOperator == &AS_BLPAREN_BLPAREN)
            parenStack->back()--;

      currentChar = (*newOperator)[newOperator->length() - 1];
      // pad after operator
      // but do not pad after a '-' that is a unary-minus.
      if (shouldPad
              && !isInBlParen
              && !isBeforeComment()
              && !(newOperator == &AS_MINUS && isUnaryMinus())
              && !(currentLine.compare(charNum + 1, 1,  ";") == 0)
              && !(currentLine.compare(charNum + 1, 2, "::") == 0))
            appendSpaceAfter();

      previousOperator = newOperator;
      return;
}

/**
 * add or remove space padding to parens
 * currentChar contains the paren
 * the parens and necessary padding will be appended to formattedLine
 * the calling function should have a continue statement after calling this method
 */
void ASFormatter::padParens(void)
{
      assert(shouldPadParensOutside || shouldPadParensInside || shouldUnPadParens);
      assert (currentChar == '(' || currentChar == ')');

      if (currentChar == '(')
      {
            int spacesOutsideToDelete = formattedLine.length() - 1;
            int spacesInsideToDelete = 0;

            // compute spaces outside the opening paren to delete
            if (shouldUnPadParens)
            {
                  char lastChar = ' ';
                  bool prevIsParenHeader = false;
                  size_t i = formattedLine.find_last_not_of(" \t");
                  if (i != string::npos)
                  {
                        size_t end = i;
                        spacesOutsideToDelete -= i;
                        lastChar = formattedLine[i];
                        // was last word a paren header?
                        int start;          // start of the previous word
                        for (start = i; start > 0; start--)
                        {
                              if (isLegalNameChar(formattedLine[start]) || formattedLine[start] == '*')
                                    continue;
                              start++;
                              break;
                        }
                        string prevWord = formattedLine.substr(start, end-start+1);
                        // if previous word is a header, it will be a paren header
                        const string *prevWordH = ASBeautifier::findHeader(formattedLine, start, headers);
                        if (prevWordH != NULL)
                        {
                              prevIsParenHeader = true;
                              TRxtra(*prevWordH);         // trace macro
                        }
                        else if (prevWord == "return"       // don't unpad return statements
                                 || prevWord == "*")     // don't unpad multiply or pointer
                        {
                              prevIsParenHeader = true;
                              TRxtra(prevWord);           // trace macro
                        }
                        // don't unpad variables
                        else if (prevWord == "bool"
                                 || prevWord ==  "int"
                                 || prevWord ==  "void"
                                 || prevWord ==  "void*"
                                 || (prevWord.length() >= 6     // check end of word for _t
                                     && prevWord.compare(prevWord.length()-2, 2, "_t") == 0)
                                 || prevWord ==  "BOOL"
                                 || prevWord ==  "DWORD"
                                 || prevWord ==  "HWND"
                                 || prevWord ==  "INT"
                                 || prevWord ==  "LPSTR"
                                 || prevWord ==  "VOID"
                                 || prevWord ==  "LPVOID"
                                )
                        {
                              prevIsParenHeader = true;
                              TRxtra(prevWord);           // trace macro
                        }
                  }
                  // do not unpad operators, but leave them if already padded
                  if (shouldPadParensOutside || prevIsParenHeader)
                        spacesOutsideToDelete--;
                  else if (lastChar == '|'          // check for ||
                           || lastChar == '&'      // check for &&
                           || lastChar == ','
                           || (lastChar == '>' && !foundCastOperator)
                           || lastChar == '<'
                           || lastChar == '?'
                           || lastChar == ':'
                           || lastChar == ';'
                           || lastChar == '='
                           || lastChar == '+'
                           || lastChar == '-'
                           || (lastChar == '*' && isInPotentialCalculation)
                           || lastChar == '/'
                           || lastChar == '%')
                        spacesOutsideToDelete--;

                  if (spacesOutsideToDelete > 0)
                  {
                        formattedLine.erase(i + 1, spacesOutsideToDelete);
                        spacePadNum -= spacesOutsideToDelete;
                  }
            }

            // pad open paren outside
            char peekedCharOutside = peekNextChar();
            if (shouldPadParensOutside)
                  if (!(currentChar == '(' && peekedCharOutside == ')'))
                        appendSpacePad();

            appendCurrentChar();

            // unpad open paren inside
            if (shouldUnPadParens)
            {
                  size_t j = currentLine.find_first_not_of(" \t", charNum + 1);
                  if (j != string::npos)
                        spacesInsideToDelete = j - charNum - 1;
                  if (shouldPadParensInside)
                        spacesInsideToDelete--;
                  if (spacesInsideToDelete > 0)
                  {
                        currentLine.erase(charNum + 1, spacesInsideToDelete);
                        spacePadNum -= spacesInsideToDelete;
                  }
            }

            // pad open paren inside
            char peekedCharInside = peekNextChar();
            if (shouldPadParensInside)
                  if (!(currentChar == '(' && peekedCharInside == ')'))
                        appendSpaceAfter();

            TRunpad('(', spacesOutsideToDelete, spacesInsideToDelete);       // trace macro
      }
      else if (currentChar == ')' /*|| currentChar == ']'*/)
      {
            int spacesOutsideToDelete = 0;
            int spacesInsideToDelete = formattedLine.length();

            // unpad close paren inside
            if (shouldUnPadParens)
            {
                  size_t i = formattedLine.find_last_not_of(" \t");
                  if (i != string::npos)
                        spacesInsideToDelete = formattedLine.length() - 1 - i;
                  if (shouldPadParensInside)
                        spacesInsideToDelete--;
                  if (spacesInsideToDelete > 0)
                  {
                        formattedLine.erase(i + 1, spacesInsideToDelete);
                        spacePadNum -= spacesInsideToDelete;
                  }
            }

            // pad close paren inside
            if (shouldPadParensInside)
                  if (!(previousChar == '(' && currentChar == ')'))
                        appendSpacePad();

            appendCurrentChar();

            // unpad close paren outside
            if (shouldUnPadParens)
            {
                  // may have end of line comments
                  size_t j = currentLine.find_first_not_of(" \t", charNum + 1);
                  if (j != string::npos)
                        if (currentLine[j] == '[' || currentLine[j] == ']')
                              spacesOutsideToDelete = j - charNum - 1;
                  if (shouldPadParensOutside)
                        spacesOutsideToDelete--;
//                    spacesOutsideToDelete--;            // always leave 1 space

                  if (spacesOutsideToDelete > 0)
                  {
                        currentLine.erase(charNum + 1, spacesOutsideToDelete);
                        spacePadNum -= spacesOutsideToDelete;
                  }
            }

            // pad close paren outside
            char peekedCharOutside = peekNextChar();
            if (shouldPadParensOutside)
                  if (peekedCharOutside != ';'
                          && peekedCharOutside != ','
                          && peekedCharOutside != '.'
                          && peekedCharOutside != '-')    // check for ->
//                            && !(currentChar == ']' && peekedCharOutside == '['))
                        appendSpaceAfter();

            TRunpad(')', spacesInsideToDelete, 0 /*spacesOutsideToDelete*/);       // trace macro
      }
      return;
}

/**
 * format brackets as attached or broken
 * currentChar contains the bracket
 * the brackets will be appended to the current formattedLine or a new formattedLine as necessary
 * the calling function should have a continue statement after calling this method
 *
 * @param bracketType    the type of bracket to be formatted.
 */
void ASFormatter::formatBrackets(BracketType bracketType)
{
      assert(!IS_A(bracketType, ARRAY_TYPE));
      assert (currentChar == '{' || currentChar == '}');

      if (currentChar == '{')
      {
            parenStack->push_back(0);
      }
      else if (currentChar == '}')
      {
            if (!parenStack->empty())
            {
                  parenStack->pop_back();
            }
      }

      if (currentChar == '{')
      {
            bool bdacBreak = false;
            // should a Linux bracket be broken?
            if (bracketFormatMode == BDAC_MODE)
            {
                  // always break a class
                  if (IS_A((*bracketTypeStack)[bracketTypeStack->size()-1], CLASS_TYPE))
                        bdacBreak = true;
                  // break a namespace and the first bracket if a function
                  else if (bracketTypeStack->size() <= 2)
                  {
                        if (IS_A((*bracketTypeStack)[bracketTypeStack->size()-1], NAMESPACE_TYPE)
                                || IS_A((*bracketTypeStack)[bracketTypeStack->size()-1], COMMAND_TYPE))
                              bdacBreak = true;
                  }
                  // break the first bracket after a namespace if a function
                  else if (IS_A((*bracketTypeStack)[bracketTypeStack->size()-2], NAMESPACE_TYPE))
                  {
                        if (IS_A((*bracketTypeStack)[bracketTypeStack->size()-1], COMMAND_TYPE))
                              bdacBreak = true;
                  }
                  // if not C style then break the first bracket after a class if a function
                  else if (!ASBeautifier::isCStyle)
                  {
                        if (IS_A((*bracketTypeStack)[bracketTypeStack->size()-2], CLASS_TYPE)
                                && IS_A((*bracketTypeStack)[bracketTypeStack->size()-1], COMMAND_TYPE))
                              bdacBreak = true;
                  }
            }
            if (bracketFormatMode == ATTACH_MODE
                    || (bracketFormatMode == BDAC_MODE && !bdacBreak))
            {
                  // are there comments before the bracket?
                  if (isCharImmediatelyPostComment || isCharImmediatelyPostLineComment)
                  {
                        if ((shouldBreakOneLineBlocks || !IS_A(bracketType,  SINGLE_LINE_TYPE))
                                && peekNextChar() != '}')
                              appendCharInsideComments();
                        else
                              appendCurrentChar(true);            // don't attach
                  }
                  else if (previousCommandChar == '{'
                           || previousCommandChar == '}'
                           || previousCommandChar == ';')  // '}' , ';' chars added for proper handling of '{' immediately after a '}' or ';'
                  {
                        appendCurrentChar(true);                  // don't attach
                  }
                  else
                  {
                        size_t firstChar = formattedLine.find_first_not_of(" \t");
                        if (firstChar == string::npos)            // if a blank line preceeds this
                              appendCurrentChar(true);            // don't attach
                        else if (shouldBreakOneLineBlocks
                                 || !IS_A(bracketType,  SINGLE_LINE_TYPE)
                                 || peekNextChar() == '}')
                        {
                              appendSpacePad();
                              appendCurrentChar(false);           // OK to attach
                        }
                        else
                              appendCurrentChar(true);            // don't attach
                  }
            }
            else if (bracketFormatMode == BREAK_MODE
                     || (bracketFormatMode == BDAC_MODE && bdacBreak))
            {
                  if (isBeforeComment())
                  {
                        // do not break unless comment is at line end
                        if (isBeforeLineEndComment(charNum))
                        {
                              currentChar = ' ';                        // remove bracket from current line
                              appendOpeningBracket = true;  // append bracket to following line
                        }
                  }
                  else if (!IS_A(bracketType,  SINGLE_LINE_TYPE))
                        breakLine();
                  else if (shouldBreakOneLineBlocks && peekNextChar() != '}')
                        breakLine();

                  appendCurrentChar();
            }
            else if (bracketFormatMode == NONE_MODE)
            {
                  if (lineBeginsWith('{'))                // is opening bracket broken?
                        appendCurrentChar(true);
                  else
                        appendCurrentChar(false);
            }
      }
      else if (currentChar == '}')
      {
            // mark state of immediately after empty block
            // this state will be used for locating brackets that appear immedately AFTER an empty block (e.g. '{} \n}').
            if (previousCommandChar == '{')
                  isImmediatelyPostEmptyBlock = true;

            if ((!(previousCommandChar == '{' && isPreviousBracketBlockRelated))            // this '{' does not close an empty block
                    && (shouldBreakOneLineBlocks || !IS_A(bracketType,  SINGLE_LINE_TYPE))  // astyle is allowed to break on line blocks
                    && (!(bracketFormatMode == NONE_MODE && IS_A(bracketType,  SINGLE_LINE_TYPE)))
                    && !isImmediatelyPostEmptyBlock)                                        // this '}' does not immediately follow an empty block
            {
                  breakLine();
                  appendCurrentChar();
            }
            else
            {
                  if (!isCharImmediatelyPostComment
                          && !bracketFormatMode == NONE_MODE
                          && !isImmediatelyPostEmptyBlock)
                        isInLineBreak = false;

                  appendCurrentChar();

                  //if (!bracketFormatMode == NONE_MODE)
                  //    if ((shouldBreakOneLineBlocks || !IS_A(bracketType,  SINGLE_LINE_TYPE))
                  //            && !(currentChar == '}' && peekNextChar() == ';'))      // fixes }; placed on separate lines
                  //          shouldBreakLineAfterComments = true;
            }

            if (shouldBreakBlocks)
            {
                  isAppendPostBlockEmptyLineRequested = true;
            }
      }
      return;
}

/**
 * format array brackets as attached or broken
 * determine if the brackets can have an inStatement indent
 * currentChar contains the bracket
 * the brackets will be appended to the current formattedLine or a new formattedLine as necessary
 * the calling function should have a continue statement after calling this method
 *
 * @param bracketType            the type of bracket to be formatted, must be an ARRAY_TYPE.
 * @param isOpeningArrayBracket  indicates if this is the opening bracket for the array block.
 */
void ASFormatter::formatArrayBrackets(BracketType bracketType, bool isOpeningArrayBracket)
{
      assert(IS_A(bracketType, ARRAY_TYPE));
      assert (currentChar == '{' || currentChar == '}');

      if (currentChar == '{')
      {
            // is this the first opening bracket in the array?
            if (isOpeningArrayBracket)
            {
                  if (bracketFormatMode == ATTACH_MODE || bracketFormatMode == BDAC_MODE)
                  {
                        // don't attach to a preprocessor directive
                        if (isImmediatelyPostPreprocessor)
                              appendCurrentChar(true);                  // don't attach
                        // are there comments before the bracket?
                        else if (isCharImmediatelyPostComment || isCharImmediatelyPostLineComment)
                        {
                              appendCharInsideComments();
                        }
                        else
                        {
                              // if bracket is broken or not an assignment
                              if (lineBeginsWith('{') || previousNonWSChar != '=')
                                    appendSpacePad();
                              appendCurrentChar(false);                 // OK to attach
                        }
                  }
                  else if (bracketFormatMode == BREAK_MODE)
                  {
                        if (isWhiteSpace(peekNextChar()))
                              breakLine();
                        else if (isBeforeComment())
                        {
                              // do not break unless comment is at line end
                              if (isBeforeLineEndComment(charNum))
                              {
                                    currentChar = ' ';                        // remove bracket from current line
                                    appendOpeningBracket = true;  // append bracket to following line
                              }
                        }
                        appendCurrentChar();
                  }
                  else if (bracketFormatMode == NONE_MODE)
                  {
                        if (lineBeginsWith('{'))                // is opening bracket broken?
                              appendCurrentChar();
                        else
                              appendCurrentChar(false);
                  }
            }
            else
                  appendCurrentChar();     // not the first opening bracket - don't change

            // if an opening bracket ends the line there will be no inStatement indent
            char nextChar = peekNextChar();
            if (isWhiteSpace(nextChar)
                    || isBeforeLineEndComment(charNum)
                    || nextChar == '{')
                  isNonInStatementArray = true;
            if (isNonInStatementArray)
                  TRarray('x');
            else
                  TRarray(' ');

      }
      else if (currentChar == '}')
      {
            // does this close the first opening bracket in the array?
            if (isOpeningArrayBracket && !IS_A(bracketType, SINGLE_LINE_TYPE) )
            {
                  breakLine();
                  appendCurrentChar();
            }
            else
                  appendCurrentChar();
      }
}


}   // end namespace astyle

Generated by  Doxygen 1.6.0   Back to index