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

ASBeautifier.cpp

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

#include "astyle.h"

#include <algorithm>
#include <iostream>


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


namespace astyle
{
vector<const string*> ASBeautifier::headers;
vector<const string*> ASBeautifier::nonParenHeaders;
vector<const string*> ASBeautifier::preBlockStatements;
vector<const string*> ASBeautifier::assignmentOperators;
vector<const string*> ASBeautifier::nonAssignmentOperators;


/*
 * initialize the static vars
 */
void ASBeautifier::initStatic()
{
      static int beautifierFileType = 9;     // initialized with an invalid type

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

      beautifierFileType = fileType;

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

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

//    cout << "beaut" << endl;
}

/**
 * ASBeautifier's constructor
 */
ASBeautifier::ASBeautifier()
{
      waitingBeautifierStack = NULL;
      activeBeautifierStack = NULL;
      waitingBeautifierStackLengthStack = NULL;
      activeBeautifierStackLengthStack = NULL;

      headerStack  = NULL;
      tempStacks = NULL;
      blockParenDepthStack = NULL;
      blockStatementStack = NULL;
      parenStatementStack = NULL;
      bracketBlockStateStack = NULL;
      inStatementIndentStack = NULL;
      inStatementIndentStackSizeStack = NULL;
      parenIndentStack = NULL;
      sourceIterator = NULL;

      isMinimalConditinalIndentSet = false;
      shouldForceTabIndentation = false;

      setSpaceIndentation(4);
      setMaxInStatementIndentLength(40);
      setClassIndent(false);
      setSwitchIndent(false);
      setCaseIndent(false);
      setBlockIndent(false);
      setBracketIndent(false);
      setNamespaceIndent(false);
      setLabelIndent(false);
      setEmptyLineFill(false);
      fileType = C_TYPE;
      setCStyle();
      setPreprocessorIndent(false);
}

/**
 * ASBeautifier's copy constructor
 */
ASBeautifier::ASBeautifier(const ASBeautifier &other)
{
      waitingBeautifierStack = NULL;
      activeBeautifierStack = NULL;
      waitingBeautifierStackLengthStack = NULL;
      activeBeautifierStackLengthStack = NULL;

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

      tempStacks = new vector<vector<const string*>*>;
      vector<vector<const string*>*>::iterator iter;
      for (iter = other.tempStacks->begin();
              iter != other.tempStacks->end();
              ++iter)
      {
            vector<const string*> *newVec = new vector<const string*>;
            *newVec = **iter;
            tempStacks->push_back(newVec);
      }
      blockParenDepthStack = new vector<int>;
      *blockParenDepthStack = *other.blockParenDepthStack;

      blockStatementStack = new vector<bool>;
      *blockStatementStack = *other.blockStatementStack;

      parenStatementStack =  new vector<bool>;
      *parenStatementStack = *other.parenStatementStack;

      bracketBlockStateStack = new vector<bool>;
      *bracketBlockStateStack = *other.bracketBlockStateStack;

      inStatementIndentStack = new vector<int>;
      *inStatementIndentStack = *other.inStatementIndentStack;

      inStatementIndentStackSizeStack = new vector<int>;
      *inStatementIndentStackSizeStack = *other.inStatementIndentStackSizeStack;

      parenIndentStack = new vector<int>;
      *parenIndentStack = *other.parenIndentStack;

      sourceIterator = other.sourceIterator;

      // protected variables
      fileType = other.fileType;
      isCStyle = other.isCStyle;
      isJavaStyle = other.isJavaStyle;
      isSharpStyle = other.isSharpStyle;

      // variables set by ASFormatter
      // must also be updated in preprocessor
      inLineNumber = other.inLineNumber;
      outLineNumber = other.outLineNumber;
      lineCommentNoBeautify = other.lineCommentNoBeautify;
      isNonInStatementArray = other.isNonInStatementArray;

      // private variables
      indentString = other.indentString;
      currentHeader = other.currentHeader;
      previousLastLineHeader = other.previousLastLineHeader;
      immediatelyPreviousAssignmentOp = other.immediatelyPreviousAssignmentOp;
      probationHeader = other.probationHeader;
      isInQuote = other.isInQuote;
      isInComment = other.isInComment;
      isInCase = other.isInCase;
      isInQuestion = other.isInQuestion;
      isInStatement = other.isInStatement;
      isInHeader = other.isInHeader;
      isInOperator = other.isInOperator;
      isInTemplate = other.isInTemplate;
      isInDefine = other.isInDefine;
      isInDefineDefinition = other.isInDefineDefinition;
      classIndent = other.classIndent;
      isInClassHeader = other.isInClassHeader;
      isInClassHeaderTab = other.isInClassHeaderTab;
      switchIndent = other.switchIndent;
      caseIndent = other.caseIndent;
      namespaceIndent = other.namespaceIndent;
      bracketIndent = other.bracketIndent;
      blockIndent = other.blockIndent;
      labelIndent = other.labelIndent;
      preprocessorIndent = other.preprocessorIndent;
      isInConditional = other.isInConditional;
      isMinimalConditinalIndentSet = other.isMinimalConditinalIndentSet;
      shouldForceTabIndentation = other.shouldForceTabIndentation;
      emptyLineFill = other.emptyLineFill;
      backslashEndsPrevLine = other.backslashEndsPrevLine;
      blockCommentNoIndent = other.blockCommentNoIndent;
      blockCommentNoBeautify = other.blockCommentNoBeautify;
      previousLineProbationTab = other.previousLineProbationTab;
      minConditionalIndent = other.minConditionalIndent;
      parenDepth = other.parenDepth;
      indentLength = other.indentLength;
      blockTabCount = other.blockTabCount;
      leadingWhiteSpaces = other.leadingWhiteSpaces;
      maxInStatementIndent = other.maxInStatementIndent;
      templateDepth = other.templateDepth;
      prevFinalLineSpaceTabCount = other.prevFinalLineSpaceTabCount;
      prevFinalLineTabCount = other.prevFinalLineTabCount;
      defineTabCount = other.defineTabCount;
      quoteChar = other.quoteChar;
      prevNonSpaceCh = other.prevNonSpaceCh;
      currentNonSpaceCh = other.currentNonSpaceCh;
      currentNonLegalCh = other.currentNonLegalCh;
      prevNonLegalCh = other.prevNonLegalCh;
}

/**
 * ASBeautifier's destructor
 */
ASBeautifier::~ASBeautifier()
{
      DELETE_CONTAINER(headerStack);
      DELETE_CONTAINER(tempStacks);
      DELETE_CONTAINER(blockParenDepthStack);
      DELETE_CONTAINER(blockStatementStack);
      DELETE_CONTAINER(parenStatementStack);
      DELETE_CONTAINER(bracketBlockStateStack);
      DELETE_CONTAINER(inStatementIndentStack);
      DELETE_CONTAINER(inStatementIndentStackSizeStack);
      DELETE_CONTAINER(parenIndentStack);
}

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

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

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

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

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

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

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

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

      immediatelyPreviousAssignmentOp = NULL;
      previousLastLineHeader = NULL;
      currentHeader = NULL;

      isInQuote = false;
      isInComment = false;
      isInStatement = false;
      isInCase = false;
      isInQuestion = false;
      isInClassHeader = false;
      isInClassHeaderTab = false;
      isInHeader = false;
      isInOperator = false;
      isInTemplate = false;
      isInConditional = false;
      templateDepth = 0;
      parenDepth = 0;
      blockTabCount = 0;
      leadingWhiteSpaces = 0;
      prevNonSpaceCh = '{';
      currentNonSpaceCh = '{';
      prevNonLegalCh = '{';
      currentNonLegalCh = '{';
      quoteChar = ' ';
      prevFinalLineSpaceTabCount = 0;
      prevFinalLineTabCount = 0;
      probationHeader = NULL;
      backslashEndsPrevLine = false;
      isInDefine = false;
      isInDefineDefinition = false;
      defineTabCount = 0;
      lineCommentNoBeautify = false;
      blockCommentNoIndent = false;
      blockCommentNoBeautify = false;
      previousLineProbationTab = false;
      isNonInStatementArray = false;
      inLineNumber = -1;           // for debugging
      outLineNumber = 0;           // for debugging
}

/**
 * set indentation style to C/C++.
 */
void ASBeautifier::setCStyle()
{
      fileType = C_TYPE;
      isCStyle     = true;
      isJavaStyle  = false;
      isSharpStyle = false;
}

/**
 * set indentation style to Java.
 */
void ASBeautifier::setJavaStyle()
{
      fileType = JAVA_TYPE;
      isJavaStyle  = true;
      isCStyle     = false;
      isSharpStyle = false;
}

/**
 * set indentation style to C#.
 */
void ASBeautifier::setSharpStyle()
{
      fileType = SHARP_TYPE;
      isSharpStyle = true;
      isCStyle     = false;
      isJavaStyle  = false;
}

/**
 * indent using one tab per indentation
 */
void ASBeautifier::setTabIndentation(int length, bool forceTabs)
{
      indentString = "\t";
      indentLength = length;
      shouldForceTabIndentation = forceTabs;

      if (!isMinimalConditinalIndentSet)
            minConditionalIndent = indentLength * 2;
}

/**
 * indent using a number of spaces per indentation.
 *
 * @param   length     number of spaces per indent.
 */
void ASBeautifier::setSpaceIndentation(int length)
{
      indentString = string(length, ' ');
      indentLength = length;

      if (!isMinimalConditinalIndentSet)
            minConditionalIndent = indentLength * 2;
}

/**
 * set the maximum indentation between two lines in a multi-line statement.
 *
 * @param   max     maximum indentation length.
 */
void ASBeautifier::setMaxInStatementIndentLength(int max)
{
      maxInStatementIndent = max;
}

/**
 * set the minimum indentation between two lines in a multi-line condition.
 *
 * @param   min     minimal indentation length.
 */
void ASBeautifier::setMinConditionalIndentLength(int min)
{
      minConditionalIndent = min;
      isMinimalConditinalIndentSet = true;
}

/**
 * set the state of the bracket indentation option. If true, brackets will
 * be indented one additional indent.
 *
 * @param   state             state of option.
 */
void ASBeautifier::setBracketIndent(bool state)
{
      bracketIndent = state;
}

/**
 * set the state of the block indentation option. If true, entire blocks
 * will be indented one additional indent, similar to the GNU indent style.
 *
 * @param   state             state of option.
 */
void ASBeautifier::setBlockIndent(bool state)
{
      if (state)
            setBracketIndent(false); // so that we don't have both bracket and block indent
      blockIndent = state;
}

/**
 * set the state of the class indentation option. If true, C++ class
 * definitions will be indented one additional indent.
 *
 * @param   state             state of option.
 */
void ASBeautifier::setClassIndent(bool state)
{
      classIndent = state;
}

/**
 * set the state of the switch indentation option. If true, blocks of 'switch'
 * statements will be indented one additional indent.
 *
 * @param   state             state of option.
 */
void ASBeautifier::setSwitchIndent(bool state)
{
      switchIndent = state;
}

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

/**
 * set the state of the namespace indentation option.
 * If true, blocks of 'namespace' statements will be indented one
 * additional indent. Otherwise, NO indentation will be added.
 *
 * @param   state             state of option.
 */
void ASBeautifier::setNamespaceIndent(bool state)
{
      namespaceIndent = state;
}

/**
 * set the state of the label indentation option.
 * If true, labels will be indented one indent LESS than the
 * current indentation level.
 * If false, labels will be flushed to the left with NO
 * indent at all.
 *
 * @param   state             state of option.
 */
void ASBeautifier::setLabelIndent(bool state)
{
      labelIndent = state;
}

/**
 * set the state of the preprocessor indentation option.
 * If true, multiline #define statements will be indented.
 *
 * @param   state             state of option.
 */
void ASBeautifier::setPreprocessorIndent(bool state)
{
      preprocessorIndent = state;
}

/**
 * set the state of the empty line fill option.
 * If true, empty lines will be filled with the whitespace.
 * of their previous lines.
 * If false, these lines will remain empty.
 *
 * @param   state             state of option.
 */
void ASBeautifier::setEmptyLineFill(bool state)
{
      emptyLineFill = state;
}

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

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

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

/**
 * get C style identifier.
 * If true, a C source is being indented.
 *
 * @return   state of isCStyle option.
 */
bool ASBeautifier::getCStyle(void)
{
      return isCStyle;
}

/**
 * get Java style identifier.
 * If true, a Java source is being indented.
 *
 * @return   state of isJavaStyle option.
 */
bool ASBeautifier::getJavaStyle(void)
{
      return isJavaStyle;
}

/**
 * get C# style identifier.
 * If true, a C# source is being indented.
 *
 * @return   state of isSharpStyle option.
 */
bool ASBeautifier::getSharpStyle(void)
{
      return isSharpStyle;
}

/**
 * get the state of the empty line fill option.
 * If true, empty lines will be filled with the whitespace.
 * of their previous lines.
 * If false, these lines will remain empty.
 *
 * @return   state of emptyLineFill option.
 */
bool ASBeautifier::getEmptyLineFill(void)
{
      return emptyLineFill;
}

/**
 * check if there are any indented lines ready to be read by nextLine()
 *
 * @return    are there any indented lines ready?
 */
bool ASBeautifier::hasMoreLines() const
{
      return sourceIterator->hasMoreLines();
}

/**
 * get the next indented line.
 *
 * @return    indented line.
 */
string ASBeautifier::nextLine()
{
      return beautify(sourceIterator->nextLine());
}

/**
 * beautify a line of source code.
 * every line of source code in a source code file should be sent
 * one after the other to the beautify method.
 *
 * @return      the indented line.
 * @param originalLine       the original unindented line.
 */
string ASBeautifier::beautify(const string &originalLine)
{
      string line;
      bool isInLineComment = false;
      bool lineStartsInComment = false;
      bool isInClass = false;
      bool isInSwitch = false;
      bool isImmediatelyAfterConst = false;
      bool isSpecialChar = false;
      char ch = ' ';
      char prevCh;
      string outBuffer; // the newly idented line is bufferd here
      int tabCount = 0;
      const string *lastLineHeader = NULL;
      bool closingBracketReached = false;
      int spaceTabCount = 0;
      char tempCh;
      size_t headerStackSize = headerStack->size();
      bool shouldIndentBrackettedLine = true;
      int lineOpeningBlocksNum = 0;
      int lineClosingBlocksNum = 0;
      bool previousLineProbation = (probationHeader != NULL);
      int i;

      currentHeader = NULL;
      lineStartsInComment = isInComment;
      blockCommentNoBeautify = blockCommentNoIndent;
      previousLineProbationTab = false;
      outLineNumber++;

      // handle and remove white spaces around the line:
      // If not in comment, first find out size of white space before line,
      // so that possible comments starting in the line continue in
      // relation to the preliminary white-space.
      if (!isInComment)
      {
            int strlen = originalLine.length();
            leadingWhiteSpaces = 0;

            for (int j = 0; j < strlen && isWhiteSpace(originalLine[j]); j++)
            {
                  if (originalLine[j] == '\t')
                        leadingWhiteSpaces += indentLength;
                  else
                        leadingWhiteSpaces++;
            }
            line = trim(originalLine);
      }
      else
      {
            // convert leading tabs to spaces
            string spaceTabs(indentLength, ' ');
            string newLine = originalLine;
            int strlen = newLine.length();

            for (int j=0; j < leadingWhiteSpaces && j < strlen; j++)
            {
                  if (newLine[j] == '\t')
                  {
                        newLine.replace(j, 1, spaceTabs);
                        strlen = newLine.length();
                  }
            }

            // trim the comment leaving the new leading whitespace
            int trimSize = 0;
            strlen = newLine.length();

            while (trimSize < strlen
                    && trimSize < leadingWhiteSpaces
                    && isWhiteSpace(newLine[trimSize]))
                  trimSize++;


            while (trimSize < strlen && isWhiteSpace(newLine[strlen-1]))
                  strlen--;

            line = newLine.substr(trimSize, strlen);
            size_t trimEnd = line.find_last_not_of(" \t");
            if (trimEnd != string::npos)
            {
                  int spacesToDelete = line.length() - 1 - trimEnd;
                  if (spacesToDelete > 0)
                        line.erase(trimEnd + 1, spacesToDelete);
            }
      }


      if (line.length() == 0)
      {
            if (backslashEndsPrevLine)    // must continue to clear variables
                  line = ' ';
            else if (emptyLineFill)
                  return preLineWS(prevFinalLineSpaceTabCount, prevFinalLineTabCount);
            else
                  return line;
      }

      // handle preprocessor commands

      if (isCStyle && !isInComment && (line[0] == '#' || backslashEndsPrevLine))
      {
            if (line[0] == '#')
            {
                  string preproc = trim(string(line.c_str() + 1));

                  // When finding a multi-lined #define statement, the original beautifier
                  // 1. sets its isInDefineDefinition flag
                  // 2. clones a new beautifier that will be used for the actual indentation
                  //    of the #define. This clone is put into the activeBeautifierStack in order
                  //    to be called for the actual indentation.
                  // The original beautifier will have isInDefineDefinition = true, isInDefine = false
                  // The cloned beautifier will have   isInDefineDefinition = true, isInDefine = true
                  if (preprocessorIndent && preproc.compare(0, 6, "define") == 0 &&  line[line.length() - 1] == '\\')
                  {
                        if (!isInDefineDefinition)
                        {
                              ASBeautifier *defineBeautifier;

                              // this is the original beautifier
                              isInDefineDefinition = true;

                              // push a new beautifier into the active stack
                              // this beautifier will be used for the indentation of this define
                              defineBeautifier = new ASBeautifier(*this);
                              activeBeautifierStack->push_back(defineBeautifier);
                        }
                        else
                        {
                              // the is the cloned beautifier that is in charge of indenting the #define.
                              isInDefine = true;
                        }
                  }
                  else if (preproc.compare(0, 2, "if") == 0)
                  {
                        // push a new beautifier into the stack
                        waitingBeautifierStackLengthStack->push_back(waitingBeautifierStack->size());
                        activeBeautifierStackLengthStack->push_back(activeBeautifierStack->size());
                        waitingBeautifierStack->push_back(new ASBeautifier(*this));
                  }
                  else if (preproc.compare(0, 4/*2*/, "else") == 0)
                  {
                        if (waitingBeautifierStack && !waitingBeautifierStack->empty())
                        {
                              // MOVE current waiting beautifier to active stack.
                              activeBeautifierStack->push_back(waitingBeautifierStack->back());
                              waitingBeautifierStack->pop_back();
                        }
                  }
                  else if (preproc.compare(0, 4, "elif") == 0)
                  {
                        if (waitingBeautifierStack && !waitingBeautifierStack->empty())
                        {
                              // append a COPY current waiting beautifier to active stack, WITHOUT deleting the original.
                              activeBeautifierStack->push_back(new ASBeautifier(*(waitingBeautifierStack->back())));
                        }
                  }
                  else if (preproc.compare(0, 5, "endif") == 0)
                  {
                        int stackLength;
                        ASBeautifier *beautifier;

                        if (waitingBeautifierStackLengthStack && !waitingBeautifierStackLengthStack->empty())
                        {
                              stackLength = waitingBeautifierStackLengthStack->back();
                              waitingBeautifierStackLengthStack->pop_back();
                              while ((int) waitingBeautifierStack->size() > stackLength)
                              {
                                    beautifier = waitingBeautifierStack->back();
                                    waitingBeautifierStack->pop_back();
                                    delete beautifier;
                              }
                        }

                        if (!activeBeautifierStackLengthStack->empty())
                        {
                              stackLength = activeBeautifierStackLengthStack->back();
                              activeBeautifierStackLengthStack->pop_back();
                              while ((int) activeBeautifierStack->size() > stackLength)
                              {
                                    beautifier = activeBeautifierStack->back();
                                    activeBeautifierStack->pop_back();
                                    delete beautifier;
                              }
                        }
                  }
            }

            // check if the last char is a backslash
            if (line.length() > 0)
                  backslashEndsPrevLine = (line[line.length() - 1] == '\\');
            else
                  backslashEndsPrevLine = false;

            // check if this line ends a multi-line #define
            // if so, use the #define's cloned beautifier for the line's indentation
            // and then remove it from the active beautifier stack and delete it.
            if (!backslashEndsPrevLine && isInDefineDefinition && !isInDefine)
            {
                  string beautifiedLine;
                  ASBeautifier *defineBeautifier;

                  isInDefineDefinition = false;
                  defineBeautifier = activeBeautifierStack->back();
                  activeBeautifierStack->pop_back();

                  beautifiedLine = defineBeautifier->beautify(line);
                  delete defineBeautifier;
                  return beautifiedLine;
            }

            // unless this is a multi-line #define, return this precompiler line as is.
            if (!isInDefine && !isInDefineDefinition)
                  return originalLine;
      }

      // if there exists any worker beautifier in the activeBeautifierStack,
      // then use it instead of me to indent the current line.
      // variables set by ASFormatter must be updated.
      if (!isInDefine && activeBeautifierStack != NULL && !activeBeautifierStack->empty())
      {
            activeBeautifierStack->back()->inLineNumber = inLineNumber;
            activeBeautifierStack->back()->outLineNumber = outLineNumber;
            activeBeautifierStack->back()->lineCommentNoBeautify = lineCommentNoBeautify;
            activeBeautifierStack->back()->isNonInStatementArray = isNonInStatementArray;
            return activeBeautifierStack->back()->beautify(line);
      }

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


      for (i = 0; i < (int) headerStackSize; i++)
      {
            isInClass = false;

            if (blockIndent || (!(i > 0 && (*headerStack)[i-1] != &AS_OPEN_BRACKET
                                  && (*headerStack)[i] == &AS_OPEN_BRACKET)))
                  ++tabCount;

            if (!isJavaStyle && !namespaceIndent && i >= 1
                    && (*headerStack)[i-1] == &AS_NAMESPACE
                    && (*headerStack)[i] == &AS_OPEN_BRACKET)
                  --tabCount;

            if (isCStyle && i >= 1
                    && (*headerStack)[i-1] == &AS_CLASS
                    && (*headerStack)[i] == &AS_OPEN_BRACKET)
            {
                  if (classIndent)
                        ++tabCount;
                  isInClass = true;
            }

            // is the switchIndent option is on, indent switch statements an additional indent.
            else if (switchIndent && i > 1 &&
                     (*headerStack)[i-1] == &AS_SWITCH &&
                     (*headerStack)[i] == &AS_OPEN_BRACKET
                    )
            {
                  ++tabCount;
                  isInSwitch = true;
            }

      }

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

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

      if (isInClassHeader)
      {
            isInClassHeaderTab = true;
            tabCount += 2;
      }

      if (isInConditional)
      {
            --tabCount;
      }


      // parse characters in the current line.

      for (i = 0; i < (int) line.length(); i++)
      {
            tempCh = line[i];

            prevCh = ch;
            ch = tempCh;

            outBuffer.append(1, ch);

            if (isWhiteSpace(ch))
                  continue;

            // check for utf8 characters
            // isalnum() will display an assert message in debug if not bypassed here
            if (ch < 0)
                  continue;

            // handle special characters (i.e. backslash+character such as \n, \t, ...)
            if (isSpecialChar)
            {
                  isSpecialChar = false;
                  continue;
            }
            if (!(isInComment || isInLineComment) && line.compare(i, 2, "\\\\") == 0)
            {
                  outBuffer.append(1, '\\');
                  i++;
                  continue;
            }
            if (!(isInComment || isInLineComment) && ch == '\\')
            {
                  isSpecialChar = true;
                  continue;
            }

            // handle quotes (such as 'x' and "Hello Dolly")
            if (!(isInComment || isInLineComment) && (ch == '"' || ch == '\''))
                  if (!isInQuote)
                  {
                        quoteChar = ch;
                        isInQuote = true;
                  }
                  else if (quoteChar == ch)
                  {
                        isInQuote = false;
                        isInStatement = true;
                        continue;
                  }
            if (isInQuote)
                  continue;

            // handle comments

            if (!(isInComment || isInLineComment) && line.compare(i, 2, "//") == 0)
            {
                  isInLineComment = true;
                  outBuffer.append(1, '/');
                  i++;
                  continue;
            }
            else if (!(isInComment || isInLineComment) && line.compare(i, 2, "/*") == 0)
            {
                  isInComment = true;
                  outBuffer.append(1, '*');
                  i++;
                  size_t j = line.find_first_not_of(" \t");
                  if (!line.compare(j, 2, "/*") == 0) // does line start with comment?
                        blockCommentNoIndent = true;  // if no, cannot indent continuation lines
                  continue;
            }
            else if ((isInComment || isInLineComment) && line.compare(i, 2, "*/") == 0)
            {
                  isInComment = false;
                  outBuffer.append(1, '/');
                  i++;
                  blockCommentNoIndent = false;       // ok to indent next comment
                  continue;
            }

            if (isInComment || isInLineComment)
                  continue;

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

            if (probationHeader != NULL)
            {
                  if (((probationHeader == &AS_STATIC || probationHeader == &AS_CONST) && ch == '{')
                          || (probationHeader == &AS_SYNCHRONIZED && ch == '('))
                  {
                        // insert the probation header as a new header
                        isInHeader = true;
                        headerStack->push_back(probationHeader);

                        // handle the specific probation header
                        isInConditional = (probationHeader == &AS_SYNCHRONIZED);
                        if (probationHeader == &AS_CONST)
                              isImmediatelyAfterConst = true;

                        isInStatement = false;
                        // if the probation comes from the previous line, then indent by 1 tab count.
                        if (previousLineProbation && ch == '{')
                        {
                              tabCount++;
                              previousLineProbationTab = true;
                        }
                        previousLineProbation = false;
                  }

                  // dismiss the probation header
                  probationHeader = NULL;
            }

            prevNonSpaceCh = currentNonSpaceCh;
            currentNonSpaceCh = ch;
            if (!isLegalNameChar(ch) && ch != ',' && ch != ';')
            {
                  prevNonLegalCh = currentNonLegalCh;
                  currentNonLegalCh = ch;
            }

            if (isInHeader)
            {
                  isInHeader = false;
                  currentHeader = headerStack->back();
            }
            else
                  currentHeader = NULL;

            if (isCStyle && isInTemplate
                    && (ch == '<' || ch == '>')
                    &&  findHeader(line, i, nonAssignmentOperators) == NULL)
            {
                  if (ch == '<')
                  {
                        ++templateDepth;
                  }
                  else if (ch == '>')
                  {
                        if (--templateDepth <= 0)
                        {
                              if (isInTemplate)
                                    ch = ';';
                              else
                                    ch = 't';
                              isInTemplate = false;
                              templateDepth = 0;
                        }
                  }
            }

            // handle parenthesies
            if (ch == '(' || ch == '[' || ch == ')' || ch == ']')
            {
                  if (ch == '(' || ch == '[')
                  {
                        if (parenDepth == 0)
                        {
                              parenStatementStack->push_back(isInStatement);
                              isInStatement = true;
                        }
                        parenDepth++;

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

                        if (currentHeader != NULL)
                              registerInStatementIndent(line, i, spaceTabCount, minConditionalIndent/*indentLength*2*/, true);
                        else
                              registerInStatementIndent(line, i, spaceTabCount, 0, true);
                  }
                  else if (ch == ')' || ch == ']')
                  {
                        parenDepth--;
                        if (parenDepth == 0)
                        {
                              isInStatement = parenStatementStack->back();
                              parenStatementStack->pop_back();
                              ch = ' ';

                              isInConditional = false;
                        }

                        if (!inStatementIndentStackSizeStack->empty())
                        {
                              int previousIndentStackSize = inStatementIndentStackSizeStack->back();
                              inStatementIndentStackSizeStack->pop_back();
                              while (previousIndentStackSize < (int) inStatementIndentStack->size())
                                    inStatementIndentStack->pop_back();

                              if (!parenIndentStack->empty())
                              {
                                    int poppedIndent = parenIndentStack->back();
                                    parenIndentStack->pop_back();

                                    if (i == 0)
                                          spaceTabCount = poppedIndent;
                              }
                        }
                  }

                  continue;
            }


            if (ch == '{')
            {
                  bool isBlockOpener;
                  // first, check if '{' is a block-opener or an static-array opener
                  isBlockOpener = ((prevNonSpaceCh == '{' && bracketBlockStateStack->back())
                                   || prevNonSpaceCh == '}'
                                   || prevNonSpaceCh == ')'
                                   || prevNonSpaceCh == ';'
                                   || peekNextChar(line, i) == '{'
                                   || isNonInStatementArray
                                   || isInClassHeader
//                                 || isBlockOpener
                                   || isImmediatelyAfterConst
                                   || (isInDefine &&
                                       (prevNonSpaceCh == '('
                                        || prevNonSpaceCh == '_'
                                        || isalnum(prevNonSpaceCh))));

                  isInClassHeader = false;
                  if (!isBlockOpener && currentHeader != NULL)
                  {
                        for (size_t n = 0; n < nonParenHeaders.size(); n++)
                              if (currentHeader == nonParenHeaders[n])
                              {
                                    isBlockOpener = true;
                                    break;
                              }
                  }
                  bracketBlockStateStack->push_back(isBlockOpener);
                  if (!isBlockOpener)
                  {
                        inStatementIndentStackSizeStack->push_back(inStatementIndentStack->size());
                        registerInStatementIndent(line, i, spaceTabCount, 0, true);
                        parenDepth++;
                        if (i == 0)
                              shouldIndentBrackettedLine = false;

                        continue;
                  }

                  // this bracket is a block opener...

                  ++lineOpeningBlocksNum;
//                if (isInClassHeader)
//                isInClassHeader = false;

                  if (isInClassHeaderTab)
                  {
                        isInClassHeaderTab = false;
                        // decrease tab count if bracket is broken
                        size_t firstChar = line.find_first_not_of(" \t");
                        if (firstChar != string::npos)
                              if (line[firstChar] == '{' && (int) firstChar == i)
                                    tabCount -= 2;
                  }

                  // do not allow inStatementIndent - should occur for Java files only
                  if (inStatementIndentStack->size() > 0)
                  {
                        spaceTabCount = 0;
                        inStatementIndentStack->back() = 0;
                  }

                  blockParenDepthStack->push_back(parenDepth);
                  blockStatementStack->push_back(isInStatement);

                  inStatementIndentStackSizeStack->push_back(inStatementIndentStack->size());
                  if (inStatementIndentStack->size() > 0)
                        inStatementIndentStack->back() = 0;

                  blockTabCount += isInStatement ? 1 : 0;
                  parenDepth = 0;
                  isInStatement = false;

                  tempStacks->push_back(new vector<const string*>);
                  headerStack->push_back(&AS_OPEN_BRACKET);
                  lastLineHeader = &AS_OPEN_BRACKET;

                  continue;
            }

            //check if a header has been reached
            if (isWhiteSpace(prevCh))
            {
                  bool isIndentableHeader = true;
                  const string *newHeader = findHeader(line, i, headers);
                  if (newHeader != NULL)
                  {
                        // if we reached here, then this is a header...
                        isInHeader = true;

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

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

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

                        // take care of 'else'
                        else if (newHeader == &AS_ELSE)
                        {
                              if (lastTempStack != NULL)
                              {
                                    int indexOfIf = indexOf(*lastTempStack, &AS_IF);
                                    if (indexOfIf != -1)
                                    {
                                          // recreate the header list in headerStack up to the previous 'if'
                                          // from the temporary snapshot stored in lastTempStack.
                                          int restackSize = lastTempStack->size() - indexOfIf - 1;
                                          for (int r = 0; r < restackSize; r++)
                                          {
                                                headerStack->push_back(lastTempStack->back());
                                                lastTempStack->pop_back();
                                          }
                                          if (!closingBracketReached)
                                                tabCount += restackSize;
                                    }
                                    /*
                                     * If the above if is not true, i.e. no 'if' before the 'else',
                                     * then nothing beautiful will come out of this...
                                     * I should think about inserting an Exception here to notify the caller of this...
                                     */
                              }
                        }

                        // check if 'while' closes a previous 'do'
                        else if (newHeader == &AS_WHILE)
                        {
                              if (lastTempStack != NULL)
                              {
                                    int indexOfDo = indexOf(*lastTempStack, &AS_DO);
                                    if (indexOfDo != -1)
                                    {
                                          // recreate the header list in headerStack up to the previous 'do'
                                          // from the temporary snapshot stored in lastTempStack.
                                          int restackSize = lastTempStack->size() - indexOfDo - 1;
                                          for (int r = 0; r < restackSize; r++)
                                          {
                                                headerStack->push_back(lastTempStack->back());
                                                lastTempStack->pop_back();
                                          }
                                          if (!closingBracketReached)
                                                tabCount += restackSize;
                                    }
                              }
                        }
                        // check if 'catch' closes a previous 'try' or 'catch'
                        else if (newHeader == &AS_CATCH || newHeader == &AS_FINALLY)
                        {
                              if (lastTempStack != NULL)
                              {
                                    int indexOfTry = indexOf(*lastTempStack, &AS_TRY);
                                    if (indexOfTry == -1)
                                          indexOfTry = indexOf(*lastTempStack, &AS_CATCH);
                                    if (indexOfTry != -1)
                                    {
                                          // recreate the header list in headerStack up to the previous 'try'
                                          // from the temporary snapshot stored in lastTempStack.
                                          int restackSize = lastTempStack->size() - indexOfTry - 1;
                                          for (int r = 0; r < restackSize; r++)
                                          {
                                                headerStack->push_back(lastTempStack->back());
                                                lastTempStack->pop_back();
                                          }

                                          if (!closingBracketReached)
                                                tabCount += restackSize;
                                    }
                              }
                        }
                        else if (newHeader == &AS_CASE)
                        {
                              isInCase = true;
                              --tabCount;
                        }
                        else if (newHeader == &AS_DEFAULT)
                        {
                              isInCase = true;
                              --tabCount;
                        }
                        else if (newHeader == &AS_STATIC
                                 || newHeader == &AS_SYNCHRONIZED
                                 || (newHeader == &AS_CONST && isCStyle))
                        {
                              if (!headerStack->empty() &&
                                      (headerStack->back() == &AS_STATIC
                                       || headerStack->back() == &AS_SYNCHRONIZED
                                       || headerStack->back() == &AS_CONST))
                              {
                                    isIndentableHeader = false;
                              }
                              else
                              {
                                    isIndentableHeader = false;
                                    probationHeader = newHeader;
                              }
                        }
                        else if (newHeader == &AS_CONST)
                        {
                              isIndentableHeader = false;
                        }
                        else if (newHeader == &AS_TEMPLATE)
                        {
                              if (isCStyle)
                                    isInTemplate = true;
                              isIndentableHeader = false;
                        }


                        if (isIndentableHeader)
                        {
                              headerStack->push_back(newHeader);
                              isInStatement = false;
                              if (indexOf(nonParenHeaders, newHeader) == -1)
                              {
                                    isInConditional = true;
                              }
                              lastLineHeader = newHeader;
                        }
                        else
                              isInHeader = false;

                        outBuffer.append(newHeader->substr(1));
                        i += newHeader->length() - 1;

                        continue;
                  }
            }

            if (isCStyle && !isalpha(prevCh)
                    && line.compare(i, 8, "operator") == 0 && !isalnum(line[i+8]))
            {
                  isInOperator = true;
                  outBuffer.append(AS_OPERATOR.substr(1));
                  i += 7;
                  continue;
            }

            // "new" operator is a pointer, not a calculation
            if (!isalpha(prevCh)
                    && line.compare(i, 3, "new") == 0 && !isalnum(line[i+3]))
            {
                  if (prevNonSpaceCh == '=' && isInStatement && !inStatementIndentStack->empty())
                        inStatementIndentStack->back() = 0;
            }

            if (ch == '?')
                  isInQuestion = true;


            // special handling of 'case' statements
            if (ch == ':')
            {
                  if ((int) line.length() > i + 1 && line[i+1] == ':') // look for ::
                  {
                        ++i;
                        outBuffer.append(1, ':');
                        ch = ' ';
                        continue;
                  }

                  else if (isInQuestion)
                  {
                        isInQuestion = false;
                  }

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

                  else if (!isJavaStyle && isInClassHeader)
                  {
                        // found a 'class A : public B' definition
                        // so do nothing special
                  }

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

                  else if (isCStyle && prevNonSpaceCh == ')')
                  {
                        isInClassHeader = true;
                        if (i == 0)
                              tabCount += 2;
                  }
                  else
                  {
                        currentNonSpaceCh = ';'; // so that brackets after the ':' will appear as block-openers
                        if (isInCase)
                        {
                              isInCase = false;
                              ch = ';'; // from here on, treat char as ';'
                        }


                        else // is in a label (e.g. 'label1:')
                        {
                              if (labelIndent)
                                    --tabCount; // unindent label by one indent
                              else
                                    tabCount = 0; // completely flush indent to left
                        }



                  }
            }

            if ((ch == ';'  || (parenDepth > 0 && ch == ','))  && !inStatementIndentStackSizeStack->empty())
                  while ((int) inStatementIndentStackSizeStack->back() + (parenDepth > 0 ? 1 : 0)
                          < (int) inStatementIndentStack->size())
                        inStatementIndentStack->pop_back();


            // handle ends of statements
            if ((ch == ';' && parenDepth == 0) || ch == '}'/* || (ch == ',' && parenDepth == 0)*/)
            {
                  if (ch == '}')
                  {
                        // first check if this '}' closes a previous block, or a static array...
                        if (!bracketBlockStateStack->empty())
                        {
                              bool bracketBlockState = bracketBlockStateStack->back();
                              bracketBlockStateStack->pop_back();
                              if (!bracketBlockState)
                              {
                                    if (!inStatementIndentStackSizeStack->empty())
                                    {
                                          // this bracket is a static array

                                          int previousIndentStackSize = inStatementIndentStackSizeStack->back();
                                          inStatementIndentStackSizeStack->pop_back();
                                          while (previousIndentStackSize < (int) inStatementIndentStack->size())
                                                inStatementIndentStack->pop_back();
                                          parenDepth--;
                                          if (i == 0)
                                                shouldIndentBrackettedLine = false;

                                          if (!parenIndentStack->empty())
                                          {
                                                int poppedIndent = parenIndentStack->back();
                                                parenIndentStack->pop_back();
                                                if (i == 0)
                                                      spaceTabCount = poppedIndent;
                                          }
                                    }
                                    continue;
                              }
                        }

                        // this bracket is block closer...

                        ++lineClosingBlocksNum;

                        if (!inStatementIndentStackSizeStack->empty())
                              inStatementIndentStackSizeStack->pop_back();

                        if (!blockParenDepthStack->empty())
                        {
                              parenDepth = blockParenDepthStack->back();
                              blockParenDepthStack->pop_back();
                              isInStatement = blockStatementStack->back();
                              blockStatementStack->pop_back();

                              if (isInStatement)
                                    blockTabCount--;
                        }

                        closingBracketReached = true;
                        int headerPlace = indexOf(*headerStack, &AS_OPEN_BRACKET);
                        if (headerPlace != -1)
                        {
                              const string *popped = headerStack->back();
                              while (popped != &AS_OPEN_BRACKET)
                              {
                                    headerStack->pop_back();
                                    popped = headerStack->back();
                              }
                              headerStack->pop_back();

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


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

                  /*
                   * Create a temporary snapshot of the current block's header-list in the
                   * uppermost inner stack in tempStacks, and clear the headerStack up to
                   * the begining of the block.
                   * Thus, the next future statement will think it comes one indent past
                   * the block's '{' unless it specifically checks for a companion-header
                   * (such as a previous 'if' for an 'else' header) within the tempStacks,
                   * and recreates the temporary snapshot by manipulating the tempStacks.
                   */
                  if (!tempStacks->back()->empty())
                        while (!tempStacks->back()->empty())
                              tempStacks->back()->pop_back();
                  while (!headerStack->empty() && headerStack->back() != &AS_OPEN_BRACKET)
                  {
                        tempStacks->back()->push_back(headerStack->back());
                        headerStack->pop_back();
                  }

                  if (parenDepth == 0 && ch == ';')
                        isInStatement = false;

                  previousLastLineHeader = NULL;
                  isInClassHeader = false;
                  isInQuestion = false;

                  continue;
            }


            // check for preBlockStatements ONLY if not within parenthesies
            // (otherwise 'struct XXX' statements would be wrongly interpreted...)
            if (isWhiteSpace(prevCh) && !isInTemplate && parenDepth == 0)
            {
                  const string *newHeader = findHeader(line, i, preBlockStatements);
                  if (newHeader != NULL)
                  {
                        isInClassHeader = true;
                        outBuffer.append(newHeader->substr(1));
                        i += newHeader->length() - 1;
                        headerStack->push_back(newHeader);
                  }
            }

            // Handle operators

            immediatelyPreviousAssignmentOp = NULL;

            // Check if an operator has been reached.
            const string *foundAssignmentOp = findHeader(line, i, assignmentOperators, false);
            if (foundAssignmentOp == &AS_RETURN)
                  foundAssignmentOp = findHeader(line, i, assignmentOperators, true);
            const string *foundNonAssignmentOp = findHeader(line, i, nonAssignmentOperators, false);

            // Since findHeader's boundry checking was not used above, it is possible
            // that both an assignment op and a non-assignment op where found,
            // e.g. '>>' and '>>='. If this is the case, treat the LONGER one as the
            // found operator.
            if (foundAssignmentOp != NULL && foundNonAssignmentOp != NULL)
                  if (foundAssignmentOp->length() < foundNonAssignmentOp->length())
                        foundAssignmentOp = NULL;
                  else
                        foundNonAssignmentOp = NULL;

            if (foundNonAssignmentOp != NULL)
            {
                  if (foundNonAssignmentOp->length() > 1)
                  {
                        outBuffer.append(foundNonAssignmentOp->substr(1));
                        i += foundNonAssignmentOp->length() - 1;
                  }
            }

            else if (foundAssignmentOp != NULL)
            {
                  if (foundAssignmentOp->length() > 1)
                  {
                        outBuffer.append(foundAssignmentOp->substr(1));
                        i += foundAssignmentOp->length() - 1;
                  }

                  if (!isInOperator && !isInTemplate && !isNonInStatementArray)
                  {
                        registerInStatementIndent(line, i, spaceTabCount, 0, false);
                        immediatelyPreviousAssignmentOp = foundAssignmentOp;
                        isInStatement = true;
                  }
            }

            if (isInOperator)
                  isInOperator = false;
      }

      // handle special cases of unindentation:

      /*
       * if '{' doesn't follow an immediately previous '{' in the headerStack
       * (but rather another header such as "for" or "if", then unindent it
       * by one indentation relative to its block.
       */

      if (!lineStartsInComment
              && !blockIndent
              && outBuffer.length() > 0
              && outBuffer[0] == '{'
              && !(lineOpeningBlocksNum > 0 && lineOpeningBlocksNum == lineClosingBlocksNum)
              && !(headerStack->size() > 1 && (*headerStack)[headerStack->size()-2] == &AS_OPEN_BRACKET)
              && shouldIndentBrackettedLine)
            --tabCount;

      else if (!lineStartsInComment
               && outBuffer.length() > 0
               && outBuffer[0] == '}'
               && shouldIndentBrackettedLine)
            --tabCount;

      // correctly indent one-line-blocks...
      else if (!lineStartsInComment
               && outBuffer.length() > 0
               && lineOpeningBlocksNum > 0
               && lineOpeningBlocksNum == lineClosingBlocksNum
               && previousLineProbationTab)
            --tabCount; //lineOpeningBlocksNum - (blockIndent ? 1 : 0);

      if (tabCount < 0)
            tabCount = 0;

      // take care of extra bracket indentatation option...
      if (bracketIndent && outBuffer.length() > 0 && shouldIndentBrackettedLine)
            if (outBuffer[0] == '{' || outBuffer[0] == '}')
                  tabCount++;


      if (isInDefine)
      {
            if (outBuffer[0] == '#')
            {
                  string preproc = trim(string(outBuffer.c_str() + 1));
                  if (preproc.compare(0, 6, "define") == 0)
                  {
                        if (!inStatementIndentStack->empty()
                                && inStatementIndentStack->back() > 0)
                        {
                              defineTabCount = tabCount;
                        }
                        else
                        {
                              defineTabCount = tabCount - 1;
                              tabCount--;
                        }
                  }
            }

            tabCount -= defineTabCount;
      }

      if (tabCount < 0)
            tabCount = 0;
      if (lineCommentNoBeautify || blockCommentNoBeautify)
            tabCount = spaceTabCount = 0;

      // finally, insert indentations into begining of line

      prevFinalLineSpaceTabCount = spaceTabCount;
      prevFinalLineTabCount = tabCount;

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

      outBuffer = preLineWS(spaceTabCount, tabCount) + outBuffer;

      if (lastLineHeader != NULL)
            previousLastLineHeader = lastLineHeader;

      return outBuffer;
}


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

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

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

      return ws;

}

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

      // if indent is around the last char in the line, indent instead 2 spaces from the previous indent
      if (nextNonWSChar == remainingCharNum)
      {
            int previousIndent = spaceTabCount;
            if (!inStatementIndentStack->empty())
                  previousIndent = inStatementIndentStack->back();

            inStatementIndentStack->push_back(/*2*/ indentLength + previousIndent);
            if (updateParenStack)
                  parenIndentStack->push_back(previousIndent);
            return;
      }

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

      inStatementIndent = i + nextNonWSChar + spaceTabCount;

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

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

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

      if (isNonInStatementArray)
            inStatementIndent = 0;

      inStatementIndentStack->push_back(inStatementIndent);
}

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

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

      return charDistance;
}


/**
 * check if a specific line position contains a header, out of several possible headers.
 *
 * @return    a pointer to the found header. if no header was found then return NULL.
 */
const string *ASBeautifier::findHeader(const string &line, int i, const vector<const string*> &possibleHeaders, bool checkBoundry)
{
      int maxHeaders = possibleHeaders.size();
      // const string *header = NULL;
      int p;

      for (p = 0; p < maxHeaders; p++)
      {
            const string *header = possibleHeaders[p];

            if (line.compare(i, header->length(), header->c_str()) == 0)
            {
                  // check that this is a header and not a part of a longer word
                  // (e.g. not at its begining, not at its middle...)

                  int lineLength = line.length();
                  int headerEnd = i + header->length();
                  char startCh = (*header)[0];   // first char of header
                  char endCh = 0;                // char just after header
                  char prevCh = 0;               // char just before header

                  if (headerEnd < lineLength)
                  {
                        endCh = line[headerEnd];
                  }
                  if (i > 0)
                  {
                        prevCh = line[i-1];
                  }

                  if (!checkBoundry)
                  {
                        return header;
                  }
                  else if (prevCh != 0
                           && isLegalNameChar(startCh)
                           && isLegalNameChar(prevCh))
                  {
                        return NULL;
                  }
                  else if (headerEnd >= lineLength
                           || !isLegalNameChar(startCh)
                           || !isLegalNameChar(endCh))
                  {
                        return header;
                  }
                  else
                  {
                        return NULL;
                  }
            }
      }

      return NULL;
}

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

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

/**
 * trim removes the white space surrounding a line.
 *
 * @return          the trimmed line.
 * @param str       the line to trim.
 */
string ASBeautifier::trim(const string &str)
{

      int start = 0;
      int end = str.length() - 1;

      while (start < end && isWhiteSpace(str[start]))
            start++;

      while (start <= end && isWhiteSpace(str[end]))
            end--;

      string returnStr(str, start, end + 1 - start);
      return returnStr;
}

/**
* peek at the next unread character.
*
* @return         the next unread character.
* @param line   the line to check.
* @param i      the current char position on the line.
*/
char ASBeautifier::peekNextChar(string &line, int i)
{
      char ch = ' ';
      size_t peekNum = line.find_first_not_of(" \t", i + 1);

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

      ch = line[peekNum];

      return ch;
}


}   // end namespace astyle


Generated by  Doxygen 1.6.0   Back to index