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

ASBeautifier.cpp

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *
 *   Copyright (C) 2006-2009 by Jim Pattee <jimp03@email.com>
 *   Copyright (C) 1998-2002 by Tal Davidson
 *   <http://www.gnu.org/licenses/lgpl-3.0.html>
 *
 *   This file is a part of Artistic Style - an indentation and
 *   reformatting tool for C, C++, C# and Java source files.
 *   <http://astyle.sourceforge.net>
 *
 *   Artistic Style is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU Lesser General Public License as published
 *   by the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   Artistic Style is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU Lesser General Public License for more details.
 *
 *   You should have received a copy of the GNU Lesser General Public License
 *   along with Artistic Style.  If not, see <http://www.gnu.org/licenses/>.
 *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 */

#include "astyle.h"

#include <algorithm>
#include <iostream>


namespace astyle
{
// static member variables
int ASBeautifier::beautifierFileType = 9;       // initialized with an invalid type
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;
vector<const string*> ASBeautifier::indentableHeaders;


/*
 * initialize the static vars
 */
void ASBeautifier::initStatic()
{
      if (fileType == beautifierFileType)    // don't build unless necessary
            return;

      beautifierFileType = fileType;

      headers.clear();
      nonParenHeaders.clear();
      assignmentOperators.clear();
      nonAssignmentOperators.clear();
      preBlockStatements.clear();
      indentableHeaders.clear();

      ASResource::buildHeaders(headers, fileType, true);
      ASResource::buildNonParenHeaders(nonParenHeaders, fileType, true);
      ASResource::buildAssignmentOperators(assignmentOperators);
      ASResource::buildNonAssignmentOperators(nonAssignmentOperators);
      ASResource::buildPreBlockStatements(preBlockStatements, fileType);
      ASResource::buildIndentableHeaders(indentableHeaders);
}

/**
 * ASBeautifier's constructor
 */
00073 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);
      classInitializerTabs = 1;
      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
 * must explicitly call the base class copy constructor
 */
00114 ASBeautifier::ASBeautifier(const ASBeautifier &other) : ASBase(other)
{
      // these don't need to copy the stack
      waitingBeautifierStack = NULL;
      activeBeautifierStack = NULL;
      waitingBeautifierStackLengthStack = NULL;
      activeBeautifierStackLengthStack = NULL;

      // vector '=' operator performs a DEEP copy of all elements in the vector

      headerStack  = new vector<const string*>;
      *headerStack = *other.headerStack;

      tempStacks = 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
      // variables set by ASFormatter
      // must also be updated in activeBeautifierStack
      inLineNumber = other.inLineNumber;
      horstmannIndentInStatement = other.horstmannIndentInStatement;
      nonInStatementBracket = other.nonInStatementBracket;
      lineCommentNoBeautify = other.lineCommentNoBeautify;
      isNonInStatementArray = other.isNonInStatementArray;
      isSharpAccessor = other.isSharpAccessor;
      isSharpDelegate = other.isSharpDelegate;
      isInExtern = other.isInExtern;
      isInEnum = other.isInEnum;

      // private variables
      indentString = other.indentString;
      currentHeader = other.currentHeader;
      previousLastLineHeader = other.previousLastLineHeader;
      probationHeader = other.probationHeader;
      isInQuote = other.isInQuote;
      isInVerbatimQuote = other.isInVerbatimQuote;
      haveLineContinuationChar = other.haveLineContinuationChar;
      isInComment = other.isInComment;
      isInCase = other.isInCase;
      isInQuestion = other.isInQuestion;
      isInStatement = other.isInStatement;
      isInHeader = other.isInHeader;
      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;
      lineOpensComment = other.lineOpensComment;
      backslashEndsPrevLine = other.backslashEndsPrevLine;
      blockCommentNoIndent = other.blockCommentNoIndent;
      blockCommentNoBeautify = other.blockCommentNoBeautify;
      previousLineProbationTab = other.previousLineProbationTab;
      fileType = other.fileType;
      minConditionalIndent = other.minConditionalIndent;
      parenDepth = other.parenDepth;
      indentLength = other.indentLength;
      blockTabCount = other.blockTabCount;
      maxInStatementIndent = other.maxInStatementIndent;
      classInitializerTabs = other.classInitializerTabs;
      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
 */
00229 ASBeautifier::~ASBeautifier()
{
      deleteContainer(waitingBeautifierStack);
      deleteContainer(activeBeautifierStack);
      deleteContainer(waitingBeautifierStackLengthStack);
      deleteContainer(activeBeautifierStackLengthStack);
      deleteContainer(headerStack);
      deleteContainer(tempStacks);
      deleteContainer(blockParenDepthStack);
      deleteContainer(blockStatementStack);
      deleteContainer(parenStatementStack);
      deleteContainer(bracketBlockStateStack);
      deleteContainer(inStatementIndentStack);
      deleteContainer(inStatementIndentStackSizeStack);
      deleteContainer(parenIndentStack);
}

/**
 * initialize the ASBeautifier.
 *
 * init() should be called every time a ABeautifier object is to start
 * beautifying a NEW source file.
 * init() recieves a pointer to a 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.
 */
00258 void ASBeautifier::init(ASSourceIterator *iter)
{
      sourceIterator = iter;
      init();
}

/**
 * initialize the ASBeautifier.
 */
00267 void ASBeautifier::init()
{
      initStatic();
      ASBase::init(getFileType());

      initContainer(waitingBeautifierStack, new vector<ASBeautifier*>);
      initContainer(activeBeautifierStack, new vector<ASBeautifier*>);

      initContainer(waitingBeautifierStackLengthStack, new vector<int>);
      initContainer(activeBeautifierStackLengthStack, new vector<int>);

      initContainer(headerStack,  new vector<const string*>);

      initContainer(tempStacks, new vector<vector<const string*>*>);
      tempStacks->push_back(new vector<const string*>);

      initContainer(blockParenDepthStack, new vector<int>);
      initContainer(blockStatementStack, new vector<bool>);
      initContainer(parenStatementStack, new vector<bool>);

      initContainer(bracketBlockStateStack, new vector<bool>);
      bracketBlockStateStack->push_back(true);

      initContainer(inStatementIndentStack, new vector<int>);
      initContainer(inStatementIndentStackSizeStack, new vector<int>);
      inStatementIndentStackSizeStack->push_back(0);
      initContainer(parenIndentStack, new vector<int>);

      previousLastLineHeader = NULL;
      currentHeader = NULL;

      isInQuote = false;
      isInVerbatimQuote = false;
      haveLineContinuationChar = false;
      isInComment = false;
      isInStatement = false;
      isInCase = false;
      isInQuestion = false;
      isInClassHeader = false;
      isInClassHeaderTab = false;
      isInHeader = false;
      isInTemplate = false;
      isInConditional = false;
      templateDepth = 0;
      parenDepth = 0;
      blockTabCount = 0;
      prevNonSpaceCh = '{';
      currentNonSpaceCh = '{';
      prevNonLegalCh = '{';
      currentNonLegalCh = '{';
      quoteChar = ' ';
      prevFinalLineSpaceTabCount = 0;
      prevFinalLineTabCount = 0;
      probationHeader = NULL;
      backslashEndsPrevLine = false;
      lineOpensComment = false;
      isInDefine = false;
      isInDefineDefinition = false;
      defineTabCount = 0;
      lineCommentNoBeautify = false;
      blockCommentNoIndent = false;
      blockCommentNoBeautify = false;
      previousLineProbationTab = false;
      isNonInStatementArray = false;
      isSharpAccessor = false;
      isSharpDelegate = false;
      isInExtern = false;
      isInEnum = false;
      inLineNumber = 0;
      horstmannIndentInStatement = 0;
      nonInStatementBracket = 0;
}

/**
 * set indentation style to C/C++.
 */
00343 void ASBeautifier::setCStyle()
{
      fileType = C_TYPE;
}

/**
 * set indentation style to Java.
 */
00351 void ASBeautifier::setJavaStyle()
{
      fileType = JAVA_TYPE;
}

/**
 * set indentation style to C#.
 */
00359 void ASBeautifier::setSharpStyle()
{
      fileType = SHARP_TYPE;
}

/**
 * indent using one tab per indentation
 */
00367 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.
 */
00382 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.
 */
00396 void ASBeautifier::setMaxInStatementIndentLength(int max)
{
      maxInStatementIndent = max;
}

/**
 * set the minimum indentation between two lines in a multi-line condition.
 *
 * @param   min     minimal indentation length.
 */
00406 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.
 */
00418 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.
 */
00429 void ASBeautifier::setBlockIndent(bool state)
{
      blockIndent = state;
}

/**
 * set the state of the class indentation option. If true, C++ class
 * definitions will be indented one additional indent.
 *
 * @param   state             state of option.
 */
00440 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.
 */
00451 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.
 */
00462 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.
 */
00474 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.
 */
00488 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.
 */
00499 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.
 */
00512 void ASBeautifier::setEmptyLineFill(bool state)
{
      emptyLineFill = state;
}

/**
 * get the file type.
 */
00520 int ASBeautifier::getFileType()
{
      return fileType;
}

/**
 * get the number of spaces per indent
 *
 * @return   value of indentLength option.
 */
00530 int ASBeautifier::getIndentLength(void)
{
      return indentLength;
}

/**
 * get the char used for indentation, space or tab
 *
 * @return   the char used for indentation.
 */
00540 string ASBeautifier::getIndentString(void)
{
      return indentString;
}

/**
 * get the state of the force tab indentation option.
 *
 * @return   state of force tab indentation.
 */
00550 bool ASBeautifier::getForceTabIndentation(void)
{
      return shouldForceTabIndentation;
}

/**
 * get the state of the block indentation option.
 *
 * @return   state of blockIndent option.
 */
00560 bool ASBeautifier::getBlockIndent(void)
{
      return blockIndent;
}

/**
 * get the state of the bracket indentation option.
 *
 * @return   state of bracketIndent option.
 */
00570 bool ASBeautifier::getBracketIndent(void)
{
      return bracketIndent;
}

/**
 * get the state of the class indentation option. If true, blocks of
 * the 'class' statement will be indented one additional indent.
 *
 * @return   state of classIndent option.
 */
00581 bool ASBeautifier::getClassIndent(void)
{
      return classIndent;
}

/**
 * get the state of the switch indentation option. If true, blocks of
 * the 'switch' statement will be indented one additional indent.
 *
 * @return   state of switchIndent option.
 */
00592 bool ASBeautifier::getSwitchIndent(void)
{
      return switchIndent;
}

/**
 * get the state of the case indentation option. If true, lines of 'case'
 * statements will be indented one additional indent.
 *
 * @return   state of caseIndent option.
 */
00603 bool ASBeautifier::getCaseIndent(void)
{
      return caseIndent;
}

/**
 * get the state of the empty line fill option.
 * If true, empty lines will be filled with the whitespace.
 * of their previous lines.
 * If false, these lines will remain empty.
 *
 * @return   state of emptyLineFill option.
 */
00616 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?
 */
00626 bool ASBeautifier::hasMoreLines() const
{
      return sourceIterator->hasMoreLines();
}

/**
 * get the next indented line.
 *
 * @return    indented line.
 */
00636 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.
 */
00649 string ASBeautifier::beautify(const string &originalLine)
{
      string line;
      bool isInLineComment = false;
      bool lineStartsInComment = false;
      bool isInClass = false;
      bool isInSwitch = false;
      bool isInOperator = false;
      bool isSpecialChar = false;
      bool haveCaseIndent = false;
      bool lineBeginsWithBracket = false;
      bool closingBracketReached = false;
      bool shouldIndentBrackettedLine = true;
      bool previousLineProbation = (probationHeader != NULL);
      bool isInQuoteContinuation = isInVerbatimQuote | haveLineContinuationChar;
      char ch = ' ';
      char prevCh;
      char tempCh;
      int tabCount = 0;
      int spaceTabCount = 0;
      int lineOpeningBlocksNum = 0;
      int lineClosingBlocksNum = 0;
      int tabIncrementIn = 0;
      int i;
      int iPrelim;
      string outBuffer; // the newly idented line is buffered here
      const string *lastLineHeader = NULL;

      currentHeader = NULL;
      lineStartsInComment = isInComment;
      blockCommentNoBeautify = blockCommentNoIndent;
      lineOpensComment = false;
      previousLineProbationTab = false;
      haveLineContinuationChar = false;

      // handle and remove white spaces around the line:
      // If not in comment, first find out size of white space before line,
      // so that possible comments starting in the line continue in
      // relation to the preliminary white-space.
      if (isInQuoteContinuation)
      {
            // trim a single space added by ASFormatter, otherwise leave it alone
            if (!(originalLine.length() == 1 && originalLine[0] == ' '))
                  line = originalLine;
      }
      else if (!isInComment)
      {
            line = trim(originalLine);
            if (line.length() > 0 && line[0] == '{')
                  lineBeginsWithBracket = true;

            size_t j = line.find_first_not_of(" \t{");
            if (j != string::npos && line.compare(j, 2, "/*") == 0)
                  lineOpensComment = true;
      }
      else
      {
            // trim the end of comment lines
            line = originalLine;
            size_t trimEnd = line.find_last_not_of(" \t");
            if (trimEnd == string::npos)
                  trimEnd = 0;
            else
                  trimEnd++;
            if (trimEnd < line.length())
                  line.erase(trimEnd);
      }

      if (line.length() == 0)
      {
            if (backslashEndsPrevLine)  // must continue to clear variables
                  line = ' ';
            else if (emptyLineFill && !isInQuoteContinuation && headerStack->size() > 0)
                  return preLineWS(prevFinalLineSpaceTabCount, prevFinalLineTabCount);
            else
                  return line;
      }

      // handle preprocessor commands
      // except C# region and endregion

      if (!isInComment
              && (line[0] == '#' || backslashEndsPrevLine)
              && line.compare(0, 7, "#region") != 0
              && line.compare(0, 10, "#endregion") != 0)
      {
            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()->horstmannIndentInStatement = horstmannIndentInStatement;
            activeBeautifierStack->back()->nonInStatementBracket = nonInStatementBracket;
            activeBeautifierStack->back()->lineCommentNoBeautify = lineCommentNoBeautify;
            activeBeautifierStack->back()->isNonInStatementArray = isNonInStatementArray;
            activeBeautifierStack->back()->isSharpAccessor = isSharpAccessor;
            activeBeautifierStack->back()->isSharpDelegate = isSharpDelegate;
            // must return originalLine not the trimmed line
            return activeBeautifierStack->back()->beautify(originalLine);
      }

      // calculate preliminary indentation based on data from past lines
      if (!inStatementIndentStack->empty())
            spaceTabCount = inStatementIndentStack->back();

      for (i = 0; i < (int) headerStack->size(); i++)
      {
            isInClass = false;

            if (blockIndent)
            {
                  // do NOT indent opening block for these headers
                  if (!((*headerStack)[i] == &AS_NAMESPACE
                          || (*headerStack)[i] == &AS_CLASS
                          || (*headerStack)[i] == &AS_STRUCT
                          || (*headerStack)[i] == &AS_UNION
                          || (*headerStack)[i] == &AS_CONST
                          || (*headerStack)[i] == &AS_INTERFACE
                          || (*headerStack)[i] == &AS_THROWS
                          || (*headerStack)[i] == &AS_STATIC))
                        ++tabCount;
            }
            else if (!(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;
            }

      }

      iPrelim = i;

      if (!lineStartsInComment
              && isCStyle()
              && isInClass
              && classIndent
              && headerStack->size() >= 2
              && (*headerStack)[headerStack->size()-2] == &AS_CLASS
              && (*headerStack)[headerStack->size()-1] == &AS_OPEN_BRACKET
              && line[0] == '}'
              && bracketBlockStateStack->back() == true)
            --tabCount;

      else if (!lineStartsInComment
               && isInSwitch
               && switchIndent
               && headerStack->size() >= 2
               && (*headerStack)[headerStack->size()-2] == &AS_SWITCH
               && (*headerStack)[headerStack->size()-1] == &AS_OPEN_BRACKET
               && line[0] == '}')
            --tabCount;

      if (isInClassHeader)
      {
            if (lineStartsInComment || lineOpensComment)
            {
                  if (!lineBeginsWithBracket)
                        tabCount--;
            }
            else if (isCStyle() && !isClassAccessModifier(line))
            {
                  isInClassHeaderTab = true;
                  tabCount += classInitializerTabs;
            }
            else if (blockIndent)
            {
                  if (!lineBeginsWithBracket)
                        tabCount++;
            }
      }

      if (isInConditional)
      {
            --tabCount;
      }


      // parse characters in the current line.

      for (i = 0; i < (int) line.length(); i++)
      {
            outBuffer.append(1, line[i]);

            tempCh = line[i];
            prevCh = ch;
            ch = tempCh;

            if (isWhiteSpace(ch))
            {
                  if (ch == '\t')
                        tabIncrementIn += convertTabToSpaces(i, tabIncrementIn);
                  continue;
            }

            // handle special characters (i.e. backslash+character such as \n, \t, ...)

            if (isInQuote && !isInVerbatimQuote)
            {
                  if (isSpecialChar)
                  {
                        isSpecialChar = false;
                        continue;
                  }
                  if (line.compare(i, 2, "\\\\") == 0)
                  {
                        outBuffer.append(1, '\\');
                        i++;
                        continue;
                  }
                  if (ch == '\\')
                  {
                        if (peekNextChar(line, i) == ' ')   // is this '\' at end of line
                              haveLineContinuationChar = true;
                        else
                              isSpecialChar = true;
                        continue;
                  }
            }
            else if (isInDefine && ch == '\\')
                  continue;

            // handle quotes (such as 'x' and "Hello Dolly")
            if (!(isInComment || isInLineComment) && (ch == '"' || ch == '\''))
            {
                  if (!isInQuote)
                  {
                        quoteChar = ch;
                        isInQuote = true;
                        if (isSharpStyle() && prevCh == '@')
                              isInVerbatimQuote = true;
                  }
                  else if (isInVerbatimQuote && ch == '"')
                  {
                        if (peekNextChar(line, i) == '"')           // check consecutive quotes
                        {
                              outBuffer.append(1, '"');
                              i++;
                        }
                        else
                        {
                              isInQuote = false;
                              isInVerbatimQuote = false;
                        }
                  }
                  else if (quoteChar == ch)
                  {
                        isInQuote = false;
                        isInStatement = true;
                        continue;
                  }
            }
            if (isInQuote)
                  continue;

            // handle comments

            if (!(isInComment || isInLineComment) && line.compare(i, 2, "//") == 0)
            {
                  isInLineComment = true;
                  outBuffer.append(1, '/');
                  i++;
                  continue;
            }
            else if (!(isInComment || isInLineComment) && line.compare(i, 2, "/*") == 0)
            {
                  isInComment = true;
                  outBuffer.append(1, '*');
                  i++;
                  if (!lineOpensComment)                          // does line start with comment?
                        blockCommentNoIndent = true;        // if no, cannot indent continuation lines
                  continue;
            }
            else if ((isInComment || isInLineComment) && line.compare(i, 2, "*/") == 0)
            {
                  isInComment = false;
                  outBuffer.append(1, '/');
                  i++;
                  blockCommentNoIndent = false;           // ok to indent next comment
                  continue;
            }
            // treat C# '#region' and '#endregion' statements as a line comment
            else if (isSharpStyle() &&
                     (line.compare(i, 7, "#region") == 0 || line.compare(i, 10, "#endregion") == 0))
            {
                  isInLineComment = true;
//                continue;
            }

            if (isInComment || isInLineComment)
            {
                  // append rest of the comment up to the comment end
                  while (i+1 < (int) line.length()
                          && line.compare(i+1, 2, "*/") != 0)
                        outBuffer.append(1, line[++i]);
                  continue;
            }

            // if we have reached this far then we are NOT in a comment or string of special character...

            if (probationHeader != NULL)
            {
                  if (((probationHeader == &AS_STATIC || 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);

                        isInStatement = false;
                        // if the probation comes from the previous line, then indent by 1 tab count.
                        if (previousLineProbation
                                && ch == '{'
                                && !(blockIndent
                                     && (probationHeader == &AS_CONST || probationHeader == &AS_STATIC)))
                        {
                              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 == '>')
                    &&  findOperator(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 == '[')
                  {
                        isInOperator = false;
                        // if have a struct header, this is a declaration not a definition
                        if (ch == '('
                                && (isInClassHeader || isInClassHeaderTab)
                                && headerStack->size() > 0
                                && headerStack->back() == &AS_STRUCT)
                        {
                              headerStack->pop_back();
                              isInClassHeader = false;
                              // -1 for isInClassHeader, -2 for isInClassHeaderTab
                              if (isInClassHeaderTab)
                              {
                                    tabCount -= (1 + classInitializerTabs);
                                    isInClassHeaderTab = false;
                              }
                              if (tabCount < 0)
                                    tabCount = 0;
                        }

                        if (parenDepth == 0)
                        {
                              parenStatementStack->push_back(isInStatement);
                              isInStatement = true;
                        }
                        parenDepth++;

                        inStatementIndentStackSizeStack->push_back(inStatementIndentStack->size());

                        if (currentHeader != NULL)
                              registerInStatementIndent(line, i, spaceTabCount, tabIncrementIn, minConditionalIndent/*indentLength*2*/, true);
                        else
                              registerInStatementIndent(line, i, spaceTabCount, tabIncrementIn, 0, true);
                  }
                  else if (ch == ')' || ch == ']')
                  {
                        parenDepth--;
                        if (parenDepth == 0)
                        {
                              if (!parenStatementStack->empty())      // in case of unmatched closing parens
                              {
                                    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 == '{')
            {
                  // first, check if '{' is a block-opener or an static-array opener
                  bool isBlockOpener = ((prevNonSpaceCh == '{' && bracketBlockStateStack->back())
                                        || prevNonSpaceCh == '}'
                                        || prevNonSpaceCh == ')'
                                        || prevNonSpaceCh == ';'
                                        || peekNextChar(line, i) == '{'
                                        || isInClassHeader
                                        || isNonInStatementArray
                                        || isSharpAccessor
                                        || isSharpDelegate
                                        || isInExtern
                                        || (isInDefine &&
                                            (prevNonSpaceCh == '('
                                             || isLegalNameChar(prevNonSpaceCh))));

                  //if (isNonInStatementArray
                  //        && prevNonSpaceCh != ')'
                  //        && prevNonSpaceCh != '='
                  //        && !isInEnum
                  //        && i == nonInStatementBracket)
                  //    isBlockOpener = false;

                  isInClassHeader = false;

                  if (!isBlockOpener && currentHeader != NULL)
                  {
                        for (size_t n = 0; n < nonParenHeaders.size(); n++)
                              if (currentHeader == nonParenHeaders[n])
                              {
                                    isBlockOpener = true;
                                    break;
                              }
                  }

                  // TODO: TEMPORARY??? fix to give C# }) statements a full indent
                  // check for anonymous method
                  //if (isBlockOpener && isSharpStyle() && !parenIndentStack->empty())
                  //    isBlockOpener = false;

                  bracketBlockStateStack->push_back(isBlockOpener);

                  if (!isBlockOpener)
                  {
                        inStatementIndentStackSizeStack->push_back(inStatementIndentStack->size());
                        registerInStatementIndent(line, i, spaceTabCount, tabIncrementIn, 0, true);
                        parenDepth++;
                        if (i == 0)
                              shouldIndentBrackettedLine = false;

                        continue;
                  }

                  // this bracket is a block opener...

                  ++lineOpeningBlocksNum;

                  if (isInClassHeaderTab)
                  {
                        isInClassHeaderTab = false;
                        // decrease tab count if bracket is broken
                        size_t firstChar = line.find_first_not_of(" \t");
                        if (firstChar != string::npos
                                && line[firstChar] == '{'
                                && (int) firstChar == i)
                        {
                              tabCount -= classInitializerTabs;
                              // decrease one more if an empty class
                              if (headerStack->size() > 0
                                      && (*headerStack).back() == &AS_CLASS)
                              {
                                    int nextChar = getNextProgramCharDistance(line, i);
                                    if (line[nextChar] == '}')
                                          tabCount--;
                              }
                        }
                  }

                  if (bracketIndent && !namespaceIndent && headerStack->size() > 0
                          && (*headerStack).back() == &AS_NAMESPACE)
                  {
                        shouldIndentBrackettedLine = false;
                        tabCount--;
                  }

                  // 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)
                  {
                        spaceTabCount = 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
            bool isPotentialHeader = isCharPotentialHeader(line, i);

            if (isPotentialHeader)
            {
                  const string *newHeader = findHeader(line, i, headers);

                  if (newHeader != NULL)
                  {
                        char peekChar = peekNextChar(line, i + newHeader->length() - 1);

                        // is not a header if part of a definition
                        if (peekChar == ',' || peekChar == ')')
                              newHeader = NULL;
                        // the following accessor definitions are NOT headers
                        // goto default; is NOT a header
                        // default(int) keyword in C# is NOT a header
                        else if ((newHeader == &AS_GET || newHeader == &AS_SET || newHeader == &AS_DEFAULT)
                                 && (peekChar == ';' ||  peekChar == '('))
                        {
                              newHeader = NULL;
                        }
                  }

                  if (newHeader != NULL)
                  {
                        // if we reached here, then this is a header...
                        bool isIndentableHeader = true;

                        isInHeader = true;

                        vector<const string*> *lastTempStack;
                        if (tempStacks->empty())
                              lastTempStack = NULL;
                        else
                              lastTempStack = tempStacks->back();

                        // if a new block is opened, push a new stack into tempStacks to hold the
                        // future list of headers in the new block.

                        // take care of the special case: 'else if (...)'
                        if (newHeader == &AS_IF && lastLineHeader == &AS_ELSE)
                        {
                              headerStack->pop_back();
                        }

                        // take care of 'else'
                        else if (newHeader == &AS_ELSE)
                        {
                              if (lastTempStack != NULL)
                              {
                                    int indexOfIf = indexOf(*lastTempStack, &AS_IF);
                                    if (indexOfIf != -1)
                                    {
                                          // recreate the header list in headerStack up to the previous 'if'
                                          // from the temporary snapshot stored in lastTempStack.
                                          int restackSize = lastTempStack->size() - indexOfIf - 1;
                                          for (int r = 0; r < restackSize; r++)
                                          {
                                                headerStack->push_back(lastTempStack->back());
                                                lastTempStack->pop_back();
                                          }
                                          if (!closingBracketReached)
                                                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;
                              if (!haveCaseIndent)
                              {
                                    haveCaseIndent = true;
                                    if (!lineBeginsWithBracket)
                                          --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;
                  }  // newHeader != NULL
            }   // isPotentialHeader

            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() && isInClassHeader)
                  {
                        // found a 'class A : public B' definition
                        // so do nothing special
                  }

                  else if (isCStyle() && isdigit(peekNextChar(line, i)))
                  {
                        // found a bit field
                        // so do nothing special
                  }

                  else if (isCStyle() && isInClass && prevNonSpaceCh != ')')
                  {
                        // found a 'private:' or 'public:' inside a class definition
                        --tabCount;
                  }

                  else if (isJavaStyle() && lastLineHeader == &AS_FOR)
                  {
                        // found a java for-each statement
                        // so do nothing special
                  }

                  else if (isCStyle() && prevNonSpaceCh == ')' && !isInCase)
                  {
                        isInClassHeader = true;
                        if (i == 0)
                              tabCount += classInitializerTabs;
                  }
                  else
                  {
                        currentNonSpaceCh = ';'; // so that brackets after the ':' will appear as block-openers
                        if (isInCase)
                        {
                              isInCase = false;
                              ch = ';'; // from here on, treat char as ';'
                        }
                        else if (isCStyle() || (isSharpStyle() && peekNextChar(line, i) == ';'))    // is in a label (e.g. 'label1:')
                        {
                              if (labelIndent)
                                    --tabCount; // unindent label by one indent
                              else if (!lineBeginsWithBracket)
                                    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();

                              // do not indent namespace bracket unless namespaces are indented
                              if (!namespaceIndent && headerStack->size() > 0
                                      && (*headerStack).back() == &AS_NAMESPACE)
                                    shouldIndentBrackettedLine = false;

                              if (!tempStacks->empty())
                              {
                                    vector<const string*> *temp =  tempStacks->back();
                                    tempStacks->pop_back();
                                    delete temp;
                              }
                        }


                        ch = ' '; // needed due to cases such as '}else{', so that headers ('else' tn tih case) will be identified...
                  }

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

            if (isPotentialHeader)
            {
                  // check for preBlockStatements in C/C++ ONLY if not within parenthesies
                  // (otherwise 'struct XXX' statements would be wrongly interpreted...)
                  if (!isInTemplate && !(isCStyle() && parenDepth > 0))
                  {
                        const string *newHeader = findHeader(line, i, preBlockStatements);
                        if (newHeader != NULL)
                        {
                              isInClassHeader = true;

                              if (!isSharpStyle())
                                    headerStack->push_back(newHeader);
                              // do not need 'where' in the headerStack
                              // do not need second 'class' statement in a row
                              else if (!(newHeader == &AS_WHERE
                                         || (newHeader == &AS_CLASS
                                             && headerStack->size() > 0
                                             && headerStack->back() == &AS_CLASS)))
                                    headerStack->push_back(newHeader);

                              outBuffer.append(newHeader->substr(1));
                              i += newHeader->length() - 1;
                              continue;
                        }
                  }
                  const string *foundIndentableHeader = findHeader(line, i, indentableHeaders);

                  if (foundIndentableHeader != NULL)
                  {
                        // must bypass the header before registering the in statement
                        outBuffer.append(foundIndentableHeader->substr(1));
                        i += foundIndentableHeader->length() - 1;
                        if (!isInOperator && !isInTemplate && !isNonInStatementArray)
                        {
                              registerInStatementIndent(line, i, spaceTabCount, tabIncrementIn, 0, false);
                              isInStatement = true;
                        }
                        continue;
                  }

                  if (isCStyle() && findKeyword(line, i, AS_OPERATOR))
                        isInOperator = true;

                  // "new" operator is a pointer, not a calculation
                  if (findKeyword(line, i, AS_NEW))
                  {
                        if (prevNonSpaceCh == '=' && isInStatement && !inStatementIndentStack->empty())
                              inStatementIndentStack->back() = 0;
                  }

                  // append the entire name for all others
                  string name = getCurrentWord(line, i);
                  outBuffer.append(name.substr(1));
                  i += name.length() - 1;
                  continue;
            }

            // Handle operators

            bool isPotentialOperator = isCharPotentialOperator(ch);

            if (isPotentialOperator)
            {
                  // Check if an operator has been reached.
                  const string *foundAssignmentOp = findOperator(line, i, assignmentOperators);
                  const string *foundNonAssignmentOp = findOperator(line, i, nonAssignmentOperators);

                  // 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, tabIncrementIn, 0, false);
                              isInStatement = true;
                        }
                  }
            }
      }   // end of for loop  *  end of for loop  *  end of for loop  *  end of for loop

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

      // must check one less in headerStack if more than one header on a line (allow-addins)...
      else if (!lineStartsInComment
               && (int) headerStack->size() > iPrelim + 1
               && !blockIndent
               && outBuffer.length() > 0
               && outBuffer[0] == '{'
               && !(lineOpeningBlocksNum > 0 && lineOpeningBlocksNum == lineClosingBlocksNum)
               && !(headerStack->size() > 2 && (*headerStack)[headerStack->size()-3] == &AS_OPEN_BRACKET)
               && shouldIndentBrackettedLine)
            --tabCount;

      // unindent a closing bracket...
      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);

      // correctly indent class continuation lines...
      else if (!lineStartsInComment
               && !lineOpensComment
               && isInClassHeaderTab
               && !blockIndent
               && outBuffer.length() > 0
               && lineOpeningBlocksNum == 0
               && lineOpeningBlocksNum == lineClosingBlocksNum
               && (headerStack->size() > 0 && headerStack->back() == &AS_CLASS))
            --tabCount;

      if (tabCount < 0)
            tabCount = 0;

      // take care of extra bracket indentatation option...
      if (!lineStartsInComment
              && bracketIndent
              && shouldIndentBrackettedLine
              && outBuffer.length() > 0
              && (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 || isInQuoteContinuation)
            tabCount = spaceTabCount = 0;

      // finally, insert indentations into begining of line

      if (shouldForceTabIndentation)
      {
            tabCount += spaceTabCount / indentLength;
            spaceTabCount = spaceTabCount % indentLength;
      }

      outBuffer = preLineWS(spaceTabCount, tabCount) + outBuffer;

      prevFinalLineSpaceTabCount = spaceTabCount;
      prevFinalLineTabCount = tabCount;

      if (lastLineHeader != NULL)
            previousLastLineHeader = lastLineHeader;

      return outBuffer;
}


string ASBeautifier::preLineWS(int spaceTabCount, int tabCount)
{
      string ws;

      for (int i = 0; i < tabCount; i++)
            ws += indentString;

      while ((spaceTabCount--) > 0)
            ws += string(" ");

      return ws;

}

bool ASBeautifier::isClassAccessModifier(string& line) const
{
      size_t firstChar = line.find_first_not_of(" \t");
      if (firstChar == string::npos)
            return false;
      // bypass a colon
      if (line[firstChar] == ':')
      {
            firstChar = line.find_first_not_of(" \t");
            if (firstChar == string::npos)
                  return false;
      }
      if (line.compare(firstChar, 7, "public ") == 0
              || line.compare(firstChar, 8, "private ") == 0
              || line.compare(firstChar, 10, "protected ") == 0)
            return true;
      return false;
}

/**
 * register an in-statement indent.
 */
01959 void ASBeautifier::registerInStatementIndent(const string &line, int i, int spaceTabCount,
        int tabIncrementIn, int minIndent, bool updateParenStack)
{
      int inStatementIndent;
      int remainingCharNum = line.length() - i;
      int nextNonWSChar = getNextProgramCharDistance(line, i);

      // if indent is around the last char in the line, indent instead one indent from the previous indent
      if (nextNonWSChar == remainingCharNum)
      {
            int previousIndent = spaceTabCount;
            if (!inStatementIndentStack->empty())
                  previousIndent = inStatementIndentStack->back();
            int currIndent = /*2*/ indentLength + previousIndent;
            if (currIndent > maxInStatementIndent
                    && line[i] != '{')
                  currIndent = indentLength * 2 + spaceTabCount;
            inStatementIndentStack->push_back(currIndent);
            if (updateParenStack)
                  parenIndentStack->push_back(previousIndent);
            return;
      }

      if (updateParenStack)
            parenIndentStack->push_back(i + spaceTabCount - horstmannIndentInStatement);

      int tabIncrement = tabIncrementIn;

      // check for following tabs
      for (int j = i + 1; j < (i + nextNonWSChar); j++)
      {
            if (line[j] == '\t')
                  tabIncrement += convertTabToSpaces(j, tabIncrement);
      }

      inStatementIndent = i + nextNonWSChar + spaceTabCount + tabIncrement;

      // check for run-in statement
      if (i > 0 && line[0] == '{')
            inStatementIndent -= indentLength;

//    if (i + nextNonWSChar < minIndent)
//          inStatementIndent = minIndent + spaceTabCount;

      if (inStatementIndent < minIndent)
            inStatementIndent = minIndent + spaceTabCount;

//    if (i + nextNonWSChar > maxInStatementIndent)
//          inStatementIndent =  indentLength * 2 + spaceTabCount;

      if (inStatementIndent > maxInStatementIndent)
            inStatementIndent = indentLength * 2 + spaceTabCount;

      if (!inStatementIndentStack->empty() &&
              inStatementIndent < inStatementIndentStack->back())
            inStatementIndent = inStatementIndentStack->back();

      // the block opener is not indented for a NonInStatementArray
      if (isNonInStatementArray && !bracketBlockStateStack->empty() && bracketBlockStateStack->back())
            inStatementIndent = 0;

      inStatementIndentStack->push_back(inStatementIndent);
}

/**
 * get distance to the next non-white space, non-comment character in the line.
 * if no such character exists, return the length remaining to the end of the line.
 */
02027 int ASBeautifier::getNextProgramCharDistance(const string &line, int i) const
{
      bool inComment = false;
      int  remainingCharNum = line.length() - i;
      int  charDistance;
      char ch;

      for (charDistance = 1; charDistance < remainingCharNum; charDistance++)
      {
            ch = line[i + charDistance];
            if (inComment)
            {
                  if (line.compare(i + charDistance, 2, "*/") == 0)
                  {
                        charDistance++;
                        inComment = false;
                  }
                  continue;
            }
            else if (isWhiteSpace(ch))
                  continue;
            else if (ch == '/')
            {
                  if (line.compare(i + charDistance, 2, "//") == 0)
                        return remainingCharNum;
                  else if (line.compare(i + charDistance, 2, "/*") == 0)
                  {
                        charDistance++;
                        inComment = true;
                  }
            }
            else
                  return charDistance;
      }

      return charDistance;
}

// check if a specific line position contains a header.
const string* ASBeautifier::findHeader(const string &line, int i,
                                       const vector<const string*> &possibleHeaders) const
{
      assert(isCharPotentialHeader(line, i));
      // check the word
      size_t maxHeaders = possibleHeaders.size();
      for (size_t p = 0; p < maxHeaders; p++)
      {
            const string* header = possibleHeaders[p];
            const size_t wordEnd = i + header->length();
            if (wordEnd > line.length())
                  continue;
            int result = (line.compare(i, header->length(), *header));
            if (result > 0)
                  continue;
            if (result < 0)
                  break;
            // check that this is not part of a longer word
            if (wordEnd == line.length())
                  return header;
            if (isLegalNameChar(line[wordEnd]))
                  continue;
            // is not a header if part of a definition
            const char peekChar = peekNextChar(line, wordEnd - 1);
            if (peekChar == ',' || peekChar == ')')
                  break;
            return header;
      }
      return NULL;
}


// check if a specific line position contains an operator.
const string* ASBeautifier::findOperator(const string &line, int i,
        const vector<const string*> &possibleOperators) const
{
      assert(isCharPotentialOperator(line[i]));
      // find the operator in the vector
      // the vector contains the LONGEST operators first
      // must loop thru the entire vector
      size_t maxOperators = possibleOperators.size();
      for (size_t p = 0; p < maxOperators; p++)
      {
            const size_t wordEnd = i + (*possibleOperators[p]).length();
            if (wordEnd > line.length())
                  continue;
            if (line.compare(i, (*possibleOperators[p]).length(), *possibleOperators[p]) == 0)
                  return possibleOperators[p];
      }
      return NULL;
}

/**
 * find the index number of a string element in a container of strings
 *
 * @return              the index number of element in the ocntainer. -1 if element not found.
 * @param container     a vector of strings.
 * @param element       the element to find .
 */
02125 int ASBeautifier::indexOf(vector<const string*> &container, const string *element)
{
      vector<const string*>::const_iterator where;

      where = find(container.begin(), container.end(), element);
      if (where == container.end())
            return -1;
      else
            return (int) (where - container.begin());
}

/**
 * convert tabs to spaces.
 * i is the position of the character to convert to spaces.
 * tabIncrementIn is the increment that must be added for tab indent characters
 *     to get the correct column for the current tab.
 */
02142 int ASBeautifier::convertTabToSpaces(int i, int tabIncrementIn) const
{
      int tabToSpacesAdjustment = indentLength - 1 - ((tabIncrementIn + i) % indentLength);
      return tabToSpacesAdjustment;
}

/**
 * trim removes the white space surrounding a line.
 *
 * @return          the trimmed line.
 * @param str       the line to trim.
 */
02154 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;
}

/**
 * delete a static member vector object using swap
 * to eliminate memory leak reporting for the vector
 */
02174 void ASBeautifier::deleteStaticVectors()
{
      beautifierFileType = 9;       // reset to an invalid type
      vector<const string*> headersClear;
      headers.swap(headersClear);
      vector<const string*> nonParenHeadersClear;
      nonParenHeaders.swap(nonParenHeadersClear);
      vector<const string*> preBlockStatementsClear;
      preBlockStatements.swap(preBlockStatementsClear);
      vector<const string*> assignmentOperatorsClear;
      assignmentOperators.swap(assignmentOperatorsClear);
      vector<const string*> nonAssignmentOperatorsClear;
      nonAssignmentOperators.swap(nonAssignmentOperatorsClear);
      vector<const string*> indentableHeadersClear;
      indentableHeaders.swap(indentableHeadersClear);
}

/**
 * delete a vector object
 * T is the type of vector
 * used for all vectors except tempStacks
 */
template<typename T>
02197 void ASBeautifier::deleteContainer(T &container)
{
      if (container != NULL)
      {
            container->clear();
            delete (container);
            container = NULL;
      }
}

/**
 * Delete the tempStacks vector object.
 * The tempStacks is a vector of pointers to strings allocated with
 * the 'new' operator.
 * Therefore the strings have to be deleted in addition to the
 * tempStacks entries.
 */
02214 void ASBeautifier::deleteContainer(vector<vector<const string*>*>* &container)
{
      if (container != NULL)
      {
            vector<vector<const string*>*>::iterator iter = container->begin();
            for (; iter != container->end(); iter++)
                  delete *iter;
            container->clear();
            delete (container);
            container = NULL;
      }
}

/**
 * initialize a vector object
 * T is the type of vector
 * used for all vectors
 */
template<typename T>
02233 void ASBeautifier::initContainer(T &container, T value)
{
      // since the ASFormatter object is never deleted,
      // the existing vectors must be deleted before creating new ones
      if (container != NULL )
            deleteContainer(container);
      container = value;
}


}   // end namespace astyle


Generated by  Doxygen 1.6.0   Back to index