File indexing completed on 2024-04-21 04:36:09

0001 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
0002  *
0003  *   Copyright (C) 2006-2010 by Jim Pattee <jimp03@email.com>
0004  *   Copyright (C) 1998-2002 by Tal Davidson
0005  *   <http://www.gnu.org/licenses/lgpl-3.0.html>
0006  *
0007  *   This file is a part of Artistic Style - an indentation and
0008  *   reformatting tool for C, C++, C# and Java source files.
0009  *   <http://astyle.sourceforge.net>
0010  *
0011  *   Artistic Style is free software: you can redistribute it and/or modify
0012  *   it under the terms of the GNU Lesser General Public License as published
0013  *   by the Free Software Foundation, either version 3 of the License, or
0014  *   (at your option) any later version.
0015  *
0016  *   Artistic Style is distributed in the hope that it will be useful,
0017  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
0018  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0019  *   GNU Lesser General Public License for more details.
0020  *
0021  *   You should have received a copy of the GNU Lesser General Public License
0022  *   along with Artistic Style.  If not, see <http://www.gnu.org/licenses/>.
0023  *
0024  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
0025  */
0026 
0027 #include "astyle.h"
0028 
0029 #include <algorithm>
0030 #include <iostream>
0031 
0032 
0033 namespace astyle
0034 {
0035 // static member variables
0036 int ASBeautifier::beautifierFileType = 9;       // initialized with an invalid type
0037 vector<const string*>* ASBeautifier::headers = NULL;
0038 vector<const string*>* ASBeautifier::nonParenHeaders = NULL;
0039 vector<const string*>* ASBeautifier::preBlockStatements;
0040 vector<const string*>* ASBeautifier::assignmentOperators = NULL;
0041 vector<const string*>* ASBeautifier::nonAssignmentOperators;
0042 vector<const string*>* ASBeautifier::indentableHeaders;
0043 
0044 
0045 /**
0046  * ASBeautifier's constructor
0047  */
0048 ASBeautifier::ASBeautifier()
0049 {
0050     waitingBeautifierStack = NULL;
0051     activeBeautifierStack = NULL;
0052     waitingBeautifierStackLengthStack = NULL;
0053     activeBeautifierStackLengthStack = NULL;
0054 
0055     headerStack  = NULL;
0056     tempStacks = NULL;
0057     blockParenDepthStack = NULL;
0058     blockStatementStack = NULL;
0059     parenStatementStack = NULL;
0060     bracketBlockStateStack = NULL;
0061     inStatementIndentStack = NULL;
0062     inStatementIndentStackSizeStack = NULL;
0063     parenIndentStack = NULL;
0064     sourceIterator = NULL;
0065     isIndentManuallySet = false;
0066     isMinConditionalManuallySet = false;
0067     isModeManuallySet = false;
0068     shouldForceTabIndentation = false;
0069     setSpaceIndentation(4);             // also sets minConditionalIndent
0070     setMaxInStatementIndentLength(40);
0071     classInitializerTabs = 1;
0072     setClassIndent(false);
0073     setSwitchIndent(false);
0074     setCaseIndent(false);
0075     setBlockIndent(false);
0076     setBracketIndent(false);
0077     setNamespaceIndent(false);
0078     setLabelIndent(false);
0079     setEmptyLineFill(false);
0080     setCStyle();
0081     setPreprocessorIndent(false);
0082 
0083     // initialize ASBeautifier static member vectors
0084     beautifierFileType = 9;     // reset to an invalid type
0085     initVector(headers);
0086     initVector(nonParenHeaders);
0087     initVector(assignmentOperators);
0088     initVector(nonAssignmentOperators);
0089     initVector(preBlockStatements);
0090     initVector(indentableHeaders);
0091 }
0092 
0093 /**
0094  * ASBeautifier's copy constructor
0095  * must explicitly call the base class copy constructor
0096  */
0097 ASBeautifier::ASBeautifier(const ASBeautifier &other) : ASBase(other)
0098 {
0099     // these don't need to copy the stack
0100     waitingBeautifierStack = NULL;
0101     activeBeautifierStack = NULL;
0102     waitingBeautifierStackLengthStack = NULL;
0103     activeBeautifierStackLengthStack = NULL;
0104 
0105     // vector '=' operator performs a DEEP copy of all elements in the vector
0106 
0107     headerStack  = new vector<const string*>;
0108     *headerStack = *other.headerStack;
0109 
0110     //tempStacks = new vector<vector<const string*>*>;
0111     //vector<vector<const string*>*>::iterator iter;
0112     //for (iter = other.tempStacks->begin();
0113     //        iter != other.tempStacks->end();
0114     //        ++iter)
0115     //{
0116     //  vector<const string*> *newVec = new vector<const string*>;
0117     //  *newVec = **iter;
0118     //  tempStacks->push_back(newVec);
0119     //}
0120     tempStacks = copyTempStacks(other);
0121 
0122     blockParenDepthStack = new vector<int>;
0123     *blockParenDepthStack = *other.blockParenDepthStack;
0124 
0125     blockStatementStack = new vector<bool>;
0126     *blockStatementStack = *other.blockStatementStack;
0127 
0128     parenStatementStack =  new vector<bool>;
0129     *parenStatementStack = *other.parenStatementStack;
0130 
0131     bracketBlockStateStack = new vector<bool>;
0132     *bracketBlockStateStack = *other.bracketBlockStateStack;
0133 
0134     inStatementIndentStack = new vector<int>;
0135     *inStatementIndentStack = *other.inStatementIndentStack;
0136 
0137     inStatementIndentStackSizeStack = new vector<int>;
0138     *inStatementIndentStackSizeStack = *other.inStatementIndentStackSizeStack;
0139 
0140     parenIndentStack = new vector<int>;
0141     *parenIndentStack = *other.parenIndentStack;
0142 
0143     sourceIterator = other.sourceIterator;
0144 
0145     // protected variables
0146     // variables set by ASFormatter
0147     // must also be updated in activeBeautifierStack
0148     inLineNumber = other.inLineNumber;
0149     horstmannIndentInStatement = other.horstmannIndentInStatement;
0150     nonInStatementBracket = other.nonInStatementBracket;
0151     lineCommentNoBeautify = other.lineCommentNoBeautify;
0152     isNonInStatementArray = other.isNonInStatementArray;
0153     isSharpAccessor = other.isSharpAccessor;
0154     isSharpDelegate = other.isSharpDelegate;
0155     isInExtern = other.isInExtern;
0156     isInBeautifySQL = other.isInBeautifySQL;
0157     isInIndentableStruct = other.isInIndentableStruct;
0158 
0159     // private variables
0160     indentString = other.indentString;
0161     currentHeader = other.currentHeader;
0162     previousLastLineHeader = other.previousLastLineHeader;
0163     probationHeader = other.probationHeader;
0164     isInQuote = other.isInQuote;
0165     isInVerbatimQuote = other.isInVerbatimQuote;
0166     haveLineContinuationChar = other.haveLineContinuationChar;
0167     isInAsm = other.isInAsm;
0168     isInAsmOneLine = other.isInAsmOneLine;
0169     isInAsmBlock = other.isInAsmBlock;
0170     isInComment = other.isInComment;
0171     isInHorstmannComment = other.isInHorstmannComment;
0172     isInCase = other.isInCase;
0173     isInQuestion = other.isInQuestion;
0174     isInStatement = other.isInStatement;
0175     isInHeader = other.isInHeader;
0176     isInTemplate = other.isInTemplate;
0177     isInDefine = other.isInDefine;
0178     isInDefineDefinition = other.isInDefineDefinition;
0179     classIndent = other.classIndent;
0180     isInClassInitializer = other.isInClassInitializer;
0181     isInClassHeaderTab = other.isInClassHeaderTab;
0182     isInEnum = other.isInEnum;
0183     switchIndent = other.switchIndent;
0184     caseIndent = other.caseIndent;
0185     namespaceIndent = other.namespaceIndent;
0186     bracketIndent = other.bracketIndent;
0187     blockIndent = other.blockIndent;
0188     labelIndent = other.labelIndent;
0189     preprocessorIndent = other.preprocessorIndent;
0190     isInConditional = other.isInConditional;
0191     isIndentManuallySet = other.isIndentManuallySet;
0192     isMinConditionalManuallySet = other.isMinConditionalManuallySet;
0193     isModeManuallySet = other.isModeManuallySet;
0194     shouldForceTabIndentation = other.shouldForceTabIndentation;
0195     emptyLineFill = other.emptyLineFill;
0196     lineOpensComment = other.lineOpensComment;
0197     backslashEndsPrevLine = other.backslashEndsPrevLine;
0198     blockCommentNoIndent = other.blockCommentNoIndent;
0199     blockCommentNoBeautify = other.blockCommentNoBeautify;
0200     previousLineProbationTab = other.previousLineProbationTab;
0201     fileType = other.fileType;
0202     minConditionalIndent = other.minConditionalIndent;
0203     parenDepth = other.parenDepth;
0204     indentLength = other.indentLength;
0205     blockTabCount = other.blockTabCount;
0206     maxInStatementIndent = other.maxInStatementIndent;
0207     classInitializerTabs = other.classInitializerTabs;
0208     templateDepth = other.templateDepth;
0209     prevFinalLineSpaceTabCount = other.prevFinalLineSpaceTabCount;
0210     prevFinalLineTabCount = other.prevFinalLineTabCount;
0211     defineTabCount = other.defineTabCount;
0212     quoteChar = other.quoteChar;
0213     prevNonSpaceCh = other.prevNonSpaceCh;
0214     currentNonSpaceCh = other.currentNonSpaceCh;
0215     currentNonLegalCh = other.currentNonLegalCh;
0216     prevNonLegalCh = other.prevNonLegalCh;
0217 }
0218 
0219 /**
0220  * ASBeautifier's destructor
0221  */
0222 ASBeautifier::~ASBeautifier()
0223 {
0224     deleteContainer(waitingBeautifierStack);
0225     deleteContainer(activeBeautifierStack);
0226     deleteContainer(waitingBeautifierStackLengthStack);
0227     deleteContainer(activeBeautifierStackLengthStack);
0228     deleteContainer(headerStack);
0229     deleteContainer(tempStacks);
0230     deleteContainer(blockParenDepthStack);
0231     deleteContainer(blockStatementStack);
0232     deleteContainer(parenStatementStack);
0233     deleteContainer(bracketBlockStateStack);
0234     deleteContainer(inStatementIndentStack);
0235     deleteContainer(inStatementIndentStackSizeStack);
0236     deleteContainer(parenIndentStack);
0237 }
0238 
0239 /**
0240  * initialize the ASBeautifier.
0241  *
0242  * init() should be called every time a ABeautifier object is to start
0243  * beautifying a NEW source file.
0244  * init() recieves a pointer to a ASSourceIterator object that will be
0245  * used to iterate through the source code.
0246  *
0247  * @param iter     a pointer to the ASSourceIterator or ASStreamIterator object.
0248  */
0249 void ASBeautifier::init(ASSourceIterator *iter)
0250 {
0251     sourceIterator = iter;
0252     init();
0253 }
0254 
0255 /**
0256  * initialize the ASBeautifier.
0257  */
0258 void ASBeautifier::init()
0259 {
0260     initStatic();
0261     ASBase::init(getFileType());
0262 
0263     initContainer(waitingBeautifierStack, new vector<ASBeautifier*>);
0264     initContainer(activeBeautifierStack, new vector<ASBeautifier*>);
0265 
0266     initContainer(waitingBeautifierStackLengthStack, new vector<int>);
0267     initContainer(activeBeautifierStackLengthStack, new vector<int>);
0268 
0269     initContainer(headerStack,  new vector<const string*>);
0270 
0271     initContainer(tempStacks, new vector<vector<const string*>*>);
0272     tempStacks->push_back(new vector<const string*>);
0273 
0274     initContainer(blockParenDepthStack, new vector<int>);
0275     initContainer(blockStatementStack, new vector<bool>);
0276     initContainer(parenStatementStack, new vector<bool>);
0277 
0278     initContainer(bracketBlockStateStack, new vector<bool>);
0279     bracketBlockStateStack->push_back(true);
0280 
0281     initContainer(inStatementIndentStack, new vector<int>);
0282     initContainer(inStatementIndentStackSizeStack, new vector<int>);
0283     inStatementIndentStackSizeStack->push_back(0);
0284     initContainer(parenIndentStack, new vector<int>);
0285 
0286     previousLastLineHeader = NULL;
0287     currentHeader = NULL;
0288 
0289     isInQuote = false;
0290     isInVerbatimQuote = false;
0291     haveLineContinuationChar = false;
0292     isInAsm = false;
0293     isInAsmOneLine = false;
0294     isInAsmBlock = false;
0295     isInComment = false;
0296     isInHorstmannComment = false;
0297     isInStatement = false;
0298     isInCase = false;
0299     isInQuestion = false;
0300     isInClassInitializer = false;
0301     isInClassHeaderTab = false;
0302     isInEnum = false;
0303     isInHeader = false;
0304     isInTemplate = false;
0305     isInConditional = false;
0306 
0307     templateDepth = 0;
0308     parenDepth = 0;
0309     blockTabCount = 0;
0310     prevNonSpaceCh = '{';
0311     currentNonSpaceCh = '{';
0312     prevNonLegalCh = '{';
0313     currentNonLegalCh = '{';
0314     quoteChar = ' ';
0315     prevFinalLineSpaceTabCount = 0;
0316     prevFinalLineTabCount = 0;
0317     probationHeader = NULL;
0318     backslashEndsPrevLine = false;
0319     lineOpensComment = false;
0320     isInDefine = false;
0321     isInDefineDefinition = false;
0322     defineTabCount = 0;
0323     lineCommentNoBeautify = false;
0324     blockCommentNoIndent = false;
0325     blockCommentNoBeautify = false;
0326     previousLineProbationTab = false;
0327     isNonInStatementArray = false;
0328     isSharpAccessor = false;
0329     isSharpDelegate = false;
0330     isInExtern = false;
0331     isInBeautifySQL = false;
0332     isInIndentableStruct = false;
0333     inLineNumber = 0;
0334     horstmannIndentInStatement = 0;
0335     nonInStatementBracket = 0;
0336 }
0337 
0338 /*
0339  * initialize the static vars
0340  */
0341 void ASBeautifier::initStatic()
0342 {
0343     if (fileType == beautifierFileType)    // don't build unless necessary
0344         return;
0345 
0346     beautifierFileType = fileType;
0347 
0348     headers->clear();
0349     nonParenHeaders->clear();
0350     assignmentOperators->clear();
0351     nonAssignmentOperators->clear();
0352     preBlockStatements->clear();
0353     indentableHeaders->clear();
0354 
0355     ASResource::buildHeaders(headers, fileType, true);
0356     ASResource::buildNonParenHeaders(nonParenHeaders, fileType, true);
0357     ASResource::buildAssignmentOperators(assignmentOperators);
0358     ASResource::buildNonAssignmentOperators(nonAssignmentOperators);
0359     ASResource::buildPreBlockStatements(preBlockStatements, fileType);
0360     ASResource::buildIndentableHeaders(indentableHeaders);
0361 }
0362 
0363 /**
0364  * set indentation style to C/C++.
0365  */
0366 void ASBeautifier::setCStyle()
0367 {
0368     fileType = C_TYPE;
0369 }
0370 
0371 /**
0372  * set indentation style to Java.
0373  */
0374 void ASBeautifier::setJavaStyle()
0375 {
0376     fileType = JAVA_TYPE;
0377 }
0378 
0379 /**
0380  * set indentation style to C#.
0381  */
0382 void ASBeautifier::setSharpStyle()
0383 {
0384     fileType = SHARP_TYPE;
0385 }
0386 
0387 /**
0388  * set mode manually set flag
0389  */
0390 void ASBeautifier::setModeManuallySet(bool state)
0391 {
0392     isModeManuallySet = state;
0393 }
0394 
0395 /**
0396  * indent using one tab per indentation
0397  */
0398 void ASBeautifier::setTabIndentation(int length, bool forceTabs)
0399 {
0400     indentString = "\t";
0401     indentLength = length;
0402     shouldForceTabIndentation = forceTabs;
0403 
0404     if (!isMinConditionalManuallySet)
0405         minConditionalIndent = indentLength * 2;
0406 }
0407 
0408 /**
0409  * indent using a number of spaces per indentation.
0410  *
0411  * @param   length     number of spaces per indent.
0412  */
0413 void ASBeautifier::setSpaceIndentation(int length)
0414 {
0415     indentString = string(length, ' ');
0416     indentLength = length;
0417 
0418     if (!isMinConditionalManuallySet)
0419         minConditionalIndent = indentLength * 2;
0420 }
0421 
0422 /**
0423  * set indent manually set flag
0424  */
0425 void ASBeautifier::setIndentManuallySet(bool state)
0426 {
0427     isIndentManuallySet = state;
0428 }
0429 
0430 /**
0431  * set the maximum indentation between two lines in a multi-line statement.
0432  *
0433  * @param   max     maximum indentation length.
0434  */
0435 void ASBeautifier::setMaxInStatementIndentLength(int max)
0436 {
0437     maxInStatementIndent = max;
0438 }
0439 
0440 /**
0441  * set the minimum indentation between two lines in a multi-line condition.
0442  *
0443  * @param   min     minimal indentation length.
0444  */
0445 void ASBeautifier::setMinConditionalIndentLength(int min)
0446 {
0447     minConditionalIndent = min;
0448 }
0449 
0450 /**
0451  * set min conditional manually set flag
0452  */
0453 void ASBeautifier::setMinConditionalManuallySet(bool state)
0454 {
0455     isMinConditionalManuallySet = state;
0456 }
0457 
0458 /**
0459  * set the state of the bracket indentation option. If true, brackets will
0460  * be indented one additional indent.
0461  *
0462  * @param   state             state of option.
0463  */
0464 void ASBeautifier::setBracketIndent(bool state)
0465 {
0466     bracketIndent = state;
0467 }
0468 
0469 /**
0470  * set the state of the block indentation option. If true, entire blocks
0471  * will be indented one additional indent, similar to the GNU indent style.
0472  *
0473  * @param   state             state of option.
0474  */
0475 void ASBeautifier::setBlockIndent(bool state)
0476 {
0477     blockIndent = state;
0478 }
0479 
0480 /**
0481  * set the state of the class indentation option. If true, C++ class
0482  * definitions will be indented one additional indent.
0483  *
0484  * @param   state             state of option.
0485  */
0486 void ASBeautifier::setClassIndent(bool state)
0487 {
0488     classIndent = state;
0489 }
0490 
0491 /**
0492  * set the state of the switch indentation option. If true, blocks of 'switch'
0493  * statements will be indented one additional indent.
0494  *
0495  * @param   state             state of option.
0496  */
0497 void ASBeautifier::setSwitchIndent(bool state)
0498 {
0499     switchIndent = state;
0500 }
0501 
0502 /**
0503  * set the state of the case indentation option. If true, lines of 'case'
0504  * statements will be indented one additional indent.
0505  *
0506  * @param   state             state of option.
0507  */
0508 void ASBeautifier::setCaseIndent(bool state)
0509 {
0510     caseIndent = state;
0511 }
0512 
0513 /**
0514  * set the state of the namespace indentation option.
0515  * If true, blocks of 'namespace' statements will be indented one
0516  * additional indent. Otherwise, NO indentation will be added.
0517  *
0518  * @param   state             state of option.
0519  */
0520 void ASBeautifier::setNamespaceIndent(bool state)
0521 {
0522     namespaceIndent = state;
0523 }
0524 
0525 /**
0526  * set the state of the label indentation option.
0527  * If true, labels will be indented one indent LESS than the
0528  * current indentation level.
0529  * If false, labels will be flushed to the left with NO
0530  * indent at all.
0531  *
0532  * @param   state             state of option.
0533  */
0534 void ASBeautifier::setLabelIndent(bool state)
0535 {
0536     labelIndent = state;
0537 }
0538 
0539 /**
0540  * set the state of the preprocessor indentation option.
0541  * If true, multiline #define statements will be indented.
0542  *
0543  * @param   state             state of option.
0544  */
0545 void ASBeautifier::setPreprocessorIndent(bool state)
0546 {
0547     preprocessorIndent = state;
0548 }
0549 
0550 /**
0551  * set the state of the empty line fill option.
0552  * If true, empty lines will be filled with the whitespace.
0553  * of their previous lines.
0554  * If false, these lines will remain empty.
0555  *
0556  * @param   state             state of option.
0557  */
0558 void ASBeautifier::setEmptyLineFill(bool state)
0559 {
0560     emptyLineFill = state;
0561 }
0562 
0563 /**
0564  * get the file type.
0565  */
0566 int ASBeautifier::getFileType()
0567 {
0568     return fileType;
0569 }
0570 
0571 /**
0572  * get the number of spaces per indent
0573  *
0574  * @return   value of indentLength option.
0575  */
0576 int ASBeautifier::getIndentLength(void)
0577 {
0578     return indentLength;
0579 }
0580 
0581 /**
0582  * get the char used for indentation, space or tab
0583  *
0584  * @return   the char used for indentation.
0585  */
0586 string ASBeautifier::getIndentString(void)
0587 {
0588     return indentString;
0589 }
0590 
0591 /**
0592  * get indent manually set flag
0593  */
0594 bool ASBeautifier::getIndentManuallySet()
0595 {
0596     return isIndentManuallySet;
0597 }
0598 
0599 /**
0600  * get the state of the isMinConditionalManuallySet flag
0601  *
0602  * @return   the state of isMinConditionalManuallySet.
0603  */
0604 bool ASBeautifier::getMinConditionalManuallySet()
0605 {
0606     return isMinConditionalManuallySet;
0607 }
0608 
0609 /**
0610  * get mode manually set flag
0611  */
0612 bool ASBeautifier::getModeManuallySet()
0613 {
0614     return isModeManuallySet;
0615 }
0616 
0617 /**
0618  * get the state of the force tab indentation option.
0619  *
0620  * @return   state of force tab indentation.
0621  */
0622 bool ASBeautifier::getForceTabIndentation(void)
0623 {
0624     return shouldForceTabIndentation;
0625 }
0626 
0627 /**
0628  * get the state of the block indentation option.
0629  *
0630  * @return   state of blockIndent option.
0631  */
0632 bool ASBeautifier::getBlockIndent(void)
0633 {
0634     return blockIndent;
0635 }
0636 
0637 /**
0638  * get the state of the bracket indentation option.
0639  *
0640  * @return   state of bracketIndent option.
0641  */
0642 bool ASBeautifier::getBracketIndent(void)
0643 {
0644     return bracketIndent;
0645 }
0646 
0647 /**
0648  * get the state of the class indentation option. If true, blocks of
0649  * the 'class' statement will be indented one additional indent.
0650  *
0651  * @return   state of classIndent option.
0652  */
0653 bool ASBeautifier::getClassIndent(void)
0654 {
0655     return classIndent;
0656 }
0657 
0658 /**
0659  * get the state of the switch indentation option. If true, blocks of
0660  * the 'switch' statement will be indented one additional indent.
0661  *
0662  * @return   state of switchIndent option.
0663  */
0664 bool ASBeautifier::getSwitchIndent(void)
0665 {
0666     return switchIndent;
0667 }
0668 
0669 /**
0670  * get the state of the case indentation option. If true, lines of 'case'
0671  * statements will be indented one additional indent.
0672  *
0673  * @return   state of caseIndent option.
0674  */
0675 bool ASBeautifier::getCaseIndent(void)
0676 {
0677     return caseIndent;
0678 }
0679 
0680 /**
0681  * get the state of the empty line fill option.
0682  * If true, empty lines will be filled with the whitespace.
0683  * of their previous lines.
0684  * If false, these lines will remain empty.
0685  *
0686  * @return   state of emptyLineFill option.
0687  */
0688 bool ASBeautifier::getEmptyLineFill(void)
0689 {
0690     return emptyLineFill;
0691 }
0692 
0693 /**
0694  * check if there are any indented lines ready to be read by nextLine()
0695  *
0696  * @return    are there any indented lines ready?
0697  */
0698 bool ASBeautifier::hasMoreLines() const
0699 {
0700     return sourceIterator->hasMoreLines();
0701 }
0702 
0703 /**
0704  * get the next indented line.
0705  *
0706  * @return    indented line.
0707  */
0708 string ASBeautifier::nextLine()
0709 {
0710     return beautify(sourceIterator->nextLine());
0711 }
0712 
0713 /**
0714  * beautify a line of source code.
0715  * every line of source code in a source code file should be sent
0716  * one after the other to the beautify method.
0717  *
0718  * @return      the indented line.
0719  * @param originalLine       the original unindented line.
0720  */
0721 string ASBeautifier::beautify(const string &originalLine)
0722 {
0723     string line;
0724     bool isInLineComment = false;
0725     bool lineStartsInComment = false;
0726     bool isInClass = false;
0727     bool isInSwitch = false;
0728     bool isInOperator = false;
0729     bool isSpecialChar = false;
0730     bool haveCaseIndent = false;
0731     bool haveAssignmentThisLine = false;
0732     bool lineBeginsWithBracket = false;
0733     bool closingBracketReached = false;
0734     bool shouldIndentBrackettedLine = true;
0735     bool previousLineProbation = (probationHeader != NULL);
0736     bool isInQuoteContinuation = isInVerbatimQuote | haveLineContinuationChar;
0737     char ch = ' ';
0738     char prevCh;
0739     char tempCh;
0740     int tabCount = 0;
0741     int spaceTabCount = 0;
0742     int lineOpeningBlocksNum = 0;
0743     int lineClosingBlocksNum = 0;
0744     int tabIncrementIn = 0;
0745     int i;
0746     int iPrelim;
0747     string outBuffer; // the newly idented line is buffered here
0748     const string *lastLineHeader = NULL;
0749 
0750     currentHeader = NULL;
0751     lineStartsInComment = isInComment;
0752     blockCommentNoBeautify = blockCommentNoIndent;
0753     isInAsmOneLine = false;
0754     lineOpensComment = false;
0755     previousLineProbationTab = false;
0756     haveLineContinuationChar = false;
0757 
0758     // handle and remove white spaces around the line:
0759     // If not in comment, first find out size of white space before line,
0760     // so that possible comments starting in the line continue in
0761     // relation to the preliminary white-space.
0762     if (isInQuoteContinuation)
0763     {
0764         // trim a single space added by ASFormatter, otherwise leave it alone
0765         if (!(originalLine.length() == 1 && originalLine[0] == ' '))
0766             line = originalLine;
0767     }
0768     else if (isInComment || isInBeautifySQL)
0769     {
0770         // trim the end of comment and SQL lines
0771         line = originalLine;
0772         size_t trimEnd = line.find_last_not_of(" \t");
0773         if (trimEnd == string::npos)
0774             trimEnd = 0;
0775         else
0776             trimEnd++;
0777         if (trimEnd < line.length())
0778             line.erase(trimEnd);
0779     }
0780     else
0781     {
0782         line = trim(originalLine);
0783         if (line.length() > 0 && line[0] == '{')
0784             lineBeginsWithBracket = true;
0785 
0786         isInHorstmannComment = false;
0787         size_t j = line.find_first_not_of(" \t{");
0788         if (j != string::npos && line.compare(j, 2, "/*") == 0)
0789         {
0790             lineOpensComment = true;
0791             size_t k = line.find_first_not_of(" \t");
0792             if (k != string::npos && line.compare(k, 1, "{") == 0)
0793                 isInHorstmannComment = true;
0794         }
0795     }
0796 
0797     if (line.length() == 0)
0798     {
0799         if (backslashEndsPrevLine)  // must continue to clear variables
0800             line = ' ';
0801         else if (emptyLineFill && !isInQuoteContinuation && headerStack->size() > 0)
0802             return preLineWS(prevFinalLineSpaceTabCount, prevFinalLineTabCount);
0803         else
0804             return line;
0805     }
0806 
0807     // handle preprocessor commands
0808     // except C# region and endregion
0809 
0810     if (!isInComment
0811             && (line[0] == '#' || backslashEndsPrevLine)
0812             && line.compare(0, 7, "#region") != 0
0813             && line.compare(0, 10, "#endregion") != 0)
0814     {
0815         if (line[0] == '#')
0816         {
0817             string preproc = trim(string(line.c_str() + 1));
0818 
0819             // When finding a multi-lined #define statement, the original beautifier
0820             // 1. sets its isInDefineDefinition flag
0821             // 2. clones a new beautifier that will be used for the actual indentation
0822             //    of the #define. This clone is put into the activeBeautifierStack in order
0823             //    to be called for the actual indentation.
0824             // The original beautifier will have isInDefineDefinition = true, isInDefine = false
0825             // The cloned beautifier will have   isInDefineDefinition = true, isInDefine = true
0826             if (preprocessorIndent && preproc.compare(0, 6, "define") == 0 && line[line.length() - 1] == '\\')
0827             {
0828                 if (!isInDefineDefinition)
0829                 {
0830                     ASBeautifier *defineBeautifier;
0831 
0832                     // this is the original beautifier
0833                     isInDefineDefinition = true;
0834 
0835                     // push a new beautifier into the active stack
0836                     // this beautifier will be used for the indentation of this define
0837                     defineBeautifier = new ASBeautifier(*this);
0838                     activeBeautifierStack->push_back(defineBeautifier);
0839                 }
0840                 else
0841                 {
0842                     // the is the cloned beautifier that is in charge of indenting the #define.
0843                     isInDefine = true;
0844                 }
0845             }
0846             else if (preproc.compare(0, 2, "if") == 0)
0847             {
0848                 // push a new beautifier into the stack
0849                 waitingBeautifierStackLengthStack->push_back(waitingBeautifierStack->size());
0850                 activeBeautifierStackLengthStack->push_back(activeBeautifierStack->size());
0851                 waitingBeautifierStack->push_back(new ASBeautifier(*this));
0852             }
0853             else if (preproc.compare(0, 4/*2*/, "else") == 0)
0854             {
0855                 if (waitingBeautifierStack && !waitingBeautifierStack->empty())
0856                 {
0857                     // MOVE current waiting beautifier to active stack.
0858                     activeBeautifierStack->push_back(waitingBeautifierStack->back());
0859                     waitingBeautifierStack->pop_back();
0860                 }
0861             }
0862             else if (preproc.compare(0, 4, "elif") == 0)
0863             {
0864                 if (waitingBeautifierStack && !waitingBeautifierStack->empty())
0865                 {
0866                     // append a COPY current waiting beautifier to active stack, WITHOUT deleting the original.
0867                     activeBeautifierStack->push_back(new ASBeautifier(*(waitingBeautifierStack->back())));
0868                 }
0869             }
0870             else if (preproc.compare(0, 5, "endif") == 0)
0871             {
0872                 int stackLength;
0873                 ASBeautifier *beautifier;
0874 
0875                 if (waitingBeautifierStackLengthStack && !waitingBeautifierStackLengthStack->empty())
0876                 {
0877                     stackLength = waitingBeautifierStackLengthStack->back();
0878                     waitingBeautifierStackLengthStack->pop_back();
0879                     while ((int) waitingBeautifierStack->size() > stackLength)
0880                     {
0881                         beautifier = waitingBeautifierStack->back();
0882                         waitingBeautifierStack->pop_back();
0883                         delete beautifier;
0884                     }
0885                 }
0886 
0887                 if (!activeBeautifierStackLengthStack->empty())
0888                 {
0889                     stackLength = activeBeautifierStackLengthStack->back();
0890                     activeBeautifierStackLengthStack->pop_back();
0891                     while ((int) activeBeautifierStack->size() > stackLength)
0892                     {
0893                         beautifier = activeBeautifierStack->back();
0894                         activeBeautifierStack->pop_back();
0895                         delete beautifier;
0896                     }
0897                 }
0898             }
0899         }
0900 
0901         // check if the last char is a backslash
0902         if (line.length() > 0)
0903             backslashEndsPrevLine = (line[line.length() - 1] == '\\');
0904         else
0905             backslashEndsPrevLine = false;
0906 
0907         // check if this line ends a multi-line #define
0908         // if so, use the #define's cloned beautifier for the line's indentation
0909         // and then remove it from the active beautifier stack and delete it.
0910         if (!backslashEndsPrevLine && isInDefineDefinition && !isInDefine)
0911         {
0912             string beautifiedLine;
0913             ASBeautifier *defineBeautifier;
0914 
0915             isInDefineDefinition = false;
0916             defineBeautifier = activeBeautifierStack->back();
0917             activeBeautifierStack->pop_back();
0918 
0919             beautifiedLine = defineBeautifier->beautify(line);
0920             delete defineBeautifier;
0921             return beautifiedLine;
0922         }
0923 
0924         // unless this is a multi-line #define, return this precompiler line as is.
0925         if (!isInDefine && !isInDefineDefinition)
0926             return originalLine;
0927     }
0928 
0929     // if there exists any worker beautifier in the activeBeautifierStack,
0930     // then use it instead of me to indent the current line.
0931     // variables set by ASFormatter must be updated.
0932     if (!isInDefine && activeBeautifierStack != NULL && !activeBeautifierStack->empty())
0933     {
0934         activeBeautifierStack->back()->inLineNumber = inLineNumber;
0935         activeBeautifierStack->back()->horstmannIndentInStatement = horstmannIndentInStatement;
0936         activeBeautifierStack->back()->nonInStatementBracket = nonInStatementBracket;
0937         activeBeautifierStack->back()->lineCommentNoBeautify = lineCommentNoBeautify;
0938         activeBeautifierStack->back()->isNonInStatementArray = isNonInStatementArray;
0939         activeBeautifierStack->back()->isSharpAccessor = isSharpAccessor;
0940         activeBeautifierStack->back()->isSharpDelegate = isSharpDelegate;
0941         activeBeautifierStack->back()->isInExtern = isInExtern;
0942         activeBeautifierStack->back()->isInBeautifySQL = isInBeautifySQL;
0943         activeBeautifierStack->back()->isInIndentableStruct = isInIndentableStruct;
0944         // must return originalLine not the trimmed line
0945         return activeBeautifierStack->back()->beautify(originalLine);
0946     }
0947 
0948     // calculate preliminary indentation based on data from past lines
0949 
0950     if (!inStatementIndentStack->empty())
0951         spaceTabCount = inStatementIndentStack->back();
0952 
0953     for (i = 0; i < (int) headerStack->size(); i++)
0954     {
0955         isInClass = false;
0956 
0957         if (blockIndent)
0958         {
0959             // do NOT indent opening block for these headers
0960             if (!((*headerStack)[i] == &AS_NAMESPACE
0961                     || (*headerStack)[i] == &AS_CLASS
0962                     || (*headerStack)[i] == &AS_STRUCT
0963                     || (*headerStack)[i] == &AS_UNION
0964                     || (*headerStack)[i] == &AS_CONST
0965                     || (*headerStack)[i] == &AS_INTERFACE
0966                     || (*headerStack)[i] == &AS_THROWS
0967                     || (*headerStack)[i] == &AS_STATIC))
0968                 ++tabCount;
0969         }
0970         else if (!(i > 0 && (*headerStack)[i-1] != &AS_OPEN_BRACKET
0971                    && (*headerStack)[i] == &AS_OPEN_BRACKET))
0972             ++tabCount;
0973 
0974         if (!isJavaStyle() && !namespaceIndent && i >= 1
0975                 && (*headerStack)[i-1] == &AS_NAMESPACE
0976                 && (*headerStack)[i] == &AS_OPEN_BRACKET)
0977             --tabCount;
0978 
0979         if (isCStyle() && i >= 1
0980                 && (*headerStack)[i-1] == &AS_CLASS
0981                 && (*headerStack)[i] == &AS_OPEN_BRACKET)
0982         {
0983             if (classIndent)
0984                 ++tabCount;
0985             isInClass = true;
0986         }
0987 
0988         // is the switchIndent option is on, indent switch statements an additional indent.
0989         else if (switchIndent && i > 1
0990                  && (*headerStack)[i-1] == &AS_SWITCH
0991                  && (*headerStack)[i] == &AS_OPEN_BRACKET)
0992         {
0993             ++tabCount;
0994             isInSwitch = true;
0995         }
0996 
0997     }   // end of for loop * end of for loop * end of for loop * end of for loop * end of for loop *
0998 
0999     iPrelim = i;
1000 
1001     if (!lineStartsInComment
1002             && isCStyle()
1003             && isInClass
1004             && classIndent
1005             && headerStack->size() >= 2
1006             && (*headerStack)[headerStack->size()-2] == &AS_CLASS
1007             && (*headerStack)[headerStack->size()-1] == &AS_OPEN_BRACKET
1008             && line[0] == '}'
1009             && bracketBlockStateStack->back() == true)
1010         --tabCount;
1011 
1012     else if (!lineStartsInComment
1013              && isInSwitch
1014              && switchIndent
1015              && headerStack->size() >= 2
1016              && (*headerStack)[headerStack->size()-2] == &AS_SWITCH
1017              && (*headerStack)[headerStack->size()-1] == &AS_OPEN_BRACKET
1018              && line[0] == '}')
1019         --tabCount;
1020 
1021     if (isInClassInitializer)
1022     {
1023         if (lineStartsInComment || lineOpensComment)
1024         {
1025             if (!lineBeginsWithBracket)
1026                 tabCount--;
1027         }
1028         else if (isCStyle() && !isClassAccessModifier(line))
1029         {
1030             isInClassHeaderTab = true;
1031             tabCount += classInitializerTabs;
1032         }
1033         else if (blockIndent)
1034         {
1035             if (!lineBeginsWithBracket)
1036                 tabCount++;
1037         }
1038     }
1039     // handle special case of indented horstmann brackets
1040     else if (lineStartsInComment && isInHorstmannComment && bracketIndent)
1041         tabCount++;
1042 
1043     // handle special case of horstmann comment in an indented class statement
1044     if (isInClass
1045             && classIndent
1046             && isInHorstmannComment
1047             && !lineOpensComment
1048             && headerStack->size() >= 2
1049             && (*headerStack)[headerStack->size()-2] == &AS_CLASS)
1050         --tabCount;
1051 
1052     if (isInConditional)
1053     {
1054         --tabCount;
1055     }
1056 
1057 
1058     // parse characters in the current line.
1059 
1060     for (i = 0; i < (int) line.length(); i++)
1061     {
1062         outBuffer.append(1, line[i]);
1063 
1064         tempCh = line[i];
1065         prevCh = ch;
1066         ch = tempCh;
1067 
1068         if (isInBeautifySQL)
1069             continue;
1070 
1071         if (isWhiteSpace(ch))
1072         {
1073             if (ch == '\t')
1074                 tabIncrementIn += convertTabToSpaces(i, tabIncrementIn);
1075             continue;
1076         }
1077 
1078         // handle special characters (i.e. backslash+character such as \n, \t, ...)
1079 
1080         if (isInQuote && !isInVerbatimQuote)
1081         {
1082             if (isSpecialChar)
1083             {
1084                 isSpecialChar = false;
1085                 continue;
1086             }
1087             if (line.compare(i, 2, "\\\\") == 0)
1088             {
1089                 outBuffer.append(1, '\\');
1090                 i++;
1091                 continue;
1092             }
1093             if (ch == '\\')
1094             {
1095                 if (peekNextChar(line, i) == ' ')   // is this '\' at end of line
1096                     haveLineContinuationChar = true;
1097                 else
1098                     isSpecialChar = true;
1099                 continue;
1100             }
1101         }
1102         else if (isInDefine && ch == '\\')
1103             continue;
1104 
1105         // handle quotes (such as 'x' and "Hello Dolly")
1106         if (!(isInComment || isInLineComment) && (ch == '"' || ch == '\''))
1107         {
1108             if (!isInQuote)
1109             {
1110                 quoteChar = ch;
1111                 isInQuote = true;
1112                 if (isSharpStyle() && prevCh == '@')
1113                     isInVerbatimQuote = true;
1114             }
1115             else if (isInVerbatimQuote && ch == '"')
1116             {
1117                 if (peekNextChar(line, i) == '"')           // check consecutive quotes
1118                 {
1119                     outBuffer.append(1, '"');
1120                     i++;
1121                 }
1122                 else
1123                 {
1124                     isInQuote = false;
1125                     isInVerbatimQuote = false;
1126                 }
1127             }
1128             else if (quoteChar == ch)
1129             {
1130                 isInQuote = false;
1131                 isInStatement = true;
1132                 continue;
1133             }
1134         }
1135         if (isInQuote)
1136             continue;
1137 
1138         // handle comments
1139 
1140         if (!(isInComment || isInLineComment) && line.compare(i, 2, "//") == 0)
1141         {
1142             isInLineComment = true;
1143             outBuffer.append(1, '/');
1144             i++;
1145             continue;
1146         }
1147         else if (!(isInComment || isInLineComment) && line.compare(i, 2, "/*") == 0)
1148         {
1149             isInComment = true;
1150             outBuffer.append(1, '*');
1151             i++;
1152             if (!lineOpensComment)                  // does line start with comment?
1153                 blockCommentNoIndent = true;        // if no, cannot indent continuation lines
1154             continue;
1155         }
1156         else if ((isInComment || isInLineComment) && line.compare(i, 2, "*/") == 0)
1157         {
1158             isInComment = false;
1159             outBuffer.append(1, '/');
1160             i++;
1161             blockCommentNoIndent = false;           // ok to indent next comment
1162             continue;
1163         }
1164         // treat C# '#region' and '#endregion' statements as a line comment
1165         else if (isSharpStyle() &&
1166                  (line.compare(i, 7, "#region") == 0 || line.compare(i, 10, "#endregion") == 0))
1167         {
1168             isInLineComment = true;
1169         }
1170 
1171         if (isInComment || isInLineComment)
1172         {
1173             // append rest of the comment up to the comment end
1174             while (i+1 < (int) line.length()
1175                     && line.compare(i+1, 2, "*/") != 0)
1176                 outBuffer.append(1, line[++i]);
1177             continue;
1178         }
1179 
1180         // if we have reached this far then we are NOT in a comment or string of special character...
1181 
1182         // SQL if formatted in ASEnhancer
1183         if (isInBeautifySQL)
1184             continue;
1185 
1186         if (probationHeader != NULL)
1187         {
1188             if (((probationHeader == &AS_STATIC || probationHeader == &AS_CONST) && ch == '{')
1189                     || (probationHeader == &AS_SYNCHRONIZED && ch == '('))
1190             {
1191                 // insert the probation header as a new header
1192                 isInHeader = true;
1193                 headerStack->push_back(probationHeader);
1194 
1195                 // handle the specific probation header
1196                 isInConditional = (probationHeader == &AS_SYNCHRONIZED);
1197 
1198                 isInStatement = false;
1199                 // if the probation comes from the previous line, then indent by 1 tab count.
1200                 if (previousLineProbation
1201                         && ch == '{'
1202                         && !(blockIndent
1203                              && (probationHeader == &AS_CONST || probationHeader == &AS_STATIC)))
1204                 {
1205                     tabCount++;
1206                     previousLineProbationTab = true;
1207                 }
1208                 previousLineProbation = false;
1209             }
1210 
1211             // dismiss the probation header
1212             probationHeader = NULL;
1213         }
1214 
1215         prevNonSpaceCh = currentNonSpaceCh;
1216         currentNonSpaceCh = ch;
1217         if (!isLegalNameChar(ch) && ch != ',' && ch != ';')
1218         {
1219             prevNonLegalCh = currentNonLegalCh;
1220             currentNonLegalCh = ch;
1221         }
1222 
1223         if (isInHeader)
1224         {
1225             isInHeader = false;
1226             currentHeader = headerStack->back();
1227         }
1228         else
1229             currentHeader = NULL;
1230 
1231         if (isCStyle() && isInTemplate
1232                 && (ch == '<' || ch == '>')
1233                 &&  findOperator(line, i, nonAssignmentOperators) == NULL)
1234         {
1235             if (ch == '<')
1236             {
1237                 ++templateDepth;
1238             }
1239             else if (ch == '>')
1240             {
1241                 if (--templateDepth <= 0)
1242                 {
1243                     if (isInTemplate)
1244                         ch = ';';
1245                     else
1246                         ch = 't';
1247                     isInTemplate = false;
1248                     templateDepth = 0;
1249                 }
1250             }
1251         }
1252 
1253         // handle parenthesies
1254         if (ch == '(' || ch == '[' || ch == ')' || ch == ']')
1255         {
1256             if (ch == '(' || ch == '[')
1257             {
1258                 isInOperator = false;
1259                 // if have a struct header, this is a declaration not a definition
1260                 if (ch == '('
1261                         && (isInClassInitializer || isInClassHeaderTab)
1262                         && headerStack->size() > 0
1263                         && headerStack->back() == &AS_STRUCT)
1264                 {
1265                     headerStack->pop_back();
1266                     isInClassInitializer = false;
1267                     // -1 for isInClassInitializer, -2 for isInClassHeaderTab
1268                     if (isInClassHeaderTab)
1269                     {
1270                         tabCount -= (1 + classInitializerTabs);
1271                         isInClassHeaderTab = false;
1272                     }
1273                     if (tabCount < 0)
1274                         tabCount = 0;
1275                 }
1276 
1277                 if (parenDepth == 0)
1278                 {
1279                     parenStatementStack->push_back(isInStatement);
1280                     isInStatement = true;
1281                 }
1282                 parenDepth++;
1283 
1284                 inStatementIndentStackSizeStack->push_back(inStatementIndentStack->size());
1285 
1286                 if (currentHeader != NULL)
1287                     registerInStatementIndent(line, i, spaceTabCount, tabIncrementIn, minConditionalIndent/*indentLength*2*/, true);
1288                 else
1289                     registerInStatementIndent(line, i, spaceTabCount, tabIncrementIn, 0, true);
1290             }
1291             else if (ch == ')' || ch == ']')
1292             {
1293                 parenDepth--;
1294                 if (parenDepth == 0)
1295                 {
1296                     if (!parenStatementStack->empty())      // in case of unmatched closing parens
1297                     {
1298                         isInStatement = parenStatementStack->back();
1299                         parenStatementStack->pop_back();
1300                     }
1301                     ch = ' ';
1302                     isInAsm = false;
1303                     isInConditional = false;
1304                 }
1305 
1306                 if (!inStatementIndentStackSizeStack->empty())
1307                 {
1308                     int previousIndentStackSize = inStatementIndentStackSizeStack->back();
1309                     inStatementIndentStackSizeStack->pop_back();
1310                     while (previousIndentStackSize < (int) inStatementIndentStack->size())
1311                         inStatementIndentStack->pop_back();
1312 
1313                     if (!parenIndentStack->empty())
1314                     {
1315                         int poppedIndent = parenIndentStack->back();
1316                         parenIndentStack->pop_back();
1317 
1318                         if (i == 0)
1319                             spaceTabCount = poppedIndent;
1320                     }
1321                 }
1322             }
1323 
1324             continue;
1325         }
1326 
1327 
1328         if (ch == '{')
1329         {
1330             // first, check if '{' is a block-opener or an static-array opener
1331             bool isBlockOpener = ((prevNonSpaceCh == '{' && bracketBlockStateStack->back())
1332                                   || prevNonSpaceCh == '}'
1333                                   || prevNonSpaceCh == ')'
1334                                   || prevNonSpaceCh == ';'
1335                                   || peekNextChar(line, i) == '{'
1336                                   || isInClassInitializer
1337                                   || isNonInStatementArray
1338                                   || isSharpAccessor
1339                                   || isSharpDelegate
1340                                   || isInExtern
1341                                   || (isInDefine &&
1342                                       (prevNonSpaceCh == '('
1343                                        || isLegalNameChar(prevNonSpaceCh))));
1344 
1345             // remove inStatementIndent for C++ class initializer
1346             if (isInClassInitializer)
1347             {
1348                 if (inStatementIndentStack->size() > 0)
1349                     inStatementIndentStack->pop_back();
1350                 isInStatement = false;
1351                 if (lineBeginsWithBracket)
1352                     spaceTabCount = 0;
1353                 isInClassInitializer = false;
1354             }
1355 
1356             if (!isBlockOpener && currentHeader != NULL)
1357             {
1358                 for (size_t n = 0; n < nonParenHeaders->size(); n++)
1359                     if (currentHeader == (*nonParenHeaders)[n])
1360                     {
1361                         isBlockOpener = true;
1362                         break;
1363                     }
1364             }
1365 
1366             bracketBlockStateStack->push_back(isBlockOpener);
1367 
1368             if (!isBlockOpener)
1369             {
1370                 inStatementIndentStackSizeStack->push_back(inStatementIndentStack->size());
1371                 registerInStatementIndent(line, i, spaceTabCount, tabIncrementIn, 0, true);
1372                 parenDepth++;
1373                 if (i == 0)
1374                     shouldIndentBrackettedLine = false;
1375 
1376                 continue;
1377             }
1378 
1379             // this bracket is a block opener...
1380 
1381             ++lineOpeningBlocksNum;
1382 
1383             if (isInClassHeaderTab)
1384             {
1385                 isInClassHeaderTab = false;
1386                 // decrease tab count if bracket is broken
1387                 size_t firstChar = line.find_first_not_of(" \t");
1388                 if (firstChar != string::npos
1389                         && line[firstChar] == '{'
1390                         && (int) firstChar == i)
1391                 {
1392                     tabCount -= classInitializerTabs;
1393                     // decrease one more if an empty class
1394                     if (headerStack->size() > 0
1395                             && (*headerStack).back() == &AS_CLASS)
1396                     {
1397                         int nextChar = getNextProgramCharDistance(line, i);
1398                         if (line[nextChar] == '}')
1399                             tabCount--;
1400                     }
1401                 }
1402             }
1403 
1404             if (bracketIndent && !namespaceIndent && headerStack->size() > 0
1405                     && (*headerStack).back() == &AS_NAMESPACE)
1406             {
1407                 shouldIndentBrackettedLine = false;
1408                 tabCount--;
1409             }
1410 
1411             // an indentable struct is treated like a class in the header stack
1412             if (headerStack->size() > 0
1413                     && (*headerStack).back() == &AS_STRUCT
1414                     && isInIndentableStruct)
1415                 (*headerStack).back() = &AS_CLASS;
1416 
1417             blockParenDepthStack->push_back(parenDepth);
1418             blockStatementStack->push_back(isInStatement);
1419 
1420             inStatementIndentStackSizeStack->push_back(inStatementIndentStack->size());
1421             if (inStatementIndentStack->size() > 0)
1422             {
1423                 spaceTabCount = 0;
1424                 inStatementIndentStack->back() = 0;
1425             }
1426 
1427             blockTabCount += isInStatement ? 1 : 0;
1428             parenDepth = 0;
1429             isInStatement = false;
1430 
1431             tempStacks->push_back(new vector<const string*>);
1432             headerStack->push_back(&AS_OPEN_BRACKET);
1433             lastLineHeader = &AS_OPEN_BRACKET;
1434 
1435             continue;
1436         }
1437 
1438         //check if a header has been reached
1439         bool isPotentialHeader = isCharPotentialHeader(line, i);
1440 
1441         if (isPotentialHeader)
1442         {
1443             const string *newHeader = findHeader(line, i, headers);
1444 
1445             if (newHeader != NULL)
1446             {
1447                 char peekChar = peekNextChar(line, i + newHeader->length() - 1);
1448 
1449                 // is not a header if part of a definition
1450                 if (peekChar == ',' || peekChar == ')')
1451                     newHeader = NULL;
1452                 // the following accessor definitions are NOT headers
1453                 // goto default; is NOT a header
1454                 // default(int) keyword in C# is NOT a header
1455                 else if ((newHeader == &AS_GET || newHeader == &AS_SET || newHeader == &AS_DEFAULT)
1456                          && (peekChar == ';' ||  peekChar == '('))
1457                 {
1458                     newHeader = NULL;
1459                 }
1460             }
1461 
1462             if (newHeader != NULL)
1463             {
1464                 // if we reached here, then this is a header...
1465                 bool isIndentableHeader = true;
1466 
1467                 isInHeader = true;
1468 
1469                 vector<const string*> *lastTempStack;
1470                 if (tempStacks->empty())
1471                     lastTempStack = NULL;
1472                 else
1473                     lastTempStack = tempStacks->back();
1474 
1475                 // if a new block is opened, push a new stack into tempStacks to hold the
1476                 // future list of headers in the new block.
1477 
1478                 // take care of the special case: 'else if (...)'
1479                 if (newHeader == &AS_IF && lastLineHeader == &AS_ELSE)
1480                 {
1481                     headerStack->pop_back();
1482                 }
1483 
1484                 // take care of 'else'
1485                 else if (newHeader == &AS_ELSE)
1486                 {
1487                     if (lastTempStack != NULL)
1488                     {
1489                         int indexOfIf = indexOf(*lastTempStack, &AS_IF);
1490                         if (indexOfIf != -1)
1491                         {
1492                             // recreate the header list in headerStack up to the previous 'if'
1493                             // from the temporary snapshot stored in lastTempStack.
1494                             int restackSize = lastTempStack->size() - indexOfIf - 1;
1495                             for (int r = 0; r < restackSize; r++)
1496                             {
1497                                 headerStack->push_back(lastTempStack->back());
1498                                 lastTempStack->pop_back();
1499                             }
1500                             if (!closingBracketReached)
1501                                 tabCount += restackSize;
1502                         }
1503                         /*
1504                          * If the above if is not true, i.e. no 'if' before the 'else',
1505                          * then nothing beautiful will come out of this...
1506                          * I should think about inserting an Exception here to notify the caller of this...
1507                          */
1508                     }
1509                 }
1510 
1511                 // check if 'while' closes a previous 'do'
1512                 else if (newHeader == &AS_WHILE)
1513                 {
1514                     if (lastTempStack != NULL)
1515                     {
1516                         int indexOfDo = indexOf(*lastTempStack, &AS_DO);
1517                         if (indexOfDo != -1)
1518                         {
1519                             // recreate the header list in headerStack up to the previous 'do'
1520                             // from the temporary snapshot stored in lastTempStack.
1521                             int restackSize = lastTempStack->size() - indexOfDo - 1;
1522                             for (int r = 0; r < restackSize; r++)
1523                             {
1524                                 headerStack->push_back(lastTempStack->back());
1525                                 lastTempStack->pop_back();
1526                             }
1527                             if (!closingBracketReached)
1528                                 tabCount += restackSize;
1529                         }
1530                     }
1531                 }
1532                 // check if 'catch' closes a previous 'try' or 'catch'
1533                 else if (newHeader == &AS_CATCH || newHeader == &AS_FINALLY)
1534                 {
1535                     if (lastTempStack != NULL)
1536                     {
1537                         int indexOfTry = indexOf(*lastTempStack, &AS_TRY);
1538                         if (indexOfTry == -1)
1539                             indexOfTry = indexOf(*lastTempStack, &AS_CATCH);
1540                         if (indexOfTry != -1)
1541                         {
1542                             // recreate the header list in headerStack up to the previous 'try'
1543                             // from the temporary snapshot stored in lastTempStack.
1544                             int restackSize = lastTempStack->size() - indexOfTry - 1;
1545                             for (int r = 0; r < restackSize; r++)
1546                             {
1547                                 headerStack->push_back(lastTempStack->back());
1548                                 lastTempStack->pop_back();
1549                             }
1550 
1551                             if (!closingBracketReached)
1552                                 tabCount += restackSize;
1553                         }
1554                     }
1555                 }
1556                 else if (newHeader == &AS_CASE)
1557                 {
1558                     isInCase = true;
1559                     if (!haveCaseIndent)
1560                     {
1561                         haveCaseIndent = true;
1562                         if (!lineBeginsWithBracket)
1563                             --tabCount;
1564                     }
1565                 }
1566                 else if (newHeader == &AS_DEFAULT)
1567                 {
1568                     isInCase = true;
1569                     --tabCount;
1570                 }
1571                 else if (newHeader == &AS_STATIC
1572                          || newHeader == &AS_SYNCHRONIZED
1573                          || (newHeader == &AS_CONST && isCStyle()))
1574                 {
1575                     if (!headerStack->empty() &&
1576                             (headerStack->back() == &AS_STATIC
1577                              || headerStack->back() == &AS_SYNCHRONIZED
1578                              || headerStack->back() == &AS_CONST))
1579                     {
1580                         isIndentableHeader = false;
1581                     }
1582                     else
1583                     {
1584                         isIndentableHeader = false;
1585                         probationHeader = newHeader;
1586                     }
1587                 }
1588                 else if (newHeader == &AS_CONST)
1589                 {
1590                     isIndentableHeader = false;
1591                 }
1592                 else if (newHeader == &AS_TEMPLATE)
1593                 {
1594                     if (isCStyle())
1595                         isInTemplate = true;
1596                     isIndentableHeader = false;
1597                 }
1598 
1599                 if (isIndentableHeader)
1600                 {
1601                     headerStack->push_back(newHeader);
1602                     isInStatement = false;
1603                     if (indexOf(*nonParenHeaders, newHeader) == -1)
1604                     {
1605                         isInConditional = true;
1606                     }
1607                     lastLineHeader = newHeader;
1608                 }
1609                 else
1610                     isInHeader = false;
1611 
1612                 outBuffer.append(newHeader->substr(1));
1613                 i += newHeader->length() - 1;
1614 
1615                 continue;
1616             }  // newHeader != NULL
1617 
1618             if (isCStyle() && findKeyword(line, i, AS_ENUM))
1619                 isInEnum = true;
1620 
1621         }   // isPotentialHeader
1622 
1623         if (ch == '?')
1624             isInQuestion = true;
1625 
1626         // special handling of 'case' statements
1627         if (ch == ':')
1628         {
1629             if ((int) line.length() > i + 1 && line[i+1] == ':') // look for ::
1630             {
1631                 ++i;
1632                 outBuffer.append(1, ':');
1633                 ch = ' ';
1634                 continue;
1635             }
1636 
1637             else if (isInQuestion)
1638             {
1639                 isInQuestion = false;
1640             }
1641 
1642             else if (isCStyle() && isInClassInitializer)
1643             {
1644                 // found a 'class A : public B' definition
1645                 // so do nothing special
1646             }
1647 
1648             else if (isCStyle()
1649                      && (isInAsm || isInAsmOneLine || isInAsmBlock))
1650             {
1651                 // do nothing special
1652             }
1653 
1654             else if (isCStyle() && isdigit(peekNextChar(line, i)))
1655             {
1656                 // found a bit field
1657                 // so do nothing special
1658             }
1659 
1660             else if (isCStyle() && isInClass && prevNonSpaceCh != ')')
1661             {
1662                 // found a 'private:' or 'public:' inside a class definition
1663                 --tabCount;
1664             }
1665 
1666             else if (isCStyle() && prevNonSpaceCh == ')' && !isInCase)
1667             {
1668                 isInClassInitializer = true;
1669                 if (i == 0)
1670                     tabCount += classInitializerTabs;
1671             }
1672 
1673             else if (isJavaStyle() && lastLineHeader == &AS_FOR)
1674             {
1675                 // found a java for-each statement
1676                 // so do nothing special
1677             }
1678 
1679             else
1680             {
1681                 currentNonSpaceCh = ';'; // so that brackets after the ':' will appear as block-openers
1682                 if (isInCase)
1683                 {
1684                     isInCase = false;
1685                     ch = ';'; // from here on, treat char as ';'
1686                 }
1687                 else if (isCStyle() || (isSharpStyle() && peekNextChar(line, i) == ';'))    // is in a label (e.g. 'label1:')
1688                 {
1689                     if (labelIndent)
1690                         --tabCount; // unindent label by one indent
1691                     else if (!lineBeginsWithBracket)
1692                         tabCount = 0; // completely flush indent to left
1693                 }
1694             }
1695         }
1696 
1697         if ((ch == ';'  || (parenDepth > 0 && ch == ','))  && !inStatementIndentStackSizeStack->empty())
1698             while ((int) inStatementIndentStackSizeStack->back() + (parenDepth > 0 ? 1 : 0)
1699                     < (int) inStatementIndentStack->size())
1700                 inStatementIndentStack->pop_back();
1701 
1702         // handle commas
1703         // previous "isInStatement" will be from an assignment operator
1704         if (ch == ',' && parenDepth == 0 && !isInStatement && !isNonInStatementArray)
1705         {
1706             // is comma at end of line
1707             size_t nextChar = line.find_first_not_of(" \t", i + 1);
1708             if (nextChar != string::npos)
1709             {
1710                 if (line.compare(nextChar, 2, "//") == 0
1711                         || line.compare(nextChar, 2, "/*") == 0)
1712                     nextChar = string::npos;
1713             }
1714             // register indent
1715             if (nextChar == string::npos)
1716             {
1717                 // register indent at first word after the colon of a C++ class initializer
1718                 if (isInClassInitializer)
1719                 {
1720                     size_t firstChar = line.find_first_not_of(" \t");
1721                     if (firstChar != string::npos && line[firstChar] == ':')
1722                     {
1723                         size_t firstWord = line.find_first_not_of(" \t", firstChar + 1);
1724                         if (firstChar != string::npos)
1725                         {
1726                             int inStatementIndent = firstWord + spaceTabCount + tabIncrementIn;
1727                             inStatementIndentStack->push_back(inStatementIndent);
1728                             isInStatement = true;
1729                         }
1730                     }
1731                 }
1732                 // register indent at previous word
1733                 else
1734                 {
1735                     int prevWord = getInStatementIndentComma(line, i);
1736                     int inStatementIndent = prevWord + spaceTabCount + tabIncrementIn;
1737                     inStatementIndentStack->push_back(inStatementIndent);
1738                     isInStatement = true;
1739                 }
1740             }
1741         }
1742 
1743         // handle ends of statements
1744         if ((ch == ';' && parenDepth == 0) || ch == '}')
1745         {
1746             if (ch == '}')
1747             {
1748                 // first check if this '}' closes a previous block, or a static array...
1749                 if (!bracketBlockStateStack->empty())
1750                 {
1751                     bool bracketBlockState = bracketBlockStateStack->back();
1752                     bracketBlockStateStack->pop_back();
1753                     if (!bracketBlockState)
1754                     {
1755                         if (!inStatementIndentStackSizeStack->empty())
1756                         {
1757                             // this bracket is a static array
1758 
1759                             int previousIndentStackSize = inStatementIndentStackSizeStack->back();
1760                             inStatementIndentStackSizeStack->pop_back();
1761                             while (previousIndentStackSize < (int) inStatementIndentStack->size())
1762                                 inStatementIndentStack->pop_back();
1763                             parenDepth--;
1764                             if (i == 0)
1765                                 shouldIndentBrackettedLine = false;
1766 
1767                             if (!parenIndentStack->empty())
1768                             {
1769                                 int poppedIndent = parenIndentStack->back();
1770                                 parenIndentStack->pop_back();
1771                                 if (i == 0)
1772                                     spaceTabCount = poppedIndent;
1773                             }
1774                         }
1775                         continue;
1776                     }
1777                 }
1778 
1779                 // this bracket is block closer...
1780 
1781                 ++lineClosingBlocksNum;
1782 
1783                 if (!inStatementIndentStackSizeStack->empty())
1784                     inStatementIndentStackSizeStack->pop_back();
1785 
1786                 if (!blockParenDepthStack->empty())
1787                 {
1788                     parenDepth = blockParenDepthStack->back();
1789                     blockParenDepthStack->pop_back();
1790                     isInStatement = blockStatementStack->back();
1791                     blockStatementStack->pop_back();
1792 
1793                     if (isInStatement)
1794                         blockTabCount--;
1795                 }
1796 
1797                 closingBracketReached = true;
1798                 isInAsmOneLine = false;
1799 
1800                 // added for release 1.24
1801                 // TODO: remove at the appropriate time
1802                 assert(isInAsm == false);
1803                 assert(isInAsmOneLine == false);
1804                 assert(isInQuote == false);
1805                 isInAsm = isInAsmOneLine = isInQuote = false;
1806                 // end remove
1807 
1808                 int headerPlace = indexOf(*headerStack, &AS_OPEN_BRACKET);
1809                 if (headerPlace != -1)
1810                 {
1811                     const string *popped = headerStack->back();
1812                     while (popped != &AS_OPEN_BRACKET)
1813                     {
1814                         headerStack->pop_back();
1815                         popped = headerStack->back();
1816                     }
1817                     headerStack->pop_back();
1818 
1819                     // do not indent namespace bracket unless namespaces are indented
1820                     if (!namespaceIndent && headerStack->size() > 0
1821                             && (*headerStack).back() == &AS_NAMESPACE)
1822                         shouldIndentBrackettedLine = false;
1823 
1824                     if (!tempStacks->empty())
1825                     {
1826                         vector<const string*> *temp =  tempStacks->back();
1827                         tempStacks->pop_back();
1828                         delete temp;
1829                     }
1830                 }
1831 
1832 
1833                 ch = ' '; // needed due to cases such as '}else{', so that headers ('else' tn tih case) will be identified...
1834             }
1835 
1836             /*
1837              * Create a temporary snapshot of the current block's header-list in the
1838              * uppermost inner stack in tempStacks, and clear the headerStack up to
1839              * the begining of the block.
1840              * Thus, the next future statement will think it comes one indent past
1841              * the block's '{' unless it specifically checks for a companion-header
1842              * (such as a previous 'if' for an 'else' header) within the tempStacks,
1843              * and recreates the temporary snapshot by manipulating the tempStacks.
1844              */
1845             if (!tempStacks->back()->empty())
1846                 while (!tempStacks->back()->empty())
1847                     tempStacks->back()->pop_back();
1848             while (!headerStack->empty() && headerStack->back() != &AS_OPEN_BRACKET)
1849             {
1850                 tempStacks->back()->push_back(headerStack->back());
1851                 headerStack->pop_back();
1852             }
1853 
1854             if (parenDepth == 0 && ch == ';')
1855                 isInStatement = false;
1856 
1857             previousLastLineHeader = NULL;
1858             isInClassInitializer = false;
1859             isInEnum = false;
1860             isInQuestion = false;
1861 
1862             continue;
1863         }
1864 
1865         if (isPotentialHeader)
1866         {
1867             // check for preBlockStatements in C/C++ ONLY if not within parenthesies
1868             // (otherwise 'struct XXX' statements would be wrongly interpreted...)
1869             if (!isInTemplate && !(isCStyle() && parenDepth > 0))
1870             {
1871                 const string *newHeader = findHeader(line, i, preBlockStatements);
1872                 if (newHeader != NULL
1873                         && !(isCStyle() && newHeader == &AS_CLASS && isInEnum)) // is it 'enum class'
1874                 {
1875                     isInClassInitializer = true;
1876 
1877                     if (!isSharpStyle())
1878                         headerStack->push_back(newHeader);
1879                     // do not need 'where' in the headerStack
1880                     // do not need second 'class' statement in a row
1881                     else if (!(newHeader == &AS_WHERE
1882                                || (newHeader == &AS_CLASS
1883                                    && headerStack->size() > 0
1884                                    && headerStack->back() == &AS_CLASS)))
1885                         headerStack->push_back(newHeader);
1886 
1887                     outBuffer.append(newHeader->substr(1));
1888                     i += newHeader->length() - 1;
1889                     continue;
1890                 }
1891             }
1892             const string *foundIndentableHeader = findHeader(line, i, indentableHeaders);
1893 
1894             if (foundIndentableHeader != NULL)
1895             {
1896                 // must bypass the header before registering the in statement
1897                 outBuffer.append(foundIndentableHeader->substr(1));
1898                 i += foundIndentableHeader->length() - 1;
1899                 if (!isInOperator && !isInTemplate && !isNonInStatementArray)
1900                 {
1901                     registerInStatementIndent(line, i, spaceTabCount, tabIncrementIn, 0, false);
1902                     isInStatement = true;
1903                 }
1904                 continue;
1905             }
1906 
1907             if (isCStyle() && findKeyword(line, i, AS_OPERATOR))
1908                 isInOperator = true;
1909 
1910             // "new" operator is a pointer, not a calculation
1911             if (findKeyword(line, i, AS_NEW))
1912             {
1913                 if (prevNonSpaceCh == '=' && isInStatement && !inStatementIndentStack->empty())
1914                     inStatementIndentStack->back() = 0;
1915             }
1916 
1917             if (isCStyle())
1918             {
1919                 if (findKeyword(line, i, AS_ASM)
1920                         || findKeyword(line, i, AS__ASM__))
1921                 {
1922                     isInAsm = true;
1923                 }
1924                 else if (findKeyword(line, i, AS_MS_ASM)        // microsoft specific
1925                          || findKeyword(line, i, AS_MS__ASM))
1926                 {
1927                     int index = 4;
1928                     if (peekNextChar(line, i) == '_')       // check for __asm
1929                         index = 5;
1930 
1931                     char peekedChar = ASBase::peekNextChar(line, i + index);
1932                     if (peekedChar == '{' || peekedChar == ' ')
1933                         isInAsmBlock = true;
1934                     else
1935                         isInAsmOneLine = true;
1936                 }
1937             }
1938 
1939             // append the entire name for all others
1940             string name = getCurrentWord(line, i);
1941             outBuffer.append(name.substr(1));
1942             i += name.length() - 1;
1943             continue;
1944         }
1945 
1946         // Handle operators
1947 
1948         bool isPotentialOperator = isCharPotentialOperator(ch);
1949 
1950         if (isPotentialOperator)
1951         {
1952             // Check if an operator has been reached.
1953             const string *foundAssignmentOp = findOperator(line, i, assignmentOperators);
1954             const string *foundNonAssignmentOp = findOperator(line, i, nonAssignmentOperators);
1955 
1956             // Since findHeader's boundry checking was not used above, it is possible
1957             // that both an assignment op and a non-assignment op where found,
1958             // e.g. '>>' and '>>='. If this is the case, treat the LONGER one as the
1959             // found operator.
1960             if (foundAssignmentOp != NULL && foundNonAssignmentOp != NULL)
1961             {
1962                 if (foundAssignmentOp->length() < foundNonAssignmentOp->length())
1963                     foundAssignmentOp = NULL;
1964                 else
1965                     foundNonAssignmentOp = NULL;
1966             }
1967 
1968             if (foundNonAssignmentOp != NULL)
1969             {
1970                 if (foundNonAssignmentOp->length() > 1)
1971                 {
1972                     outBuffer.append(foundNonAssignmentOp->substr(1));
1973                     i += foundNonAssignmentOp->length() - 1;
1974                 }
1975 
1976                 // For C++ input/output, operator<< and >> should be
1977                 // aligned, if we are not in a statement already and
1978                 // also not in the "operator<<(...)" header line
1979                 if (!isInOperator
1980                         && inStatementIndentStack->empty()
1981                         && isCStyle()
1982                         && (foundNonAssignmentOp == &AS_GR_GR ||
1983                             foundNonAssignmentOp == &AS_LS_LS))
1984                 {
1985                     // this will be true if the line begins with the operator
1986                     if (i < 2 && spaceTabCount == 0)
1987                         spaceTabCount += 2 * indentLength;
1988                     // align to the beginning column of the operator
1989                     registerInStatementIndent(line, i - foundNonAssignmentOp->length(), spaceTabCount, tabIncrementIn, 0, false);
1990                 }
1991             }
1992 
1993             else if (foundAssignmentOp != NULL)
1994             {
1995                 if (foundAssignmentOp->length() > 1)
1996                 {
1997                     outBuffer.append(foundAssignmentOp->substr(1));
1998                     i += foundAssignmentOp->length() - 1;
1999                 }
2000 
2001                 if (!isInOperator && !isInTemplate && !isNonInStatementArray)
2002                 {
2003                     // if multiple assignments, align on the previous word
2004                     if (foundAssignmentOp == &AS_ASSIGN
2005                             && prevNonSpaceCh != ']'        // an array
2006                             && statementEndsWithComma(line, i))
2007                     {
2008                         if (!haveAssignmentThisLine)        // only one assignment indent per line
2009                         {
2010                             // register indent at previous word
2011                             haveAssignmentThisLine = true;
2012                             int prevWordIndex = getInStatementIndentAssign(line, i);
2013                             int inStatementIndent = prevWordIndex + spaceTabCount + tabIncrementIn;
2014                             inStatementIndentStack->push_back(inStatementIndent);
2015                         }
2016                     }
2017                     else
2018                         registerInStatementIndent(line, i, spaceTabCount, tabIncrementIn, 0, false);
2019 
2020                     isInStatement = true;
2021                 }
2022             }
2023         }
2024     }   // end of for loop * end of for loop * end of for loop * end of for loop * end of for loop *
2025 
2026     // handle special cases of unindentation:
2027 
2028     /*
2029      * if '{' doesn't follow an immediately previous '{' in the headerStack
2030      * (but rather another header such as "for" or "if", then unindent it
2031      * by one indentation relative to its block.
2032      */
2033 
2034     if (!lineStartsInComment
2035             && !blockIndent
2036             && outBuffer.length() > 0
2037             && outBuffer[0] == '{'
2038             && !(lineOpeningBlocksNum > 0 && lineOpeningBlocksNum == lineClosingBlocksNum)
2039             && !(headerStack->size() > 1 && (*headerStack)[headerStack->size()-2] == &AS_OPEN_BRACKET)
2040             && shouldIndentBrackettedLine)
2041         --tabCount;
2042 
2043     // must check one less in headerStack if more than one header on a line (allow-addins)...
2044     else if (!lineStartsInComment
2045              && (int) headerStack->size() > iPrelim + 1
2046              && !blockIndent
2047              && outBuffer.length() > 0
2048              && outBuffer[0] == '{'
2049              && !(lineOpeningBlocksNum > 0 && lineOpeningBlocksNum == lineClosingBlocksNum)
2050              && !(headerStack->size() > 2 && (*headerStack)[headerStack->size()-3] == &AS_OPEN_BRACKET)
2051              && shouldIndentBrackettedLine)
2052         --tabCount;
2053 
2054     // unindent a closing bracket...
2055     else if (!lineStartsInComment
2056              && outBuffer.length() > 0
2057              && outBuffer[0] == '}'
2058              && shouldIndentBrackettedLine)
2059         --tabCount;
2060 
2061     // correctly indent one-line-blocks...
2062     else if (!lineStartsInComment
2063              && outBuffer.length() > 0
2064              && lineOpeningBlocksNum > 0
2065              && lineOpeningBlocksNum == lineClosingBlocksNum
2066              && previousLineProbationTab)
2067         --tabCount; //lineOpeningBlocksNum - (blockIndent ? 1 : 0);
2068 
2069     // correctly indent class continuation lines...
2070     else if (!lineStartsInComment
2071              && !lineOpensComment
2072              && isInClassHeaderTab
2073              && !blockIndent
2074              && outBuffer.length() > 0
2075              && lineOpeningBlocksNum == 0
2076              && lineOpeningBlocksNum == lineClosingBlocksNum
2077              && (headerStack->size() > 0 && headerStack->back() == &AS_CLASS))
2078         --tabCount;
2079 
2080     if (tabCount < 0)
2081         tabCount = 0;
2082 
2083     // take care of extra bracket indentatation option...
2084     if (!lineStartsInComment
2085             && bracketIndent
2086             && shouldIndentBrackettedLine
2087             && outBuffer.length() > 0
2088             && (outBuffer[0] == '{' || outBuffer[0] == '}'))
2089         tabCount++;
2090 
2091     if (isInDefine)
2092     {
2093         if (outBuffer[0] == '#')
2094         {
2095             string preproc = trim(string(outBuffer.c_str() + 1));
2096             if (preproc.compare(0, 6, "define") == 0)
2097             {
2098                 if (!inStatementIndentStack->empty()
2099                         && inStatementIndentStack->back() > 0)
2100                 {
2101                     defineTabCount = tabCount;
2102                 }
2103                 else
2104                 {
2105                     defineTabCount = tabCount - 1;
2106                     tabCount--;
2107                 }
2108             }
2109         }
2110 
2111         tabCount -= defineTabCount;
2112     }
2113 
2114     if (tabCount < 0)
2115         tabCount = 0;
2116     if (lineCommentNoBeautify || blockCommentNoBeautify || isInQuoteContinuation)
2117         tabCount = spaceTabCount = 0;
2118 
2119     // finally, insert indentations into begining of line
2120 
2121     if (shouldForceTabIndentation)
2122     {
2123         tabCount += spaceTabCount / indentLength;
2124         spaceTabCount = spaceTabCount % indentLength;
2125     }
2126 
2127     outBuffer = preLineWS(spaceTabCount, tabCount) + outBuffer;
2128 
2129     prevFinalLineSpaceTabCount = spaceTabCount;
2130     prevFinalLineTabCount = tabCount;
2131 
2132     if (lastLineHeader != NULL)
2133         previousLastLineHeader = lastLineHeader;
2134 
2135     return outBuffer;
2136 }
2137 
2138 
2139 string ASBeautifier::preLineWS(int spaceTabCount, int tabCount)
2140 {
2141     string ws;
2142 
2143     for (int i = 0; i < tabCount; i++)
2144         ws += indentString;
2145 
2146     while ((spaceTabCount--) > 0)
2147         ws += string(" ");
2148 
2149     return ws;
2150 
2151 }
2152 
2153 bool ASBeautifier::isClassAccessModifier(string& line) const
2154 {
2155     size_t firstChar = line.find_first_not_of(" \t");
2156     if (firstChar == string::npos)
2157         return false;
2158     // bypass a colon
2159     if (line[firstChar] == ':')
2160     {
2161         firstChar = line.find_first_not_of(" \t");
2162         if (firstChar == string::npos)
2163             return false;
2164     }
2165     if (line.compare(firstChar, 7, "public ") == 0
2166             || line.compare(firstChar, 8, "private ") == 0
2167             || line.compare(firstChar, 10, "protected ") == 0)
2168         return true;
2169     return false;
2170 }
2171 
2172 /**
2173  * register an in-statement indent.
2174  */
2175 void ASBeautifier::registerInStatementIndent(const string &line, int i, int spaceTabCount,
2176         int tabIncrementIn, int minIndent, bool updateParenStack)
2177 {
2178     int inStatementIndent;
2179     int remainingCharNum = line.length() - i;
2180     int nextNonWSChar = getNextProgramCharDistance(line, i);
2181 
2182     // if indent is around the last char in the line, indent instead one indent from the previous indent
2183     if (nextNonWSChar == remainingCharNum)
2184     {
2185         int previousIndent = spaceTabCount;
2186         if (!inStatementIndentStack->empty())
2187             previousIndent = inStatementIndentStack->back();
2188         int currIndent = /*2*/ indentLength + previousIndent;
2189         if (currIndent > maxInStatementIndent
2190                 && line[i] != '{')
2191             currIndent = indentLength * 2 + spaceTabCount;
2192         inStatementIndentStack->push_back(currIndent);
2193         if (updateParenStack)
2194             parenIndentStack->push_back(previousIndent);
2195         return;
2196     }
2197 
2198     if (updateParenStack)
2199         parenIndentStack->push_back(i + spaceTabCount - horstmannIndentInStatement);
2200 
2201     int tabIncrement = tabIncrementIn;
2202 
2203     // check for following tabs
2204     for (int j = i + 1; j < (i + nextNonWSChar); j++)
2205     {
2206         if (line[j] == '\t')
2207             tabIncrement += convertTabToSpaces(j, tabIncrement);
2208     }
2209 
2210     inStatementIndent = i + nextNonWSChar + spaceTabCount + tabIncrement;
2211 
2212     // check for run-in statement
2213     if (i > 0 && line[0] == '{')
2214         inStatementIndent -= indentLength;
2215 
2216 //  if (i + nextNonWSChar < minIndent)
2217 //      inStatementIndent = minIndent + spaceTabCount;
2218 
2219     if (inStatementIndent < minIndent)
2220         inStatementIndent = minIndent + spaceTabCount;
2221 
2222 //  if (i + nextNonWSChar > maxInStatementIndent)
2223 //      inStatementIndent =  indentLength * 2 + spaceTabCount;
2224 
2225     if (inStatementIndent > maxInStatementIndent)
2226         inStatementIndent = indentLength * 2 + spaceTabCount;
2227 
2228     if (!inStatementIndentStack->empty() &&
2229             inStatementIndent < inStatementIndentStack->back())
2230         inStatementIndent = inStatementIndentStack->back();
2231 
2232     // the block opener is not indented for a NonInStatementArray
2233     if (isNonInStatementArray && !bracketBlockStateStack->empty() && bracketBlockStateStack->back())
2234         inStatementIndent = 0;
2235 
2236     inStatementIndentStack->push_back(inStatementIndent);
2237 }
2238 
2239 /**
2240  * get distance to the next non-white space, non-comment character in the line.
2241  * if no such character exists, return the length remaining to the end of the line.
2242  */
2243 int ASBeautifier::getNextProgramCharDistance(const string &line, int i) const
2244 {
2245     bool inComment = false;
2246     int  remainingCharNum = line.length() - i;
2247     int  charDistance;
2248     char ch;
2249 
2250     for (charDistance = 1; charDistance < remainingCharNum; charDistance++)
2251     {
2252         ch = line[i + charDistance];
2253         if (inComment)
2254         {
2255             if (line.compare(i + charDistance, 2, "*/") == 0)
2256             {
2257                 charDistance++;
2258                 inComment = false;
2259             }
2260             continue;
2261         }
2262         else if (isWhiteSpace(ch))
2263             continue;
2264         else if (ch == '/')
2265         {
2266             if (line.compare(i + charDistance, 2, "//") == 0)
2267                 return remainingCharNum;
2268             else if (line.compare(i + charDistance, 2, "/*") == 0)
2269             {
2270                 charDistance++;
2271                 inComment = true;
2272             }
2273         }
2274         else
2275             return charDistance;
2276     }
2277 
2278     return charDistance;
2279 }
2280 
2281 // check if a specific line position contains a header.
2282 const string* ASBeautifier::findHeader(const string &line, int i,
2283                                        const vector<const string*>* possibleHeaders) const
2284 {
2285     assert(isCharPotentialHeader(line, i));
2286     // check the word
2287     size_t maxHeaders = possibleHeaders->size();
2288     for (size_t p = 0; p < maxHeaders; p++)
2289     {
2290         const string* header = (*possibleHeaders)[p];
2291         const size_t wordEnd = i + header->length();
2292         if (wordEnd > line.length())
2293             continue;
2294         int result = (line.compare(i, header->length(), *header));
2295         if (result > 0)
2296             continue;
2297         if (result < 0)
2298             break;
2299         // check that this is not part of a longer word
2300         if (wordEnd == line.length())
2301             return header;
2302         if (isLegalNameChar(line[wordEnd]))
2303             continue;
2304         // is not a header if part of a definition
2305         const char peekChar = peekNextChar(line, wordEnd - 1);
2306         if (peekChar == ',' || peekChar == ')')
2307             break;
2308         return header;
2309     }
2310     return NULL;
2311 }
2312 
2313 // check if a specific line position contains an operator.
2314 const string* ASBeautifier::findOperator(const string &line, int i,
2315         const vector<const string*>* possibleOperators) const
2316 {
2317     assert(isCharPotentialOperator(line[i]));
2318     // find the operator in the vector
2319     // the vector contains the LONGEST operators first
2320     // must loop thru the entire vector
2321     size_t maxOperators = possibleOperators->size();
2322     for (size_t p = 0; p < maxOperators; p++)
2323     {
2324         const size_t wordEnd = i + (*(*possibleOperators)[p]).length();
2325         if (wordEnd > line.length())
2326             continue;
2327         if (line.compare(i, (*(*possibleOperators)[p]).length(), *(*possibleOperators)[p]) == 0)
2328             return (*possibleOperators)[p];
2329     }
2330     return NULL;
2331 }
2332 
2333 /**
2334  * find the index number of a string element in a container of strings
2335  *
2336  * @return              the index number of element in the container. -1 if element not found.
2337  * @param container     a vector of strings.
2338  * @param element       the element to find .
2339  */
2340 int ASBeautifier::indexOf(vector<const string*> &container, const string *element)
2341 {
2342     vector<const string*>::const_iterator where;
2343 
2344     where = find(container.begin(), container.end(), element);
2345     if (where == container.end())
2346         return -1;
2347     else
2348         return (int) (where - container.begin());
2349 }
2350 
2351 /**
2352  * convert tabs to spaces.
2353  * i is the position of the character to convert to spaces.
2354  * tabIncrementIn is the increment that must be added for tab indent characters
2355  *     to get the correct column for the current tab.
2356  */
2357 int ASBeautifier::convertTabToSpaces(int i, int tabIncrementIn) const
2358 {
2359     int tabToSpacesAdjustment = indentLength - 1 - ((tabIncrementIn + i) % indentLength);
2360     return tabToSpacesAdjustment;
2361 }
2362 
2363 /**
2364  * trim removes the white space surrounding a line.
2365  *
2366  * @return          the trimmed line.
2367  * @param str       the line to trim.
2368  */
2369 string ASBeautifier::trim(const string &str)
2370 {
2371 
2372     int start = 0;
2373     int end = str.length() - 1;
2374 
2375     while (start < end && isWhiteSpace(str[start]))
2376         start++;
2377 
2378     while (start <= end && isWhiteSpace(str[end]))
2379         end--;
2380 
2381     string returnStr(str, start, end + 1 - start);
2382     return returnStr;
2383 }
2384 
2385 /**
2386  * Copy tempStacks for the copy constructor.
2387  * The value of the vectors must also be copied.
2388  */
2389 vector<vector<const string*>*>* ASBeautifier::copyTempStacks(const ASBeautifier &other) const
2390 {
2391     vector<vector<const string*>*> *tempStacksNew = new vector<vector<const string*>*>;
2392     vector<vector<const string*>*>::iterator iter;
2393     for (iter = other.tempStacks->begin();
2394             iter != other.tempStacks->end();
2395             ++iter)
2396     {
2397         vector<const string*> *newVec = new vector<const string*>;
2398         *newVec = **iter;
2399         tempStacksNew->push_back(newVec);
2400     }
2401     return tempStacksNew;
2402 }
2403 
2404 /**
2405  * delete a static member vector to eliminate memory leak reporting for the vector
2406  */
2407 void ASBeautifier::deleteStaticVectors()
2408 {
2409     beautifierFileType = 9;     // reset to an invalid type
2410     deleteVector(headers);
2411     deleteVector(nonParenHeaders);
2412     deleteVector(preBlockStatements);
2413     deleteVector(assignmentOperators);
2414     deleteVector(nonAssignmentOperators);
2415     deleteVector(indentableHeaders);
2416 }
2417 
2418 /**
2419  * delete a vector object
2420  * T is the type of vector
2421  * used for all vectors except tempStacks
2422  */
2423 template<typename T>
2424 void ASBeautifier::deleteContainer(T &container)
2425 {
2426     if (container != NULL)
2427     {
2428         container->clear();
2429         delete (container);
2430         container = NULL;
2431     }
2432 }
2433 
2434 /**
2435  * Delete the tempStacks vector object.
2436  * The tempStacks is a vector of pointers to strings allocated with
2437  * the 'new' operator.
2438  * Therefore the strings have to be deleted in addition to the
2439  * tempStacks entries.
2440  */
2441 void ASBeautifier::deleteContainer(vector<vector<const string*>*>* &container)
2442 {
2443     if (container != NULL)
2444     {
2445         vector<vector<const string*>*>::iterator iter = container->begin();
2446         for (; iter != container->end(); iter++)
2447             delete *iter;
2448         container->clear();
2449         delete (container);
2450         container = NULL;
2451     }
2452 }
2453 
2454 /**
2455  * delete a vector<const string*>* object
2456  */
2457 void ASBeautifier::deleteVector(vector<const string*>*& container)
2458 {
2459     assert(container != NULL);
2460     delete container;
2461     container = NULL;
2462 }
2463 
2464 /**
2465  * initialize a vector object
2466  * T is the type of vector
2467  * used for all vectors
2468  */
2469 template<typename T>
2470 void ASBeautifier::initContainer(T &container, T value)
2471 {
2472     // since the ASFormatter object is never deleted,
2473     // the existing vectors must be deleted before creating new ones
2474     if (container != NULL )
2475         deleteContainer(container);
2476     container = value;
2477 }
2478 
2479 /**
2480  * initialize a vector<const string*>* object
2481  */
2482 void ASBeautifier::initVector(vector<const string*>*& container)
2483 {
2484     assert(container == NULL);
2485     container = new vector<const string*>;
2486 }
2487 
2488 /**
2489  * Determine if an assignment statement ends with a comma
2490  *     that is not in a function argument. It ends with a
2491  *     comma if a comma is the last char on the line.
2492  *
2493  * @return  true if line ends with a comma, otherwise false.
2494  */
2495 bool ASBeautifier::statementEndsWithComma(string &line, int index)
2496 {
2497     assert(line[index] == '=');
2498 
2499     bool isInComment = false;
2500     bool isInQuote = false;
2501     int parenCount = 0;
2502     size_t lineLength = line.length();
2503     size_t i = 0;
2504     char quoteChar = ' ';
2505 
2506     for (i = index + 1; i < lineLength; ++i)
2507     {
2508         char ch = line[i];
2509 
2510         if (isInComment)
2511         {
2512             if (line.compare(i, 2, "*/") == 0)
2513             {
2514                 isInComment = false;
2515                 ++i;
2516             }
2517             continue;
2518         }
2519 
2520         if (ch == '\\')
2521         {
2522             ++i;
2523             continue;
2524         }
2525 
2526         if (isInQuote)
2527         {
2528             if (ch == quoteChar)
2529                 isInQuote = false;
2530             continue;
2531         }
2532 
2533         if (ch == '"' || ch == '\'')
2534         {
2535             isInQuote = true;
2536             quoteChar = ch;
2537             continue;
2538         }
2539 
2540         if (line.compare(i, 2, "//") == 0)
2541             break;
2542 
2543         if (line.compare(i, 2, "/*") == 0)
2544         {
2545             if (isLineEndComment(line, i))
2546                 break;
2547             else
2548             {
2549                 isInComment = true;
2550                 ++i;
2551                 continue;
2552             }
2553         }
2554 
2555         if (ch == '(')
2556             parenCount++;
2557         if (ch == ')')
2558             parenCount--;
2559     }
2560     if (isInComment
2561             || isInQuote
2562             || parenCount > 0)
2563         return false;
2564 
2565     size_t lastChar = line.find_last_not_of(" \t", i - 1);
2566 
2567     if (lastChar == string::npos || line[lastChar] != ',')
2568         return false;
2569 
2570     return true;
2571 }
2572 
2573 /**
2574  * check if current comment is a line-end comment
2575  *
2576  * @return     is before a line-end comment.
2577  */
2578 bool ASBeautifier::isLineEndComment(string& line, int startPos) const
2579 {
2580     assert(line.compare(startPos, 2, "/*") == 0);
2581 
2582     // comment must be closed on this line with nothing after it
2583     size_t endNum = line.find("*/", startPos + 2);
2584     if (endNum != string::npos)
2585     {
2586         size_t nextChar = line.find_first_not_of(" \t", endNum + 2);
2587         if (nextChar == string::npos)
2588             return true;
2589     }
2590     return false;
2591 }
2592 
2593 /**
2594  * get the previous word index for an assignment operator
2595  *
2596  * @return is the index to the previous word (the in statement indent).
2597  */
2598 int ASBeautifier::getInStatementIndentAssign(const string& line, size_t currPos) const
2599 {
2600     assert(line[currPos] == '=');
2601 
2602     if (currPos == 0)
2603         return 0;
2604 
2605     // get the last legal word (may be a number)
2606     size_t end = line.find_last_not_of(" \t", currPos-1);
2607     if (end == string::npos || !isLegalNameChar(line[end]))
2608         return 0;
2609 
2610     int start;          // start of the previous word
2611     for (start = end; start > -1; start--)
2612     {
2613         if (!isLegalNameChar(line[start]) || line[start] == '.')
2614             break;
2615     }
2616     start++;
2617 
2618     return start;
2619 }
2620 
2621 /**
2622  * get the instatement indent for a comma
2623  *
2624  * @return is the indent to the second word on the line (the in statement indent).
2625  */
2626 int ASBeautifier::getInStatementIndentComma(const string& line, size_t currPos) const
2627 {
2628     assert(line[currPos] == ',');
2629 
2630     if (currPos == 0)
2631         return 0;
2632 
2633     // get first word on a line
2634     size_t indent = line.find_first_not_of(" \t");
2635     if (indent == string::npos || !isLegalNameChar(line[indent]))
2636         return 0;
2637 
2638     // bypass first word
2639     for (; indent < currPos; indent++)
2640     {
2641         if (!isLegalNameChar(line[indent]))
2642             break;
2643     }
2644     indent++;
2645     if (indent >= currPos)
2646         return 0;
2647 
2648     // point to second word or assignment operator
2649     indent = line.find_last_not_of(" \t", indent);
2650     if (indent == string::npos || indent >= currPos)
2651         return 0;
2652 
2653     return indent;
2654 }
2655 
2656 
2657 }   // end namespace astyle
2658