File indexing completed on 2024-06-23 04:35:49

0001 // ASBeautifier.cpp
0002 // Copyright (c) 2018 by Jim Pattee <jimp03@email.com>.
0003 // This code is licensed under the MIT License.
0004 // License.md describes the conditions under which this software may be distributed.
0005 
0006 //-----------------------------------------------------------------------------
0007 // headers
0008 //-----------------------------------------------------------------------------
0009 
0010 #include "astyle.h"
0011 
0012 #include <algorithm>
0013 
0014 //-----------------------------------------------------------------------------
0015 // astyle namespace
0016 //-----------------------------------------------------------------------------
0017 
0018 namespace astyle {
0019 //
0020 // this must be global
0021 static int g_preprocessorCppExternCBrace;
0022 
0023 //-----------------------------------------------------------------------------
0024 // ASBeautifier class
0025 //-----------------------------------------------------------------------------
0026 
0027 /**
0028  * ASBeautifier's constructor
0029  * This constructor is called only once for each source file.
0030  * The cloned ASBeautifier objects are created with the copy constructor.
0031  */
0032 ASBeautifier::ASBeautifier()
0033 {
0034     waitingBeautifierStack = nullptr;
0035     activeBeautifierStack = nullptr;
0036     waitingBeautifierStackLengthStack = nullptr;
0037     activeBeautifierStackLengthStack = nullptr;
0038 
0039     headerStack = nullptr;
0040     tempStacks = nullptr;
0041     parenDepthStack = nullptr;
0042     blockStatementStack = nullptr;
0043     parenStatementStack = nullptr;
0044     braceBlockStateStack = nullptr;
0045     continuationIndentStack = nullptr;
0046     continuationIndentStackSizeStack = nullptr;
0047     parenIndentStack = nullptr;
0048     preprocIndentStack = nullptr;
0049     sourceIterator = nullptr;
0050     isModeManuallySet = false;
0051     shouldForceTabIndentation = false;
0052     setSpaceIndentation(4);
0053     setContinuationIndentation(1);
0054     setMinConditionalIndentOption(MINCOND_TWO);
0055     setMaxContinuationIndentLength(40);
0056     classInitializerIndents = 1;
0057     tabLength = 0;
0058     setClassIndent(false);
0059     setModifierIndent(false);
0060     setSwitchIndent(false);
0061     setCaseIndent(false);
0062     setBlockIndent(false);
0063     setBraceIndent(false);
0064     setBraceIndentVtk(false);
0065     setNamespaceIndent(false);
0066     setAfterParenIndent(false);
0067     setLabelIndent(false);
0068     setEmptyLineFill(false);
0069     setCStyle();
0070     setPreprocDefineIndent(false);
0071     setPreprocConditionalIndent(false);
0072     setAlignMethodColon(false);
0073 
0074     // initialize ASBeautifier member vectors
0075     beautifierFileType = 9;     // reset to an invalid type
0076     headers = new vector<const string*>;
0077     nonParenHeaders = new vector<const string*>;
0078     assignmentOperators = new vector<const string*>;
0079     nonAssignmentOperators = new vector<const string*>;
0080     preBlockStatements = new vector<const string*>;
0081     preCommandHeaders = new vector<const string*>;
0082     indentableHeaders = new vector<const string*>;
0083 }
0084 
0085 /**
0086  * ASBeautifier's copy constructor
0087  * Copy the vector objects to vectors in the new ASBeautifier
0088  * object so the new object can be destroyed without deleting
0089  * the vector objects in the copied vector.
0090  * This is the reason a copy constructor is needed.
0091  *
0092  * Must explicitly call the base class copy constructor.
0093  */
0094 ASBeautifier::ASBeautifier(const ASBeautifier& other) : ASBase(other)
0095 {
0096     // these don't need to copy the stack
0097     waitingBeautifierStack = nullptr;
0098     activeBeautifierStack = nullptr;
0099     waitingBeautifierStackLengthStack = nullptr;
0100     activeBeautifierStackLengthStack = nullptr;
0101 
0102     // vector '=' operator performs a DEEP copy of all elements in the vector
0103 
0104     headerStack = new vector<const string*>;
0105     *headerStack = *other.headerStack;
0106 
0107     tempStacks = copyTempStacks(other);
0108 
0109     parenDepthStack = new vector<int>;
0110     *parenDepthStack = *other.parenDepthStack;
0111 
0112     blockStatementStack = new vector<bool>;
0113     *blockStatementStack = *other.blockStatementStack;
0114 
0115     parenStatementStack = new vector<bool>;
0116     *parenStatementStack = *other.parenStatementStack;
0117 
0118     braceBlockStateStack = new vector<bool>;
0119     *braceBlockStateStack = *other.braceBlockStateStack;
0120 
0121     continuationIndentStack = new vector<int>;
0122     *continuationIndentStack = *other.continuationIndentStack;
0123 
0124     continuationIndentStackSizeStack = new vector<int>;
0125     *continuationIndentStackSizeStack = *other.continuationIndentStackSizeStack;
0126 
0127     parenIndentStack = new vector<int>;
0128     *parenIndentStack = *other.parenIndentStack;
0129 
0130     preprocIndentStack = new vector<pair<int, int> >;
0131     *preprocIndentStack = *other.preprocIndentStack;
0132 
0133     // Copy the pointers to vectors.
0134     // This is ok because the original ASBeautifier object
0135     // is not deleted until end of job.
0136     beautifierFileType = other.beautifierFileType;
0137     headers = other.headers;
0138     nonParenHeaders = other.nonParenHeaders;
0139     assignmentOperators = other.assignmentOperators;
0140     nonAssignmentOperators = other.nonAssignmentOperators;
0141     preBlockStatements = other.preBlockStatements;
0142     preCommandHeaders = other.preCommandHeaders;
0143     indentableHeaders = other.indentableHeaders;
0144 
0145     // protected variables
0146     // variables set by ASFormatter
0147     // must also be updated in activeBeautifierStack
0148     inLineNumber = other.inLineNumber;
0149     runInIndentContinuation = other.runInIndentContinuation;
0150     nonInStatementBrace = other.nonInStatementBrace;
0151     objCColonAlignSubsequent = other.objCColonAlignSubsequent;
0152     lineCommentNoBeautify = other.lineCommentNoBeautify;
0153     isElseHeaderIndent = other.isElseHeaderIndent;
0154     isCaseHeaderCommentIndent = other.isCaseHeaderCommentIndent;
0155     isNonInStatementArray = other.isNonInStatementArray;
0156     isSharpAccessor = other.isSharpAccessor;
0157     isSharpDelegate = other.isSharpDelegate;
0158     isInExternC = other.isInExternC;
0159     isInBeautifySQL = other.isInBeautifySQL;
0160     isInIndentableStruct = other.isInIndentableStruct;
0161     isInIndentablePreproc = other.isInIndentablePreproc;
0162 
0163     // private variables
0164     sourceIterator = other.sourceIterator;
0165     currentHeader = other.currentHeader;
0166     previousLastLineHeader = other.previousLastLineHeader;
0167     probationHeader = other.probationHeader;
0168     lastLineHeader = other.lastLineHeader;
0169     indentString = other.indentString;
0170     verbatimDelimiter = other.verbatimDelimiter;
0171     isInQuote = other.isInQuote;
0172     isInVerbatimQuote = other.isInVerbatimQuote;
0173     haveLineContinuationChar = other.haveLineContinuationChar;
0174     isInAsm = other.isInAsm;
0175     isInAsmOneLine = other.isInAsmOneLine;
0176     isInAsmBlock = other.isInAsmBlock;
0177     isInComment = other.isInComment;
0178     isInPreprocessorComment = other.isInPreprocessorComment;
0179     isInRunInComment = other.isInRunInComment;
0180     isInCase = other.isInCase;
0181     isInQuestion = other.isInQuestion;
0182     isContinuation = other.isContinuation;
0183     isInHeader = other.isInHeader;
0184     isInTemplate = other.isInTemplate;
0185     isInDefine = other.isInDefine;
0186     isInDefineDefinition = other.isInDefineDefinition;
0187     classIndent = other.classIndent;
0188     isIndentModeOff = other.isIndentModeOff;
0189     isInClassHeader = other.isInClassHeader;
0190     isInClassHeaderTab = other.isInClassHeaderTab;
0191     isInClassInitializer = other.isInClassInitializer;
0192     isInClass = other.isInClass;
0193     isInObjCMethodDefinition = other.isInObjCMethodDefinition;
0194     isInObjCMethodCall = other.isInObjCMethodCall;
0195     isInObjCMethodCallFirst = other.isInObjCMethodCallFirst;
0196     isImmediatelyPostObjCMethodDefinition = other.isImmediatelyPostObjCMethodDefinition;
0197     isImmediatelyPostObjCMethodCall = other.isImmediatelyPostObjCMethodCall;
0198     isInIndentablePreprocBlock = other.isInIndentablePreprocBlock;
0199     isInObjCInterface = other.isInObjCInterface;
0200     isInEnum = other.isInEnum;
0201     isInEnumTypeID = other.isInEnumTypeID;
0202     isInLet = other.isInLet;
0203     isInTrailingReturnType = other.isInTrailingReturnType;
0204     modifierIndent = other.modifierIndent;
0205     switchIndent = other.switchIndent;
0206     caseIndent = other.caseIndent;
0207     namespaceIndent = other.namespaceIndent;
0208     braceIndent = other.braceIndent;
0209     braceIndentVtk = other.braceIndentVtk;
0210     blockIndent = other.blockIndent;
0211     shouldIndentAfterParen = other.shouldIndentAfterParen;
0212     labelIndent = other.labelIndent;
0213     isInConditional = other.isInConditional;
0214     isModeManuallySet = other.isModeManuallySet;
0215     shouldForceTabIndentation = other.shouldForceTabIndentation;
0216     emptyLineFill = other.emptyLineFill;
0217     lineOpensWithLineComment = other.lineOpensWithLineComment;
0218     lineOpensWithComment = other.lineOpensWithComment;
0219     lineStartsInComment = other.lineStartsInComment;
0220     backslashEndsPrevLine = other.backslashEndsPrevLine;
0221     blockCommentNoIndent = other.blockCommentNoIndent;
0222     blockCommentNoBeautify = other.blockCommentNoBeautify;
0223     previousLineProbationTab = other.previousLineProbationTab;
0224     lineBeginsWithOpenBrace = other.lineBeginsWithOpenBrace;
0225     lineBeginsWithCloseBrace = other.lineBeginsWithCloseBrace;
0226     lineBeginsWithComma = other.lineBeginsWithComma;
0227     lineIsCommentOnly = other.lineIsCommentOnly;
0228     lineIsLineCommentOnly = other.lineIsLineCommentOnly;
0229     shouldIndentBracedLine = other.shouldIndentBracedLine;
0230     isInSwitch = other.isInSwitch;
0231     foundPreCommandHeader = other.foundPreCommandHeader;
0232     foundPreCommandMacro = other.foundPreCommandMacro;
0233     shouldAlignMethodColon = other.shouldAlignMethodColon;
0234     shouldIndentPreprocDefine = other.shouldIndentPreprocDefine;
0235     shouldIndentPreprocConditional = other.shouldIndentPreprocConditional;
0236     indentCount = other.indentCount;
0237     spaceIndentCount = other.spaceIndentCount;
0238     spaceIndentObjCMethodAlignment = other.spaceIndentObjCMethodAlignment;
0239     bracePosObjCMethodAlignment = other.bracePosObjCMethodAlignment;
0240     colonIndentObjCMethodAlignment = other.colonIndentObjCMethodAlignment;
0241     lineOpeningBlocksNum = other.lineOpeningBlocksNum;
0242     lineClosingBlocksNum = other.lineClosingBlocksNum;
0243     fileType = other.fileType;
0244     minConditionalOption = other.minConditionalOption;
0245     minConditionalIndent = other.minConditionalIndent;
0246     parenDepth = other.parenDepth;
0247     indentLength = other.indentLength;
0248     tabLength = other.tabLength;
0249     continuationIndent = other.continuationIndent;
0250     blockTabCount = other.blockTabCount;
0251     maxContinuationIndent = other.maxContinuationIndent;
0252     classInitializerIndents = other.classInitializerIndents;
0253     templateDepth = other.templateDepth;
0254     squareBracketCount = other.squareBracketCount;
0255     prevFinalLineSpaceIndentCount = other.prevFinalLineSpaceIndentCount;
0256     prevFinalLineIndentCount = other.prevFinalLineIndentCount;
0257     defineIndentCount = other.defineIndentCount;
0258     preprocBlockIndent = other.preprocBlockIndent;
0259     quoteChar = other.quoteChar;
0260     prevNonSpaceCh = other.prevNonSpaceCh;
0261     currentNonSpaceCh = other.currentNonSpaceCh;
0262     currentNonLegalCh = other.currentNonLegalCh;
0263     prevNonLegalCh = other.prevNonLegalCh;
0264 }
0265 
0266 /**
0267  * ASBeautifier's destructor
0268  */
0269 ASBeautifier::~ASBeautifier()
0270 {
0271     deleteBeautifierContainer(waitingBeautifierStack);
0272     deleteBeautifierContainer(activeBeautifierStack);
0273     deleteContainer(waitingBeautifierStackLengthStack);
0274     deleteContainer(activeBeautifierStackLengthStack);
0275     deleteContainer(headerStack);
0276     deleteTempStacksContainer(tempStacks);
0277     deleteContainer(parenDepthStack);
0278     deleteContainer(blockStatementStack);
0279     deleteContainer(parenStatementStack);
0280     deleteContainer(braceBlockStateStack);
0281     deleteContainer(continuationIndentStack);
0282     deleteContainer(continuationIndentStackSizeStack);
0283     deleteContainer(parenIndentStack);
0284     deleteContainer(preprocIndentStack);
0285 }
0286 
0287 /**
0288  * initialize the ASBeautifier.
0289  *
0290  * This init() should be called every time a ABeautifier object is to start
0291  * beautifying a NEW source file.
0292  * It is called only when a new ASFormatter object is created.
0293  * init() receives a pointer to a ASSourceIterator object that will be
0294  * used to iterate through the source code.
0295  *
0296  * @param iter     a pointer to the ASSourceIterator or ASStreamIterator object.
0297  */
0298 void ASBeautifier::init(ASSourceIterator* iter)
0299 {
0300     sourceIterator = iter;
0301     initVectors();
0302     ASBase::init(getFileType());
0303     g_preprocessorCppExternCBrace = 0;
0304 
0305     initContainer(waitingBeautifierStack, new vector<ASBeautifier*>);
0306     initContainer(activeBeautifierStack, new vector<ASBeautifier*>);
0307 
0308     initContainer(waitingBeautifierStackLengthStack, new vector<int>);
0309     initContainer(activeBeautifierStackLengthStack, new vector<int>);
0310 
0311     initContainer(headerStack, new vector<const string*>);
0312 
0313     initTempStacksContainer(tempStacks, new vector<vector<const string*>*>);
0314     tempStacks->emplace_back(new vector<const string*>);
0315 
0316     initContainer(parenDepthStack, new vector<int>);
0317     initContainer(blockStatementStack, new vector<bool>);
0318     initContainer(parenStatementStack, new vector<bool>);
0319     initContainer(braceBlockStateStack, new vector<bool>);
0320     braceBlockStateStack->push_back(true);
0321     initContainer(continuationIndentStack, new vector<int>);
0322     initContainer(continuationIndentStackSizeStack, new vector<int>);
0323     continuationIndentStackSizeStack->emplace_back(0);
0324     initContainer(parenIndentStack, new vector<int>);
0325     initContainer(preprocIndentStack, new vector<pair<int, int> >);
0326 
0327     previousLastLineHeader = nullptr;
0328     currentHeader = nullptr;
0329 
0330     isInQuote = false;
0331     isInVerbatimQuote = false;
0332     haveLineContinuationChar = false;
0333     isInAsm = false;
0334     isInAsmOneLine = false;
0335     isInAsmBlock = false;
0336     isInComment = false;
0337     isInPreprocessorComment = false;
0338     isInRunInComment = false;
0339     isContinuation = false;
0340     isInCase = false;
0341     isInQuestion = false;
0342     isIndentModeOff = false;
0343     isInClassHeader = false;
0344     isInClassHeaderTab = false;
0345     isInClassInitializer = false;
0346     isInClass = false;
0347     isInObjCMethodDefinition = false;
0348     isInObjCMethodCall = false;
0349     isInObjCMethodCallFirst = false;
0350     isImmediatelyPostObjCMethodDefinition = false;
0351     isImmediatelyPostObjCMethodCall = false;
0352     isInIndentablePreprocBlock = false;
0353     isInObjCInterface = false;
0354     isInEnum = false;
0355     isInEnumTypeID = false;
0356     isInLet = false;
0357     isInHeader = false;
0358     isInTemplate = false;
0359     isInConditional = false;
0360     isInTrailingReturnType = false;
0361 
0362     indentCount = 0;
0363     spaceIndentCount = 0;
0364     spaceIndentObjCMethodAlignment = 0;
0365     bracePosObjCMethodAlignment = 0;
0366     colonIndentObjCMethodAlignment = 0;
0367     lineOpeningBlocksNum = 0;
0368     lineClosingBlocksNum = 0;
0369     templateDepth = 0;
0370     squareBracketCount = 0;
0371     parenDepth = 0;
0372     blockTabCount = 0;
0373     prevFinalLineSpaceIndentCount = 0;
0374     prevFinalLineIndentCount = 0;
0375     defineIndentCount = 0;
0376     preprocBlockIndent = 0;
0377     prevNonSpaceCh = '{';
0378     currentNonSpaceCh = '{';
0379     prevNonLegalCh = '{';
0380     currentNonLegalCh = '{';
0381     quoteChar = ' ';
0382     probationHeader = nullptr;
0383     lastLineHeader = nullptr;
0384     backslashEndsPrevLine = false;
0385     lineOpensWithLineComment = false;
0386     lineOpensWithComment = false;
0387     lineStartsInComment = false;
0388     isInDefine = false;
0389     isInDefineDefinition = false;
0390     lineCommentNoBeautify = false;
0391     isElseHeaderIndent = false;
0392     isCaseHeaderCommentIndent = false;
0393     blockCommentNoIndent = false;
0394     blockCommentNoBeautify = false;
0395     previousLineProbationTab = false;
0396     lineBeginsWithOpenBrace = false;
0397     lineBeginsWithCloseBrace = false;
0398     lineBeginsWithComma = false;
0399     lineIsCommentOnly = false;
0400     lineIsLineCommentOnly = false;
0401     shouldIndentBracedLine = true;
0402     isInSwitch = false;
0403     foundPreCommandHeader = false;
0404     foundPreCommandMacro = false;
0405 
0406     isNonInStatementArray = false;
0407     isSharpAccessor = false;
0408     isSharpDelegate = false;
0409     isInExternC = false;
0410     isInBeautifySQL = false;
0411     isInIndentableStruct = false;
0412     isInIndentablePreproc = false;
0413     inLineNumber = 0;
0414     runInIndentContinuation = 0;
0415     nonInStatementBrace = 0;
0416     objCColonAlignSubsequent = 0;
0417 }
0418 
0419 /*
0420  * initialize the vectors
0421  */
0422 void ASBeautifier::initVectors()
0423 {
0424     if (fileType == beautifierFileType)    // don't build unless necessary
0425         return;
0426 
0427     beautifierFileType = fileType;
0428 
0429     headers->clear();
0430     nonParenHeaders->clear();
0431     assignmentOperators->clear();
0432     nonAssignmentOperators->clear();
0433     preBlockStatements->clear();
0434     preCommandHeaders->clear();
0435     indentableHeaders->clear();
0436 
0437     ASResource::buildHeaders(headers, fileType, true);
0438     ASResource::buildNonParenHeaders(nonParenHeaders, fileType, true);
0439     ASResource::buildAssignmentOperators(assignmentOperators);
0440     ASResource::buildNonAssignmentOperators(nonAssignmentOperators);
0441     ASResource::buildPreBlockStatements(preBlockStatements, fileType);
0442     ASResource::buildPreCommandHeaders(preCommandHeaders, fileType);
0443     ASResource::buildIndentableHeaders(indentableHeaders);
0444 }
0445 
0446 /**
0447  * set indentation style to C/C++.
0448  */
0449 void ASBeautifier::setCStyle()
0450 {
0451     fileType = C_TYPE;
0452 }
0453 
0454 /**
0455  * set indentation style to Java.
0456  */
0457 void ASBeautifier::setJavaStyle()
0458 {
0459     fileType = JAVA_TYPE;
0460 }
0461 
0462 /**
0463  * set indentation style to C#.
0464  */
0465 void ASBeautifier::setSharpStyle()
0466 {
0467     fileType = SHARP_TYPE;
0468 }
0469 
0470 /**
0471  * set mode manually set flag
0472  */
0473 void ASBeautifier::setModeManuallySet(bool state)
0474 {
0475     isModeManuallySet = state;
0476 }
0477 
0478 /**
0479  * set tabLength equal to indentLength.
0480  * This is done when tabLength is not explicitly set by
0481  * "indent=force-tab-x"
0482  *
0483  */
0484 void ASBeautifier::setDefaultTabLength()
0485 {
0486     tabLength = indentLength;
0487 }
0488 
0489 /**
0490  * indent using a different tab setting for indent=force-tab
0491  *
0492  * @param   length     number of spaces per tab.
0493  */
0494 void ASBeautifier::setForceTabXIndentation(int length)
0495 {
0496     // set tabLength instead of indentLength
0497     indentString = "\t";
0498     tabLength = length;
0499     shouldForceTabIndentation = true;
0500 }
0501 
0502 /**
0503  * indent using one tab per indentation
0504  */
0505 void ASBeautifier::setTabIndentation(int length, bool forceTabs)
0506 {
0507     indentString = "\t";
0508     indentLength = length;
0509     shouldForceTabIndentation = forceTabs;
0510 }
0511 
0512 /**
0513  * indent using a number of spaces per indentation.
0514  *
0515  * @param   length     number of spaces per indent.
0516  */
0517 void ASBeautifier::setSpaceIndentation(int length)
0518 {
0519     indentString = string(length, ' ');
0520     indentLength = length;
0521 }
0522 
0523 /**
0524 * indent continuation lines using a number of indents.
0525 *
0526 * @param   indent     number of indents per line.
0527 */
0528 void ASBeautifier::setContinuationIndentation(int indent)
0529 {
0530     continuationIndent = indent;
0531 }
0532 
0533 /**
0534  * set the maximum indentation between two lines in a multi-line statement.
0535  *
0536  * @param   max     maximum indentation length.
0537  */
0538 void ASBeautifier::setMaxContinuationIndentLength(int max)
0539 {
0540     maxContinuationIndent = max;
0541 }
0542 
0543 // retained for compatibility with release 2.06
0544 // "MaxInStatementIndent" has been changed to "MaxContinuationIndent" in 3.0
0545 // it is referenced only by the old "MaxInStatementIndent" options
0546 void ASBeautifier::setMaxInStatementIndentLength(int max)
0547 {
0548     setMaxContinuationIndentLength(max);
0549 }
0550 
0551 /**
0552  * set the minimum conditional indentation option.
0553  *
0554  * @param   min     minimal indentation option.
0555  */
0556 void ASBeautifier::setMinConditionalIndentOption(int min)
0557 {
0558     minConditionalOption = min;
0559 }
0560 
0561 /**
0562  * set minConditionalIndent from the minConditionalOption.
0563  */
0564 void ASBeautifier::setMinConditionalIndentLength()
0565 {
0566     if (minConditionalOption == MINCOND_ZERO)
0567         minConditionalIndent = 0;
0568     else if (minConditionalOption == MINCOND_ONE)
0569         minConditionalIndent = indentLength;
0570     else if (minConditionalOption == MINCOND_ONEHALF)
0571         minConditionalIndent = indentLength / 2;
0572     // minConditionalOption = INDENT_TWO
0573     else
0574         minConditionalIndent = indentLength * 2;
0575 }
0576 
0577 /**
0578  * set the state of the brace indent option. If true, braces will
0579  * be indented one additional indent.
0580  *
0581  * @param   state             state of option.
0582  */
0583 void ASBeautifier::setBraceIndent(bool state)
0584 {
0585     braceIndent = state;
0586 }
0587 
0588 /**
0589 * set the state of the brace indent VTK option. If true, braces will
0590 * be indented one additional indent, except for the opening brace.
0591 *
0592 * @param   state             state of option.
0593 */
0594 void ASBeautifier::setBraceIndentVtk(bool state)
0595 {
0596     // need to set both of these
0597     setBraceIndent(state);
0598     braceIndentVtk = state;
0599 }
0600 
0601 /**
0602  * set the state of the block indentation option. If true, entire blocks
0603  * will be indented one additional indent, similar to the GNU indent style.
0604  *
0605  * @param   state             state of option.
0606  */
0607 void ASBeautifier::setBlockIndent(bool state)
0608 {
0609     blockIndent = state;
0610 }
0611 
0612 /**
0613  * set the state of the class indentation option. If true, C++ class
0614  * definitions will be indented one additional indent.
0615  *
0616  * @param   state             state of option.
0617  */
0618 void ASBeautifier::setClassIndent(bool state)
0619 {
0620     classIndent = state;
0621 }
0622 
0623 /**
0624  * set the state of the modifier indentation option. If true, C++ class
0625  * access modifiers will be indented one-half an indent.
0626  *
0627  * @param   state             state of option.
0628  */
0629 void ASBeautifier::setModifierIndent(bool state)
0630 {
0631     modifierIndent = state;
0632 }
0633 
0634 /**
0635  * set the state of the switch indentation option. If true, blocks of 'switch'
0636  * statements will be indented one additional indent.
0637  *
0638  * @param   state             state of option.
0639  */
0640 void ASBeautifier::setSwitchIndent(bool state)
0641 {
0642     switchIndent = state;
0643 }
0644 
0645 /**
0646  * set the state of the case indentation option. If true, lines of 'case'
0647  * statements will be indented one additional indent.
0648  *
0649  * @param   state             state of option.
0650  */
0651 void ASBeautifier::setCaseIndent(bool state)
0652 {
0653     caseIndent = state;
0654 }
0655 
0656 /**
0657  * set the state of the namespace indentation option.
0658  * If true, blocks of 'namespace' statements will be indented one
0659  * additional indent. Otherwise, NO indentation will be added.
0660  *
0661  * @param   state             state of option.
0662  */
0663 void ASBeautifier::setNamespaceIndent(bool state)
0664 {
0665     namespaceIndent = state;
0666 }
0667 
0668 /**
0669 * set the state of the indent after parens option.
0670 *
0671 * @param   state             state of option.
0672 */
0673 void ASBeautifier::setAfterParenIndent(bool state)
0674 {
0675     shouldIndentAfterParen = state;
0676 }
0677 
0678 /**
0679  * set the state of the label indentation option.
0680  * If true, labels will be indented one indent LESS than the
0681  * current indentation level.
0682  * If false, labels will be flushed to the left with NO
0683  * indent at all.
0684  *
0685  * @param   state             state of option.
0686  */
0687 void ASBeautifier::setLabelIndent(bool state)
0688 {
0689     labelIndent = state;
0690 }
0691 
0692 /**
0693  * set the state of the preprocessor indentation option.
0694  * If true, multi-line #define statements will be indented.
0695  *
0696  * @param   state             state of option.
0697  */
0698 void ASBeautifier::setPreprocDefineIndent(bool state)
0699 {
0700     shouldIndentPreprocDefine = state;
0701 }
0702 
0703 void ASBeautifier::setPreprocConditionalIndent(bool state)
0704 {
0705     shouldIndentPreprocConditional = state;
0706 }
0707 
0708 /**
0709  * set the state of the empty line fill option.
0710  * If true, empty lines will be filled with the whitespace.
0711  * of their previous lines.
0712  * If false, these lines will remain empty.
0713  *
0714  * @param   state             state of option.
0715  */
0716 void ASBeautifier::setEmptyLineFill(bool state)
0717 {
0718     emptyLineFill = state;
0719 }
0720 
0721 void ASBeautifier::setAlignMethodColon(bool state)
0722 {
0723     shouldAlignMethodColon = state;
0724 }
0725 
0726 /**
0727  * get the file type.
0728  */
0729 int ASBeautifier::getFileType() const
0730 {
0731     return fileType;
0732 }
0733 
0734 /**
0735  * get the number of spaces per indent
0736  *
0737  * @return   value of indentLength option.
0738  */
0739 int ASBeautifier::getIndentLength() const
0740 {
0741     return indentLength;
0742 }
0743 
0744 /**
0745  * get the char used for indentation, space or tab
0746  *
0747  * @return   the char used for indentation.
0748  */
0749 string ASBeautifier::getIndentString() const
0750 {
0751     return indentString;
0752 }
0753 
0754 /**
0755  * get mode manually set flag
0756  */
0757 bool ASBeautifier::getModeManuallySet() const
0758 {
0759     return isModeManuallySet;
0760 }
0761 
0762 /**
0763  * get the state of the force tab indentation option.
0764  *
0765  * @return   state of force tab indentation.
0766  */
0767 bool ASBeautifier::getForceTabIndentation() const
0768 {
0769     return shouldForceTabIndentation;
0770 }
0771 
0772 /**
0773 * Get the state of the Objective-C align method colon option.
0774 *
0775 * @return   state of shouldAlignMethodColon option.
0776 */
0777 bool ASBeautifier::getAlignMethodColon() const
0778 {
0779     return shouldAlignMethodColon;
0780 }
0781 
0782 /**
0783  * get the state of the block indentation option.
0784  *
0785  * @return   state of blockIndent option.
0786  */
0787 bool ASBeautifier::getBlockIndent() const
0788 {
0789     return blockIndent;
0790 }
0791 
0792 /**
0793  * get the state of the brace indentation option.
0794  *
0795  * @return   state of braceIndent option.
0796  */
0797 bool ASBeautifier::getBraceIndent() const
0798 {
0799     return braceIndent;
0800 }
0801 
0802 /**
0803 * Get the state of the namespace indentation option. If true, blocks
0804 * of the 'namespace' statement will be indented one additional indent.
0805 *
0806 * @return   state of namespaceIndent option.
0807 */
0808 bool ASBeautifier::getNamespaceIndent() const
0809 {
0810     return namespaceIndent;
0811 }
0812 
0813 /**
0814  * Get the state of the class indentation option. If true, blocks of
0815  * the 'class' statement will be indented one additional indent.
0816  *
0817  * @return   state of classIndent option.
0818  */
0819 bool ASBeautifier::getClassIndent() const
0820 {
0821     return classIndent;
0822 }
0823 
0824 /**
0825  * Get the state of the class access modifier indentation option.
0826  * If true, the class access modifiers will be indented one-half indent.
0827  *
0828  * @return   state of modifierIndent option.
0829  */
0830 bool ASBeautifier::getModifierIndent() const
0831 {
0832     return modifierIndent;
0833 }
0834 
0835 /**
0836  * get the state of the switch indentation option. If true, blocks of
0837  * the 'switch' statement will be indented one additional indent.
0838  *
0839  * @return   state of switchIndent option.
0840  */
0841 bool ASBeautifier::getSwitchIndent() const
0842 {
0843     return switchIndent;
0844 }
0845 
0846 /**
0847  * get the state of the case indentation option. If true, lines of 'case'
0848  * statements will be indented one additional indent.
0849  *
0850  * @return   state of caseIndent option.
0851  */
0852 bool ASBeautifier::getCaseIndent() const
0853 {
0854     return caseIndent;
0855 }
0856 
0857 /**
0858  * get the state of the empty line fill option.
0859  * If true, empty lines will be filled with the whitespace.
0860  * of their previous lines.
0861  * If false, these lines will remain empty.
0862  *
0863  * @return   state of emptyLineFill option.
0864  */
0865 bool ASBeautifier::getEmptyLineFill() const
0866 {
0867     return emptyLineFill;
0868 }
0869 
0870 /**
0871  * get the state of the preprocessor indentation option.
0872  * If true, preprocessor "define" lines will be indented.
0873  * If false, preprocessor "define" lines will be unchanged.
0874  *
0875  * @return   state of shouldIndentPreprocDefine option.
0876  */
0877 bool ASBeautifier::getPreprocDefineIndent() const
0878 {
0879     return shouldIndentPreprocDefine;
0880 }
0881 
0882 /**
0883  * get the length of the tab indentation option.
0884  *
0885  * @return   length of tab indent option.
0886  */
0887 int ASBeautifier::getTabLength() const
0888 {
0889     return tabLength;
0890 }
0891 
0892 /**
0893  * beautify a line of source code.
0894  * every line of source code in a source code file should be sent
0895  * one after the other to the beautify method.
0896  *
0897  * @return      the indented line.
0898  * @param originalLine       the original unindented line.
0899  */
0900 string ASBeautifier::beautify(const string& originalLine)
0901 {
0902     string line;
0903     bool isInQuoteContinuation = isInVerbatimQuote || haveLineContinuationChar;
0904 
0905     currentHeader = nullptr;
0906     lastLineHeader = nullptr;
0907     blockCommentNoBeautify = blockCommentNoIndent;
0908     isInClass = false;
0909     isInSwitch = false;
0910     lineBeginsWithOpenBrace = false;
0911     lineBeginsWithCloseBrace = false;
0912     lineBeginsWithComma = false;
0913     lineIsCommentOnly = false;
0914     lineIsLineCommentOnly = false;
0915     shouldIndentBracedLine = true;
0916     isInAsmOneLine = false;
0917     lineOpensWithLineComment = false;
0918     lineOpensWithComment = false;
0919     lineStartsInComment = isInComment;
0920     previousLineProbationTab = false;
0921     lineOpeningBlocksNum = 0;
0922     lineClosingBlocksNum = 0;
0923     if (isImmediatelyPostObjCMethodDefinition)
0924         clearObjCMethodDefinitionAlignment();
0925     if (isImmediatelyPostObjCMethodCall)
0926     {
0927         isImmediatelyPostObjCMethodCall = false;
0928         isInObjCMethodCall = false;
0929         objCColonAlignSubsequent = 0;
0930     }
0931 
0932     // handle and remove white spaces around the line:
0933     // If not in comment, first find out size of white space before line,
0934     // so that possible comments starting in the line continue in
0935     // relation to the preliminary white-space.
0936     if (isInQuoteContinuation)
0937     {
0938         // trim a single space added by ASFormatter, otherwise leave it alone
0939         if (!(originalLine.length() == 1 && originalLine[0] == ' '))
0940             line = originalLine;
0941     }
0942     else if (isInComment || isInBeautifySQL)
0943     {
0944         // trim the end of comment and SQL lines
0945         line = originalLine;
0946         size_t trimEnd = line.find_last_not_of(" \t");
0947         if (trimEnd == string::npos)
0948             trimEnd = 0;
0949         else
0950             trimEnd++;
0951         if (trimEnd < line.length())
0952             line.erase(trimEnd);
0953         // does a brace open the line
0954         size_t firstChar = line.find_first_not_of(" \t");
0955         if (firstChar != string::npos)
0956         {
0957             if (line[firstChar] == '{')
0958                 lineBeginsWithOpenBrace = true;
0959             else if (line[firstChar] == '}')
0960                 lineBeginsWithCloseBrace = true;
0961             else if (line[firstChar] == ',')
0962                 lineBeginsWithComma = true;
0963         }
0964     }
0965     else
0966     {
0967         line = trim(originalLine);
0968         if (line.length() > 0)
0969         {
0970             if (line[0] == '{')
0971                 lineBeginsWithOpenBrace = true;
0972             else if (line[0] == '}')
0973                 lineBeginsWithCloseBrace = true;
0974             else if (line[0] == ',')
0975                 lineBeginsWithComma = true;
0976             else if (line.compare(0, 2, "//") == 0)
0977                 lineIsLineCommentOnly = true;
0978             else if (line.compare(0, 2, "/*") == 0)
0979             {
0980                 if (line.find("*/", 2) != string::npos)
0981                     lineIsCommentOnly = true;
0982             }
0983         }
0984 
0985         isInRunInComment = false;
0986         size_t j = line.find_first_not_of(" \t{");
0987         if (j != string::npos && line.compare(j, 2, "//") == 0)
0988             lineOpensWithLineComment = true;
0989         if (j != string::npos && line.compare(j, 2, "/*") == 0)
0990         {
0991             lineOpensWithComment = true;
0992             size_t k = line.find_first_not_of(" \t");
0993             if (k != string::npos && line.compare(k, 1, "{") == 0)
0994                 isInRunInComment = true;
0995         }
0996     }
0997 
0998     // When indent is OFF the lines must still be processed by ASBeautifier.
0999     // Otherwise the lines immediately following may not be indented correctly.
1000     if ((lineIsLineCommentOnly || lineIsCommentOnly)
1001             && line.find("*INDENT-OFF*", 0) != string::npos)
1002         isIndentModeOff = true;
1003 
1004     if (line.length() == 0)
1005     {
1006         if (backslashEndsPrevLine)
1007         {
1008             backslashEndsPrevLine = false;
1009             // check if this line ends a multi-line #define
1010             // if so, remove the #define's cloned beautifier from the active
1011             // beautifier stack and delete it.
1012             if (isInDefineDefinition && !isInDefine)
1013             {
1014                 isInDefineDefinition = false;
1015                 if (!activeBeautifierStack->empty())
1016                 {
1017                     ASBeautifier* defineBeautifier = activeBeautifierStack->back();
1018                     activeBeautifierStack->pop_back();
1019                     delete defineBeautifier;
1020                 }
1021             }
1022         }
1023         if (emptyLineFill && !isInQuoteContinuation)
1024         {
1025             if (isInIndentablePreprocBlock)
1026                 return preLineWS(preprocBlockIndent, 0);
1027             if (!headerStack->empty() || isInEnum)
1028                 return preLineWS(prevFinalLineIndentCount, prevFinalLineSpaceIndentCount);
1029             // must fall thru here
1030         }
1031         else
1032             return line;
1033     }
1034 
1035     // handle preprocessor commands
1036     if (isInIndentablePreprocBlock
1037             && line.length() > 0
1038             && line[0] != '#')
1039     {
1040         string indentedLine;
1041         if (isInClassHeaderTab || isInClassInitializer)
1042         {
1043             // parsing is turned off in ASFormatter by indent-off
1044             // the originalLine will probably never be returned here
1045             indentedLine = preLineWS(prevFinalLineIndentCount, prevFinalLineSpaceIndentCount) + line;
1046             return getIndentedLineReturn(indentedLine, originalLine);
1047         }
1048         indentedLine = preLineWS(preprocBlockIndent, 0) + line;
1049         return getIndentedLineReturn(indentedLine, originalLine);
1050     }
1051 
1052     if (!isInComment
1053             && !isInQuoteContinuation
1054             && line.length() > 0
1055             && ((line[0] == '#' && !isIndentedPreprocessor(line, 0))
1056                 || backslashEndsPrevLine))
1057     {
1058         if (line[0] == '#' && !isInDefine)
1059         {
1060             string preproc = extractPreprocessorStatement(line);
1061             processPreprocessor(preproc, line);
1062             if (isInIndentablePreprocBlock || isInIndentablePreproc)
1063             {
1064                 string indentedLine;
1065                 if ((preproc.length() >= 2 && preproc.substr(0, 2) == "if")) // #if, #ifdef, #ifndef
1066                 {
1067                     indentedLine = preLineWS(preprocBlockIndent, 0) + line;
1068                     preprocBlockIndent += 1;
1069                     isInIndentablePreprocBlock = true;
1070                 }
1071                 else if (preproc == "else" || preproc == "elif")
1072                 {
1073                     indentedLine = preLineWS(preprocBlockIndent - 1, 0) + line;
1074                 }
1075                 else if (preproc == "endif")
1076                 {
1077                     preprocBlockIndent -= 1;
1078                     indentedLine = preLineWS(preprocBlockIndent, 0) + line;
1079                     if (preprocBlockIndent == 0)
1080                         isInIndentablePreprocBlock = false;
1081                 }
1082                 else
1083                     indentedLine = preLineWS(preprocBlockIndent, 0) + line;
1084                 return getIndentedLineReturn(indentedLine, originalLine);
1085             }
1086             if (shouldIndentPreprocConditional && preproc.length() > 0)
1087             {
1088                 string indentedLine;
1089                 if (preproc.length() >= 2 && preproc.substr(0, 2) == "if") // #if, #ifdef, #ifndef
1090                 {
1091                     pair<int, int> entry;   // indentCount, spaceIndentCount
1092                     if (!isInDefine && activeBeautifierStack != nullptr && !activeBeautifierStack->empty())
1093                         entry = activeBeautifierStack->back()->computePreprocessorIndent();
1094                     else
1095                         entry = computePreprocessorIndent();
1096                     preprocIndentStack->emplace_back(entry);
1097                     indentedLine = preLineWS(preprocIndentStack->back().first,
1098                                              preprocIndentStack->back().second) + line;
1099                     return getIndentedLineReturn(indentedLine, originalLine);
1100                 }
1101                 if (preproc == "else" || preproc == "elif")
1102                 {
1103                     if (!preprocIndentStack->empty())   // if no entry don't indent
1104                     {
1105                         indentedLine = preLineWS(preprocIndentStack->back().first,
1106                                                  preprocIndentStack->back().second) + line;
1107                         return getIndentedLineReturn(indentedLine, originalLine);
1108                     }
1109                 }
1110                 else if (preproc == "endif")
1111                 {
1112                     if (!preprocIndentStack->empty())   // if no entry don't indent
1113                     {
1114                         indentedLine = preLineWS(preprocIndentStack->back().first,
1115                                                  preprocIndentStack->back().second) + line;
1116                         preprocIndentStack->pop_back();
1117                         return getIndentedLineReturn(indentedLine, originalLine);
1118                     }
1119                 }
1120             }
1121         }
1122 
1123         // check if the last char is a backslash
1124         if (line.length() > 0)
1125             backslashEndsPrevLine = (line[line.length() - 1] == '\\');
1126         // comments within the definition line can be continued without the backslash
1127         if (isInPreprocessorUnterminatedComment(line))
1128             backslashEndsPrevLine = true;
1129 
1130         // check if this line ends a multi-line #define
1131         // if so, use the #define's cloned beautifier for the line's indentation
1132         // and then remove it from the active beautifier stack and delete it.
1133         if (!backslashEndsPrevLine && isInDefineDefinition && !isInDefine)
1134         {
1135             isInDefineDefinition = false;
1136             // this could happen with invalid input
1137             if (activeBeautifierStack->empty())
1138                 return originalLine;
1139             ASBeautifier* defineBeautifier = activeBeautifierStack->back();
1140             activeBeautifierStack->pop_back();
1141 
1142             string indentedLine = defineBeautifier->beautify(line);
1143             delete defineBeautifier;
1144             return getIndentedLineReturn(indentedLine, originalLine);
1145         }
1146 
1147         // unless this is a multi-line #define, return this precompiler line as is.
1148         if (!isInDefine && !isInDefineDefinition)
1149             return originalLine;
1150     }
1151 
1152     // if there exists any worker beautifier in the activeBeautifierStack,
1153     // then use it instead of me to indent the current line.
1154     // variables set by ASFormatter must be updated.
1155     if (!isInDefine && activeBeautifierStack != nullptr && !activeBeautifierStack->empty())
1156     {
1157         activeBeautifierStack->back()->inLineNumber = inLineNumber;
1158         activeBeautifierStack->back()->runInIndentContinuation = runInIndentContinuation;
1159         activeBeautifierStack->back()->nonInStatementBrace = nonInStatementBrace;
1160         activeBeautifierStack->back()->objCColonAlignSubsequent = objCColonAlignSubsequent;
1161         activeBeautifierStack->back()->lineCommentNoBeautify = lineCommentNoBeautify;
1162         activeBeautifierStack->back()->isElseHeaderIndent = isElseHeaderIndent;
1163         activeBeautifierStack->back()->isCaseHeaderCommentIndent = isCaseHeaderCommentIndent;
1164         activeBeautifierStack->back()->isNonInStatementArray = isNonInStatementArray;
1165         activeBeautifierStack->back()->isSharpAccessor = isSharpAccessor;
1166         activeBeautifierStack->back()->isSharpDelegate = isSharpDelegate;
1167         activeBeautifierStack->back()->isInExternC = isInExternC;
1168         activeBeautifierStack->back()->isInBeautifySQL = isInBeautifySQL;
1169         activeBeautifierStack->back()->isInIndentableStruct = isInIndentableStruct;
1170         activeBeautifierStack->back()->isInIndentablePreproc = isInIndentablePreproc;
1171         // must return originalLine not the trimmed line
1172         return activeBeautifierStack->back()->beautify(originalLine);
1173     }
1174 
1175     // Flag an indented header in case this line is a one-line block.
1176     // The header in the header stack will be deleted by a one-line block.
1177     bool isInExtraHeaderIndent = false;
1178     if (!headerStack->empty()
1179             && lineBeginsWithOpenBrace
1180             && (headerStack->back() != &AS_OPEN_BRACE
1181                 || probationHeader != nullptr))
1182         isInExtraHeaderIndent = true;
1183 
1184     size_t iPrelim = headerStack->size();
1185 
1186     // calculate preliminary indentation based on headerStack and data from past lines
1187     computePreliminaryIndentation();
1188 
1189     // parse characters in the current line.
1190     parseCurrentLine(line);
1191 
1192     // handle special cases of indentation
1193     adjustParsedLineIndentation(iPrelim, isInExtraHeaderIndent);
1194 
1195     if (isInObjCMethodDefinition)
1196         adjustObjCMethodDefinitionIndentation(line);
1197 
1198     if (isInObjCMethodCall)
1199         adjustObjCMethodCallIndentation(line);
1200 
1201     if (isInDefine)
1202     {
1203         if (line.length() > 0 && line[0] == '#')
1204         {
1205             // the 'define' does not have to be attached to the '#'
1206             string preproc = trim(line.substr(1));
1207             if (preproc.compare(0, 6, "define") == 0)
1208             {
1209                 if (!continuationIndentStack->empty()
1210                         && continuationIndentStack->back() > 0)
1211                 {
1212                     defineIndentCount = indentCount;
1213                 }
1214                 else
1215                 {
1216                     defineIndentCount = indentCount - 1;
1217                     --indentCount;
1218                 }
1219             }
1220         }
1221 
1222         indentCount -= defineIndentCount;
1223     }
1224 
1225     if (indentCount < 0)
1226         indentCount = 0;
1227 
1228     if (lineCommentNoBeautify || blockCommentNoBeautify || isInQuoteContinuation)
1229         indentCount = spaceIndentCount = 0;
1230 
1231     // finally, insert indentations into beginning of line
1232 
1233     string indentedLine = preLineWS(indentCount, spaceIndentCount) + line;
1234     indentedLine = getIndentedLineReturn(indentedLine, originalLine);
1235 
1236     prevFinalLineSpaceIndentCount = spaceIndentCount;
1237     prevFinalLineIndentCount = indentCount;
1238 
1239     if (lastLineHeader != nullptr)
1240         previousLastLineHeader = lastLineHeader;
1241 
1242     if ((lineIsLineCommentOnly || lineIsCommentOnly)
1243             && line.find("*INDENT-ON*", 0) != string::npos)
1244         isIndentModeOff = false;
1245 
1246     return indentedLine;
1247 }
1248 
1249 const string& ASBeautifier::getIndentedLineReturn(const string& newLine, const string& originalLine) const
1250 {
1251     if (isIndentModeOff)
1252         return originalLine;
1253     return newLine;
1254 }
1255 
1256 string ASBeautifier::preLineWS(int lineIndentCount, int lineSpaceIndentCount) const
1257 {
1258     if (shouldForceTabIndentation)
1259     {
1260         if (tabLength != indentLength)
1261         {
1262             // adjust for different tab length
1263             int indentCountOrig = lineIndentCount;
1264             int spaceIndentCountOrig = lineSpaceIndentCount;
1265             lineIndentCount = ((indentCountOrig * indentLength) + spaceIndentCountOrig) / tabLength;
1266             lineSpaceIndentCount = ((indentCountOrig * indentLength) + spaceIndentCountOrig) % tabLength;
1267         }
1268         else
1269         {
1270             lineIndentCount += lineSpaceIndentCount / indentLength;
1271             lineSpaceIndentCount = lineSpaceIndentCount % indentLength;
1272         }
1273     }
1274 
1275     string ws;
1276     for (int i = 0; i < lineIndentCount; i++)
1277         ws += indentString;
1278     while ((lineSpaceIndentCount--) > 0)
1279         ws += string(" ");
1280     return ws;
1281 }
1282 
1283 /**
1284  * register a continuation indent.
1285  */
1286 void ASBeautifier::registerContinuationIndent(const string& line, int i, int spaceIndentCount_,
1287                                               int tabIncrementIn, int minIndent, bool updateParenStack)
1288 {
1289     assert(i >= -1);
1290     int remainingCharNum = line.length() - i;
1291     int nextNonWSChar = getNextProgramCharDistance(line, i);
1292 
1293     // if indent is around the last char in the line OR indent-after-paren is requested,
1294     // indent with the continuation indent
1295     if (nextNonWSChar == remainingCharNum || shouldIndentAfterParen)
1296     {
1297         int previousIndent = spaceIndentCount_;
1298         if (!continuationIndentStack->empty())
1299             previousIndent = continuationIndentStack->back();
1300         int currIndent = continuationIndent * indentLength + previousIndent;
1301         if (currIndent > maxContinuationIndent && line[i] != '{')
1302             currIndent = indentLength * 2 + spaceIndentCount_;
1303         continuationIndentStack->emplace_back(currIndent);
1304         if (updateParenStack)
1305             parenIndentStack->emplace_back(previousIndent);
1306         return;
1307     }
1308 
1309     if (updateParenStack)
1310     {
1311         parenIndentStack->emplace_back(i + spaceIndentCount_ - runInIndentContinuation);
1312         if (parenIndentStack->back() < 0)
1313             parenIndentStack->back() = 0;
1314     }
1315 
1316     int tabIncrement = tabIncrementIn;
1317 
1318     // check for following tabs
1319     for (int j = i + 1; j < (i + nextNonWSChar); j++)
1320     {
1321         if (line[j] == '\t')
1322             tabIncrement += convertTabToSpaces(j, tabIncrement);
1323     }
1324 
1325     int continuationIndentCount = i + nextNonWSChar + spaceIndentCount_ + tabIncrement;
1326 
1327     // check for run-in statement
1328     if (i > 0 && line[0] == '{')
1329         continuationIndentCount -= indentLength;
1330 
1331     if (continuationIndentCount < minIndent)
1332         continuationIndentCount = minIndent + spaceIndentCount_;
1333 
1334     // this is not done for an in-statement array
1335     if (continuationIndentCount > maxContinuationIndent
1336             && !(prevNonLegalCh == '=' && currentNonLegalCh == '{'))
1337         continuationIndentCount = indentLength * 2 + spaceIndentCount_;
1338 
1339     if (!continuationIndentStack->empty()
1340             && continuationIndentCount < continuationIndentStack->back())
1341         continuationIndentCount = continuationIndentStack->back();
1342 
1343     // the block opener is not indented for a NonInStatementArray
1344     if ((isNonInStatementArray && i >= 0 && line[i] == '{')
1345             && !isInEnum && !braceBlockStateStack->empty() && braceBlockStateStack->back())
1346         continuationIndentCount = 0;
1347 
1348     continuationIndentStack->emplace_back(continuationIndentCount);
1349 }
1350 
1351 /**
1352 * Register a continuation indent for a class header or a class initializer colon.
1353 */
1354 void ASBeautifier::registerContinuationIndentColon(const string& line, int i, int tabIncrementIn)
1355 {
1356     assert(line[i] == ':');
1357     assert(isInClassInitializer || isInClassHeaderTab);
1358 
1359     // register indent at first word after the colon
1360     size_t firstChar = line.find_first_not_of(" \t");
1361     if (firstChar == (size_t) i)        // firstChar is ':'
1362     {
1363         size_t firstWord = line.find_first_not_of(" \t", firstChar + 1);
1364         if (firstWord != string::npos)
1365         {
1366             int continuationIndentCount = firstWord + spaceIndentCount + tabIncrementIn;
1367             continuationIndentStack->emplace_back(continuationIndentCount);
1368             isContinuation = true;
1369         }
1370     }
1371 }
1372 
1373 /**
1374  * Compute indentation for a preprocessor #if statement.
1375  * This may be called for the activeBeautiferStack
1376  * instead of the active ASBeautifier object.
1377  */
1378 pair<int, int> ASBeautifier::computePreprocessorIndent()
1379 {
1380     computePreliminaryIndentation();
1381     pair<int, int> entry(indentCount, spaceIndentCount);
1382     if (!headerStack->empty()
1383             && entry.first > 0
1384             && (headerStack->back() == &AS_IF
1385                 || headerStack->back() == &AS_ELSE
1386                 || headerStack->back() == &AS_FOR
1387                 || headerStack->back() == &AS_WHILE))
1388         --entry.first;
1389     return entry;
1390 }
1391 
1392 /**
1393  * get distance to the next non-white space, non-comment character in the line.
1394  * if no such character exists, return the length remaining to the end of the line.
1395  */
1396 int ASBeautifier::getNextProgramCharDistance(const string& line, int i) const
1397 {
1398     bool inComment = false;
1399     int  remainingCharNum = line.length() - i;
1400     int  charDistance;
1401     char ch;
1402 
1403     for (charDistance = 1; charDistance < remainingCharNum; charDistance++)
1404     {
1405         ch = line[i + charDistance];
1406         if (inComment)
1407         {
1408             if (line.compare(i + charDistance, 2, "*/") == 0)
1409             {
1410                 charDistance++;
1411                 inComment = false;
1412             }
1413             continue;
1414         }
1415         else if (isWhiteSpace(ch))
1416             continue;
1417         else if (ch == '/')
1418         {
1419             if (line.compare(i + charDistance, 2, "//") == 0)
1420                 return remainingCharNum;
1421             if (line.compare(i + charDistance, 2, "/*") == 0)
1422             {
1423                 charDistance++;
1424                 inComment = true;
1425             }
1426         }
1427         else
1428             return charDistance;
1429     }
1430 
1431     return charDistance;
1432 }
1433 
1434 /**
1435  * find the index number of a string element in a container of strings
1436  *
1437  * @return              the index number of element in the container. -1 if element not found.
1438  * @param container     a vector of strings.
1439  * @param element       the element to find .
1440  */
1441 int ASBeautifier::indexOf(const vector<const string*>& container, const string* element) const
1442 {
1443     vector<const string*>::const_iterator where;
1444 
1445     where = find(container.begin(), container.end(), element);
1446     if (where == container.end())
1447         return -1;
1448     return (int) (where - container.begin());
1449 }
1450 
1451 /**
1452  * convert tabs to spaces.
1453  * i is the position of the character to convert to spaces.
1454  * tabIncrementIn is the increment that must be added for tab indent characters
1455  *     to get the correct column for the current tab.
1456  */
1457 int ASBeautifier::convertTabToSpaces(int i, int tabIncrementIn) const
1458 {
1459     int tabToSpacesAdjustment = indentLength - 1 - ((tabIncrementIn + i) % indentLength);
1460     return tabToSpacesAdjustment;
1461 }
1462 
1463 /**
1464  * trim removes the white space surrounding a line.
1465  *
1466  * @return          the trimmed line.
1467  * @param str       the line to trim.
1468  */
1469 string ASBeautifier::trim(const string& str) const
1470 {
1471     int start = 0;
1472     int end = str.length() - 1;
1473 
1474     while (start < end && isWhiteSpace(str[start]))
1475         start++;
1476 
1477     while (start <= end && isWhiteSpace(str[end]))
1478         end--;
1479 
1480     // don't trim if it ends in a continuation
1481     if (end > -1 && str[end] == '\\')
1482         end = str.length() - 1;
1483 
1484     string returnStr(str, start, end + 1 - start);
1485     return returnStr;
1486 }
1487 
1488 /**
1489  * rtrim removes the white space from the end of a line.
1490  *
1491  * @return          the trimmed line.
1492  * @param str       the line to trim.
1493  */
1494 string ASBeautifier::rtrim(const string& str) const
1495 {
1496     size_t len = str.length();
1497     size_t end = str.find_last_not_of(" \t");
1498     if (end == string::npos
1499             || end == len - 1)
1500         return str;
1501     string returnStr(str, 0, end + 1);
1502     return returnStr;
1503 }
1504 
1505 /**
1506  * Copy tempStacks for the copy constructor.
1507  * The value of the vectors must also be copied.
1508  */
1509 vector<vector<const string*>*>* ASBeautifier::copyTempStacks(const ASBeautifier& other) const
1510 {
1511     vector<vector<const string*>*>* tempStacksNew = new vector<vector<const string*>*>;
1512     vector<vector<const string*>*>::iterator iter;
1513     for (iter = other.tempStacks->begin();
1514             iter != other.tempStacks->end();
1515             ++iter)
1516     {
1517         vector<const string*>* newVec = new vector<const string*>;
1518         *newVec = **iter;
1519         tempStacksNew->emplace_back(newVec);
1520     }
1521     return tempStacksNew;
1522 }
1523 
1524 /**
1525  * delete a member vectors to eliminate memory leak reporting
1526  */
1527 void ASBeautifier::deleteBeautifierVectors()
1528 {
1529     beautifierFileType = 9;     // reset to an invalid type
1530     delete headers;
1531     delete nonParenHeaders;
1532     delete preBlockStatements;
1533     delete preCommandHeaders;
1534     delete assignmentOperators;
1535     delete nonAssignmentOperators;
1536     delete indentableHeaders;
1537 }
1538 
1539 /**
1540  * delete a vector object
1541  * T is the type of vector
1542  * used for all vectors except tempStacks
1543  */
1544 template<typename T>
1545 void ASBeautifier::deleteContainer(T& container)
1546 {
1547     if (container != nullptr)
1548     {
1549         container->clear();
1550         delete (container);
1551         container = nullptr;
1552     }
1553 }
1554 
1555 /**
1556  * Delete the ASBeautifier vector object.
1557  * This is a vector of pointers to ASBeautifier objects allocated with the 'new' operator.
1558  * Therefore the ASBeautifier objects have to be deleted in addition to the
1559  * ASBeautifier pointer entries.
1560  */
1561 void ASBeautifier::deleteBeautifierContainer(vector<ASBeautifier*>*& container)
1562 {
1563     if (container != nullptr)
1564     {
1565         vector<ASBeautifier*>::iterator iter = container->begin();
1566         while (iter < container->end())
1567         {
1568             delete *iter;
1569             ++iter;
1570         }
1571         container->clear();
1572         delete (container);
1573         container = nullptr;
1574     }
1575 }
1576 
1577 /**
1578  * Delete the tempStacks vector object.
1579  * The tempStacks is a vector of pointers to strings allocated with the 'new' operator.
1580  * Therefore the strings have to be deleted in addition to the tempStacks entries.
1581  */
1582 void ASBeautifier::deleteTempStacksContainer(vector<vector<const string*>*>*& container)
1583 {
1584     if (container != nullptr)
1585     {
1586         vector<vector<const string*>*>::iterator iter = container->begin();
1587         while (iter < container->end())
1588         {
1589             delete *iter;
1590             ++iter;
1591         }
1592         container->clear();
1593         delete (container);
1594         container = nullptr;
1595     }
1596 }
1597 
1598 /**
1599  * initialize a vector object
1600  * T is the type of vector used for all vectors
1601  */
1602 template<typename T>
1603 void ASBeautifier::initContainer(T& container, T value)
1604 {
1605     // since the ASFormatter object is never deleted,
1606     // the existing vectors must be deleted before creating new ones
1607     if (container != nullptr)
1608         deleteContainer(container);
1609     container = value;
1610 }
1611 
1612 /**
1613  * Initialize the tempStacks vector object.
1614  * The tempStacks is a vector of pointers to strings allocated with the 'new' operator.
1615  * Any residual entries are deleted before the vector is initialized.
1616  */
1617 void ASBeautifier::initTempStacksContainer(vector<vector<const string*>*>*& container,
1618                                            vector<vector<const string*>*>* value)
1619 {
1620     if (container != nullptr)
1621         deleteTempStacksContainer(container);
1622     container = value;
1623 }
1624 
1625 /**
1626  * Determine if an assignment statement ends with a comma
1627  *     that is not in a function argument. It ends with a
1628  *     comma if a comma is the last char on the line.
1629  *
1630  * @return  true if line ends with a comma, otherwise false.
1631  */
1632 bool ASBeautifier::statementEndsWithComma(const string& line, int index) const
1633 {
1634     assert(line[index] == '=');
1635 
1636     bool isInComment_ = false;
1637     bool isInQuote_ = false;
1638     int parenCount = 0;
1639     size_t lineLength = line.length();
1640     size_t i = 0;
1641     char quoteChar_ = ' ';
1642 
1643     for (i = index + 1; i < lineLength; ++i)
1644     {
1645         char ch = line[i];
1646 
1647         if (isInComment_)
1648         {
1649             if (line.compare(i, 2, "*/") == 0)
1650             {
1651                 isInComment_ = false;
1652                 ++i;
1653             }
1654             continue;
1655         }
1656 
1657         if (ch == '\\')
1658         {
1659             ++i;
1660             continue;
1661         }
1662 
1663         if (isInQuote_)
1664         {
1665             if (ch == quoteChar_)
1666                 isInQuote_ = false;
1667             continue;
1668         }
1669 
1670         if (ch == '"'
1671                 || (ch == '\'' && !isDigitSeparator(line, i)))
1672         {
1673             isInQuote_ = true;
1674             quoteChar_ = ch;
1675             continue;
1676         }
1677 
1678         if (line.compare(i, 2, "//") == 0)
1679             break;
1680 
1681         if (line.compare(i, 2, "/*") == 0)
1682         {
1683             if (isLineEndComment(line, i))
1684                 break;
1685             else
1686             {
1687                 isInComment_ = true;
1688                 ++i;
1689                 continue;
1690             }
1691         }
1692 
1693         if (ch == '(')
1694             parenCount++;
1695         if (ch == ')')
1696             parenCount--;
1697     }
1698     if (isInComment_
1699             || isInQuote_
1700             || parenCount > 0)
1701         return false;
1702 
1703     size_t lastChar = line.find_last_not_of(" \t", i - 1);
1704 
1705     if (lastChar == string::npos || line[lastChar] != ',')
1706         return false;
1707 
1708     return true;
1709 }
1710 
1711 /**
1712  * check if current comment is a line-end comment
1713  *
1714  * @return     is before a line-end comment.
1715  */
1716 bool ASBeautifier::isLineEndComment(const string& line, int startPos) const
1717 {
1718     assert(line.compare(startPos, 2, "/*") == 0);
1719 
1720     // comment must be closed on this line with nothing after it
1721     size_t endNum = line.find("*/", startPos + 2);
1722     if (endNum != string::npos)
1723     {
1724         size_t nextChar = line.find_first_not_of(" \t", endNum + 2);
1725         if (nextChar == string::npos)
1726             return true;
1727     }
1728     return false;
1729 }
1730 
1731 /**
1732  * get the previous word index for an assignment operator
1733  *
1734  * @return is the index to the previous word (the in statement indent).
1735  */
1736 int ASBeautifier::getContinuationIndentAssign(const string& line, size_t currPos) const
1737 {
1738     assert(line[currPos] == '=');
1739 
1740     if (currPos == 0)
1741         return 0;
1742 
1743     // get the last legal word (may be a number)
1744     size_t end = line.find_last_not_of(" \t", currPos - 1);
1745     if (end == string::npos || !isLegalNameChar(line[end]))
1746         return 0;
1747 
1748     int start;          // start of the previous word
1749     for (start = end; start > -1; start--)
1750     {
1751         if (!isLegalNameChar(line[start]))
1752             break;
1753     }
1754     start++;
1755 
1756     return start;
1757 }
1758 
1759 /**
1760  * get the instatement indent for a comma
1761  *
1762  * @return is the indent to the second word on the line (the in statement indent).
1763  */
1764 int ASBeautifier::getContinuationIndentComma(const string& line, size_t currPos) const
1765 {
1766     assert(line[currPos] == ',');
1767 
1768     // get first word on a line
1769     size_t indent = line.find_first_not_of(" \t");
1770     if (indent == string::npos || !isLegalNameChar(line[indent]))
1771         return 0;
1772 
1773     // bypass first word
1774     for (; indent < currPos; indent++)
1775     {
1776         if (!isLegalNameChar(line[indent]))
1777             break;
1778     }
1779     indent++;
1780     if (indent >= currPos || indent < 4)
1781         return 0;
1782 
1783     // point to second word or assignment operator
1784     indent = line.find_first_not_of(" \t", indent);
1785     if (indent == string::npos || indent >= currPos)
1786         return 0;
1787 
1788     return indent;
1789 }
1790 
1791 /**
1792  * get the next word on a line
1793  * the argument 'currPos' must point to the current position.
1794  *
1795  * @return is the next word or an empty string if none found.
1796  */
1797 string ASBeautifier::getNextWord(const string& line, size_t currPos) const
1798 {
1799     size_t lineLength = line.length();
1800     // get the last legal word (may be a number)
1801     if (currPos == lineLength - 1)
1802         return string();
1803 
1804     size_t start = line.find_first_not_of(" \t", currPos + 1);
1805     if (start == string::npos || !isLegalNameChar(line[start]))
1806         return string();
1807 
1808     size_t end;         // end of the current word
1809     for (end = start + 1; end <= lineLength; end++)
1810     {
1811         if (!isLegalNameChar(line[end]) || line[end] == '.')
1812             break;
1813     }
1814 
1815     return line.substr(start, end - start);
1816 }
1817 
1818 /**
1819  * Check if a preprocessor directive is always indented.
1820  * C# "region" and "endregion" are always indented.
1821  * C/C++ "pragma omp" is always indented.
1822  *
1823  * @return is true or false.
1824  */
1825 bool ASBeautifier::isIndentedPreprocessor(const string& line, size_t currPos) const
1826 {
1827     assert(line[0] == '#');
1828     string nextWord = getNextWord(line, currPos);
1829     if (nextWord == "region" || nextWord == "endregion")
1830         return true;
1831     // is it #pragma omp
1832     if (nextWord == "pragma")
1833     {
1834         // find pragma
1835         size_t start = line.find("pragma");
1836         if (start == string::npos || !isLegalNameChar(line[start]))
1837             return false;
1838         // bypass pragma
1839         for (; start < line.length(); start++)
1840         {
1841             if (!isLegalNameChar(line[start]))
1842                 break;
1843         }
1844         start++;
1845         if (start >= line.length())
1846             return false;
1847         // point to start of second word
1848         start = line.find_first_not_of(" \t", start);
1849         if (start == string::npos)
1850             return false;
1851         // point to end of second word
1852         size_t end;
1853         for (end = start; end < line.length(); end++)
1854         {
1855             if (!isLegalNameChar(line[end]))
1856                 break;
1857         }
1858         // check for "pragma omp"
1859         string word = line.substr(start, end - start);
1860         if (word == "omp" || word == "region" || word == "endregion")
1861             return true;
1862     }
1863     return false;
1864 }
1865 
1866 /**
1867  * Check if a preprocessor directive is checking for __cplusplus defined.
1868  *
1869  * @return is true or false.
1870  */
1871 bool ASBeautifier::isPreprocessorConditionalCplusplus(const string& line) const
1872 {
1873     string preproc = trim(line.substr(1));
1874     if (preproc.compare(0, 5, "ifdef") == 0 && getNextWord(preproc, 4) == "__cplusplus")
1875         return true;
1876     if (preproc.compare(0, 2, "if") == 0)
1877     {
1878         // check for " #if defined(__cplusplus)"
1879         size_t charNum = 2;
1880         charNum = preproc.find_first_not_of(" \t", charNum);
1881         if (charNum != string::npos && preproc.compare(charNum, 7, "defined") == 0)
1882         {
1883             charNum += 7;
1884             charNum = preproc.find_first_not_of(" \t", charNum);
1885             if (charNum != string::npos && preproc.compare(charNum, 1, "(") == 0)
1886             {
1887                 ++charNum;
1888                 charNum = preproc.find_first_not_of(" \t", charNum);
1889                 if (charNum != string::npos && preproc.compare(charNum, 11, "__cplusplus") == 0)
1890                     return true;
1891             }
1892         }
1893     }
1894     return false;
1895 }
1896 
1897 /**
1898  * Check if a preprocessor definition contains an unterminated comment.
1899  * Comments within a preprocessor definition can be continued without the backslash.
1900  *
1901  * @return is true or false.
1902  */
1903 bool ASBeautifier::isInPreprocessorUnterminatedComment(const string& line)
1904 {
1905     if (!isInPreprocessorComment)
1906     {
1907         size_t startPos = line.find("/*");
1908         if (startPos == string::npos)
1909             return false;
1910     }
1911     size_t endNum = line.find("*/");
1912     if (endNum != string::npos)
1913     {
1914         isInPreprocessorComment = false;
1915         return false;
1916     }
1917     isInPreprocessorComment = true;
1918     return true;
1919 }
1920 
1921 void ASBeautifier::popLastContinuationIndent()
1922 {
1923     assert(!continuationIndentStackSizeStack->empty());
1924     int previousIndentStackSize = continuationIndentStackSizeStack->back();
1925     if (continuationIndentStackSizeStack->size() > 1)
1926         continuationIndentStackSizeStack->pop_back();
1927     while (previousIndentStackSize < (int) continuationIndentStack->size())
1928         continuationIndentStack->pop_back();
1929 }
1930 
1931 // for unit testing
1932 int ASBeautifier::getBeautifierFileType() const
1933 { return beautifierFileType; }
1934 
1935 /**
1936  * Process preprocessor statements and update the beautifier stacks.
1937  */
1938 void ASBeautifier::processPreprocessor(const string& preproc, const string& line)
1939 {
1940     // When finding a multi-lined #define statement, the original beautifier
1941     // 1. sets its isInDefineDefinition flag
1942     // 2. clones a new beautifier that will be used for the actual indentation
1943     //    of the #define. This clone is put into the activeBeautifierStack in order
1944     //    to be called for the actual indentation.
1945     // The original beautifier will have isInDefineDefinition = true, isInDefine = false
1946     // The cloned beautifier will have   isInDefineDefinition = true, isInDefine = true
1947     if (shouldIndentPreprocDefine && preproc == "define" && line[line.length() - 1] == '\\')
1948     {
1949         if (!isInDefineDefinition)
1950         {
1951             // this is the original beautifier
1952             isInDefineDefinition = true;
1953 
1954             // push a new beautifier into the active stack
1955             // this beautifier will be used for the indentation of this define
1956             ASBeautifier* defineBeautifier = new ASBeautifier(*this);
1957             activeBeautifierStack->emplace_back(defineBeautifier);
1958         }
1959         else
1960         {
1961             // the is the cloned beautifier that is in charge of indenting the #define.
1962             isInDefine = true;
1963         }
1964     }
1965     else if (preproc.length() >= 2 && preproc.substr(0, 2) == "if")
1966     {
1967         if (isPreprocessorConditionalCplusplus(line) && !g_preprocessorCppExternCBrace)
1968             g_preprocessorCppExternCBrace = 1;
1969         // push a new beautifier into the stack
1970         waitingBeautifierStackLengthStack->push_back(waitingBeautifierStack->size());
1971         activeBeautifierStackLengthStack->push_back(activeBeautifierStack->size());
1972         if (activeBeautifierStackLengthStack->back() == 0)
1973             waitingBeautifierStack->emplace_back(new ASBeautifier(*this));
1974         else
1975             waitingBeautifierStack->emplace_back(new ASBeautifier(*activeBeautifierStack->back()));
1976     }
1977     else if (preproc == "else")
1978     {
1979         if ((waitingBeautifierStack != nullptr) && !waitingBeautifierStack->empty())
1980         {
1981             // MOVE current waiting beautifier to active stack.
1982             activeBeautifierStack->emplace_back(waitingBeautifierStack->back());
1983             waitingBeautifierStack->pop_back();
1984         }
1985     }
1986     else if (preproc == "elif")
1987     {
1988         if ((waitingBeautifierStack != nullptr) && !waitingBeautifierStack->empty())
1989         {
1990             // append a COPY current waiting beautifier to active stack, WITHOUT deleting the original.
1991             activeBeautifierStack->emplace_back(new ASBeautifier(*(waitingBeautifierStack->back())));
1992         }
1993     }
1994     else if (preproc == "endif")
1995     {
1996         int stackLength = 0;
1997         ASBeautifier* beautifier = nullptr;
1998 
1999         if (waitingBeautifierStackLengthStack != nullptr && !waitingBeautifierStackLengthStack->empty())
2000         {
2001             stackLength = waitingBeautifierStackLengthStack->back();
2002             waitingBeautifierStackLengthStack->pop_back();
2003             while ((int) waitingBeautifierStack->size() > stackLength)
2004             {
2005                 beautifier = waitingBeautifierStack->back();
2006                 waitingBeautifierStack->pop_back();
2007                 delete beautifier;
2008             }
2009         }
2010 
2011         if (!activeBeautifierStackLengthStack->empty())
2012         {
2013             stackLength = activeBeautifierStackLengthStack->back();
2014             activeBeautifierStackLengthStack->pop_back();
2015             while ((int) activeBeautifierStack->size() > stackLength)
2016             {
2017                 beautifier = activeBeautifierStack->back();
2018                 activeBeautifierStack->pop_back();
2019                 delete beautifier;
2020             }
2021         }
2022     }
2023 }
2024 
2025 // Compute the preliminary indentation based on data in the headerStack
2026 // and data from previous lines.
2027 // Update the class variable indentCount.
2028 void ASBeautifier::computePreliminaryIndentation()
2029 {
2030     indentCount = 0;
2031     spaceIndentCount = 0;
2032     isInClassHeaderTab = false;
2033 
2034     if (isInObjCMethodDefinition && !continuationIndentStack->empty())
2035         spaceIndentObjCMethodAlignment = continuationIndentStack->back();
2036 
2037     if (!continuationIndentStack->empty())
2038         spaceIndentCount = continuationIndentStack->back();
2039 
2040     for (size_t i = 0; i < headerStack->size(); i++)
2041     {
2042         isInClass = false;
2043 
2044         if (blockIndent)
2045         {
2046             // do NOT indent opening block for these headers
2047             if (!((*headerStack)[i] == &AS_NAMESPACE
2048                     || (*headerStack)[i] == &AS_MODULE
2049                     || (*headerStack)[i] == &AS_CLASS
2050                     || (*headerStack)[i] == &AS_STRUCT
2051                     || (*headerStack)[i] == &AS_UNION
2052                     || (*headerStack)[i] == &AS_INTERFACE
2053                     || (*headerStack)[i] == &AS_THROWS
2054                     || (*headerStack)[i] == &AS_STATIC))
2055                 ++indentCount;
2056         }
2057         else if (!(i > 0 && (*headerStack)[i - 1] != &AS_OPEN_BRACE
2058                    && (*headerStack)[i] == &AS_OPEN_BRACE))
2059             ++indentCount;
2060 
2061         if (!isJavaStyle() && !namespaceIndent && i > 0
2062                 && ((*headerStack)[i - 1] == &AS_NAMESPACE
2063                     || (*headerStack)[i - 1] == &AS_MODULE)
2064                 && (*headerStack)[i] == &AS_OPEN_BRACE)
2065             --indentCount;
2066 
2067         if (isCStyle() && i >= 1
2068                 && (*headerStack)[i - 1] == &AS_CLASS
2069                 && (*headerStack)[i] == &AS_OPEN_BRACE)
2070         {
2071             if (classIndent)
2072                 ++indentCount;
2073             isInClass = true;
2074         }
2075 
2076         // is the switchIndent option is on, indent switch statements an additional indent.
2077         else if (switchIndent && i > 1
2078                  && (*headerStack)[i - 1] == &AS_SWITCH
2079                  && (*headerStack)[i] == &AS_OPEN_BRACE)
2080         {
2081             ++indentCount;
2082             isInSwitch = true;
2083         }
2084 
2085     }   // end of for loop
2086 
2087     if (isInClassHeader)
2088     {
2089         if (!isJavaStyle())
2090             isInClassHeaderTab = true;
2091         if (lineOpensWithLineComment || lineStartsInComment || lineOpensWithComment)
2092         {
2093             if (!lineBeginsWithOpenBrace)
2094                 --indentCount;
2095             if (!continuationIndentStack->empty())
2096                 spaceIndentCount -= continuationIndentStack->back();
2097         }
2098         else if (blockIndent)
2099         {
2100             if (!lineBeginsWithOpenBrace)
2101                 ++indentCount;
2102         }
2103     }
2104 
2105     if (isInClassInitializer || isInEnumTypeID)
2106     {
2107         indentCount += classInitializerIndents;
2108     }
2109 
2110     if (isInEnum && lineBeginsWithComma && !continuationIndentStack->empty())
2111     {
2112         // unregister '=' indent from the previous line
2113         continuationIndentStack->pop_back();
2114         isContinuation = false;
2115         spaceIndentCount = 0;
2116     }
2117 
2118     // Objective-C interface continuation line
2119     if (isInObjCInterface)
2120         ++indentCount;
2121 
2122     // unindent a class closing brace...
2123     if (!lineStartsInComment
2124             && isCStyle()
2125             && isInClass
2126             && classIndent
2127             && headerStack->size() >= 2
2128             && (*headerStack)[headerStack->size() - 2] == &AS_CLASS
2129             && (*headerStack)[headerStack->size() - 1] == &AS_OPEN_BRACE
2130             && lineBeginsWithCloseBrace
2131             && braceBlockStateStack->back())
2132         --indentCount;
2133 
2134     // unindent an indented switch closing brace...
2135     else if (!lineStartsInComment
2136              && isInSwitch
2137              && switchIndent
2138              && headerStack->size() >= 2
2139              && (*headerStack)[headerStack->size() - 2] == &AS_SWITCH
2140              && (*headerStack)[headerStack->size() - 1] == &AS_OPEN_BRACE
2141              && lineBeginsWithCloseBrace)
2142         --indentCount;
2143 
2144     // handle special case of run-in comment in an indented class statement
2145     if (isInClass
2146             && classIndent
2147             && isInRunInComment
2148             && !lineOpensWithComment
2149             && headerStack->size() > 1
2150             && (*headerStack)[headerStack->size() - 2] == &AS_CLASS)
2151         --indentCount;
2152 
2153     if (isInConditional)
2154         --indentCount;
2155     if (g_preprocessorCppExternCBrace >= 4)
2156         --indentCount;
2157 }
2158 
2159 void ASBeautifier::adjustParsedLineIndentation(size_t iPrelim, bool isInExtraHeaderIndent)
2160 {
2161     if (lineStartsInComment)
2162         return;
2163 
2164     // unindent a one-line statement in a header indent
2165     if (!blockIndent
2166             && lineBeginsWithOpenBrace
2167             && headerStack->size() < iPrelim
2168             && isInExtraHeaderIndent
2169             && (lineOpeningBlocksNum > 0 && lineOpeningBlocksNum <= lineClosingBlocksNum)
2170             && shouldIndentBracedLine)
2171         --indentCount;
2172 
2173     /*
2174      * if '{' doesn't follow an immediately previous '{' in the headerStack
2175      * (but rather another header such as "for" or "if", then unindent it
2176      * by one indentation relative to its block.
2177      */
2178     else if (!blockIndent
2179              && lineBeginsWithOpenBrace
2180              && !(lineOpeningBlocksNum > 0 && lineOpeningBlocksNum <= lineClosingBlocksNum)
2181              && (headerStack->size() > 1 && (*headerStack)[headerStack->size() - 2] != &AS_OPEN_BRACE)
2182              && shouldIndentBracedLine)
2183         --indentCount;
2184 
2185     // must check one less in headerStack if more than one header on a line (allow-addins)...
2186     else if (headerStack->size() > iPrelim + 1
2187              && !blockIndent
2188              && lineBeginsWithOpenBrace
2189              && !(lineOpeningBlocksNum > 0 && lineOpeningBlocksNum <= lineClosingBlocksNum)
2190              && (headerStack->size() > 2 && (*headerStack)[headerStack->size() - 3] != &AS_OPEN_BRACE)
2191              && shouldIndentBracedLine)
2192         --indentCount;
2193 
2194     // unindent a closing brace...
2195     else if (lineBeginsWithCloseBrace
2196              && shouldIndentBracedLine)
2197         --indentCount;
2198 
2199     // correctly indent one-line-blocks...
2200     else if (lineOpeningBlocksNum > 0
2201              && lineOpeningBlocksNum == lineClosingBlocksNum
2202              && previousLineProbationTab)
2203         --indentCount;
2204 
2205     if (indentCount < 0)
2206         indentCount = 0;
2207 
2208     // take care of extra brace indentation option...
2209     if (!lineStartsInComment
2210             && braceIndent
2211             && shouldIndentBracedLine
2212             && (lineBeginsWithOpenBrace || lineBeginsWithCloseBrace))
2213     {
2214         if (!braceIndentVtk)
2215             ++indentCount;
2216         else
2217         {
2218             // determine if a style VTK brace is indented
2219             bool haveUnindentedBrace = false;
2220             for (size_t i = 0; i < headerStack->size(); i++)
2221             {
2222                 if (((*headerStack)[i] == &AS_NAMESPACE
2223                         || (*headerStack)[i] == &AS_MODULE
2224                         || (*headerStack)[i] == &AS_CLASS
2225                         || (*headerStack)[i] == &AS_STRUCT)
2226                         && i + 1 < headerStack->size()
2227                         && (*headerStack)[i + 1] == &AS_OPEN_BRACE)
2228                     i++;
2229                 else if (lineBeginsWithOpenBrace)
2230                 {
2231                     // don't double count the current brace
2232                     if (i + 1 < headerStack->size()
2233                             && (*headerStack)[i] == &AS_OPEN_BRACE)
2234                         haveUnindentedBrace = true;
2235                 }
2236                 else if ((*headerStack)[i] == &AS_OPEN_BRACE)
2237                     haveUnindentedBrace = true;
2238             }   // end of for loop
2239             if (haveUnindentedBrace)
2240                 ++indentCount;
2241         }
2242     }
2243 }
2244 
2245 /**
2246  * Compute indentCount adjustment when in a series of else-if statements
2247  * and shouldBreakElseIfs is requested.
2248  * It increments by one for each 'else' in the tempStack.
2249  */
2250 int ASBeautifier::adjustIndentCountForBreakElseIfComments() const
2251 {
2252     assert(isElseHeaderIndent && !tempStacks->empty());
2253     int indentCountIncrement = 0;
2254     vector<const string*>* lastTempStack = tempStacks->back();
2255     if (lastTempStack != nullptr)
2256     {
2257         for (size_t i = 0; i < lastTempStack->size(); i++)
2258         {
2259             if (*lastTempStack->at(i) == AS_ELSE)
2260                 indentCountIncrement++;
2261         }
2262     }
2263     return indentCountIncrement;
2264 }
2265 
2266 /**
2267  * Extract a preprocessor statement without the #.
2268  * If a error occurs an empty string is returned.
2269  */
2270 string ASBeautifier::extractPreprocessorStatement(const string& line) const
2271 {
2272     string preproc;
2273     size_t start = line.find_first_not_of("#/ \t");
2274     if (start == string::npos)
2275         return preproc;
2276     size_t end = line.find_first_of("/ \t", start);
2277     if (end == string::npos)
2278         end = line.length();
2279     preproc = line.substr(start, end - start);
2280     return preproc;
2281 }
2282 
2283 void ASBeautifier::adjustObjCMethodDefinitionIndentation(const string& line_)
2284 {
2285     // register indent for Objective-C continuation line
2286     if (line_.length() > 0
2287             && (line_[0] == '-' || line_[0] == '+'))
2288     {
2289         if (shouldAlignMethodColon && objCColonAlignSubsequent != -1)
2290         {
2291             string convertedLine = getIndentedSpaceEquivalent(line_);
2292             colonIndentObjCMethodAlignment = findObjCColonAlignment(convertedLine);
2293             int objCColonAlignSubsequentIndent = objCColonAlignSubsequent + indentLength;
2294             if (objCColonAlignSubsequentIndent > colonIndentObjCMethodAlignment)
2295                 colonIndentObjCMethodAlignment = objCColonAlignSubsequentIndent;
2296         }
2297         else if (continuationIndentStack->empty()
2298                  || continuationIndentStack->back() == 0)
2299         {
2300             continuationIndentStack->emplace_back(indentLength);
2301             isContinuation = true;
2302         }
2303     }
2304     // set indent for last definition line
2305     else if (!lineBeginsWithOpenBrace)
2306     {
2307         if (shouldAlignMethodColon)
2308             spaceIndentCount = computeObjCColonAlignment(line_, colonIndentObjCMethodAlignment);
2309         else if (continuationIndentStack->empty())
2310             spaceIndentCount = spaceIndentObjCMethodAlignment;
2311     }
2312 }
2313 
2314 void ASBeautifier::adjustObjCMethodCallIndentation(const string& line_)
2315 {
2316     static int keywordIndentObjCMethodAlignment = 0;
2317     if (shouldAlignMethodColon && objCColonAlignSubsequent != -1)
2318     {
2319         if (isInObjCMethodCallFirst)
2320         {
2321             isInObjCMethodCallFirst = false;
2322             string convertedLine = getIndentedSpaceEquivalent(line_);
2323             bracePosObjCMethodAlignment = convertedLine.find('[');
2324             keywordIndentObjCMethodAlignment =
2325                 getObjCFollowingKeyword(convertedLine, bracePosObjCMethodAlignment);
2326             colonIndentObjCMethodAlignment = findObjCColonAlignment(convertedLine);
2327             if (colonIndentObjCMethodAlignment >= 0)
2328             {
2329                 int objCColonAlignSubsequentIndent = objCColonAlignSubsequent + indentLength;
2330                 if (objCColonAlignSubsequentIndent > colonIndentObjCMethodAlignment)
2331                     colonIndentObjCMethodAlignment = objCColonAlignSubsequentIndent;
2332                 if (lineBeginsWithOpenBrace)
2333                     colonIndentObjCMethodAlignment -= indentLength;
2334             }
2335         }
2336         else
2337         {
2338             if (findObjCColonAlignment(line_) != -1)
2339             {
2340                 if (colonIndentObjCMethodAlignment < 0)
2341                     spaceIndentCount += computeObjCColonAlignment(line_, objCColonAlignSubsequent);
2342                 else if (objCColonAlignSubsequent > colonIndentObjCMethodAlignment)
2343                     spaceIndentCount = computeObjCColonAlignment(line_, objCColonAlignSubsequent);
2344                 else
2345                     spaceIndentCount = computeObjCColonAlignment(line_, colonIndentObjCMethodAlignment);
2346             }
2347             else
2348             {
2349                 if (spaceIndentCount < colonIndentObjCMethodAlignment)
2350                     spaceIndentCount += keywordIndentObjCMethodAlignment;
2351             }
2352         }
2353     }
2354     else    // align keywords instead of colons
2355     {
2356         if (isInObjCMethodCallFirst)
2357         {
2358             isInObjCMethodCallFirst = false;
2359             string convertedLine = getIndentedSpaceEquivalent(line_);
2360             bracePosObjCMethodAlignment = convertedLine.find('[');
2361             keywordIndentObjCMethodAlignment =
2362                 getObjCFollowingKeyword(convertedLine, bracePosObjCMethodAlignment);
2363         }
2364         else
2365         {
2366             if (spaceIndentCount < keywordIndentObjCMethodAlignment + bracePosObjCMethodAlignment)
2367                 spaceIndentCount += keywordIndentObjCMethodAlignment;
2368         }
2369     }
2370 }
2371 
2372 /**
2373  * Clear the variables used to align the Objective-C method definitions.
2374  */
2375 void ASBeautifier::clearObjCMethodDefinitionAlignment()
2376 {
2377     assert(isImmediatelyPostObjCMethodDefinition);
2378     spaceIndentCount = 0;
2379     spaceIndentObjCMethodAlignment = 0;
2380     colonIndentObjCMethodAlignment = 0;
2381     isInObjCMethodDefinition = false;
2382     isImmediatelyPostObjCMethodDefinition = false;
2383     if (!continuationIndentStack->empty())
2384         continuationIndentStack->pop_back();
2385 }
2386 
2387 /**
2388  * Find the first alignment colon on a line.
2389  * Ternary operators (?) are bypassed.
2390  */
2391 int ASBeautifier::findObjCColonAlignment(const string& line) const
2392 {
2393     bool haveTernary = false;
2394     for (size_t i = 0; i < line.length(); i++)
2395     {
2396         i = line.find_first_of(":?", i);
2397         if (i == string::npos)
2398             break;
2399 
2400         if (line[i] == '?')
2401         {
2402             haveTernary = true;
2403             continue;
2404         }
2405         if (haveTernary)
2406         {
2407             haveTernary = false;
2408             continue;
2409         }
2410         return i;
2411     }
2412     return -1;
2413 }
2414 
2415 /**
2416  * Compute the spaceIndentCount necessary to align the current line colon
2417  * with the colon position in the argument.
2418  * If it cannot be aligned indentLength is returned and a new colon
2419  * position is calculated.
2420  */
2421 int ASBeautifier::computeObjCColonAlignment(const string& line, int colonAlignPosition) const
2422 {
2423     int colonPosition = findObjCColonAlignment(line);
2424     if (colonPosition < 0 || colonPosition > colonAlignPosition)
2425         return indentLength;
2426     return (colonAlignPosition - colonPosition);
2427 }
2428 
2429 /*
2430  * Compute position of the keyword following the method call object.
2431  * This is oversimplified to find unusual method calls.
2432  * Use for now and see what happens.
2433  * Most programmers will probably use align-method-colon anyway.
2434  */
2435 int ASBeautifier::getObjCFollowingKeyword(const string& line, int bracePos) const
2436 {
2437     assert(line[bracePos] == '[');
2438     size_t firstText = line.find_first_not_of(" \t", bracePos + 1);
2439     if (firstText == string::npos)
2440         return -(indentCount * indentLength - 1);
2441     size_t searchBeg = firstText;
2442     size_t objectEnd = 0;   // end of object text
2443     if (line[searchBeg] == '[')
2444     {
2445         objectEnd = line.find(']', searchBeg + 1);
2446         if (objectEnd == string::npos)
2447             return 0;
2448     }
2449     else
2450     {
2451         if (line[searchBeg] == '(')
2452         {
2453             searchBeg = line.find(')', searchBeg + 1);
2454             if (searchBeg == string::npos)
2455                 return 0;
2456         }
2457         // bypass the object name
2458         objectEnd = line.find_first_of(" \t", searchBeg + 1);
2459         if (objectEnd == string::npos)
2460             return 0;
2461         --objectEnd;
2462     }
2463     size_t keyPos = line.find_first_not_of(" \t", objectEnd + 1);
2464     if (keyPos == string::npos)
2465         return 0;
2466     return keyPos - firstText;
2467 }
2468 
2469 /**
2470  * Get a line using the current space indent with all tabs replaced by spaces.
2471  * The indentCount is NOT included
2472  * Needed to compute an accurate alignment.
2473  */
2474 string ASBeautifier::getIndentedSpaceEquivalent(const string& line_) const
2475 {
2476     string spaceIndent;
2477     spaceIndent.append(spaceIndentCount, ' ');
2478     string convertedLine = spaceIndent + line_;
2479     for (size_t i = spaceIndent.length(); i < convertedLine.length(); i++)
2480     {
2481         if (convertedLine[i] == '\t')
2482         {
2483             size_t numSpaces = indentLength - (i % indentLength);
2484             convertedLine.replace(i, 1, numSpaces, ' ');
2485             i += indentLength - 1;
2486         }
2487     }
2488     return convertedLine;
2489 }
2490 
2491 /**
2492  * Determine if an item is at a top level.
2493  */
2494 bool ASBeautifier::isTopLevel() const
2495 {
2496     if (headerStack->empty())
2497         return true;
2498     else if (headerStack->back() == &AS_OPEN_BRACE
2499              && headerStack->size() >= 2)
2500     {
2501         if ((*headerStack)[headerStack->size() - 2] == &AS_NAMESPACE
2502                 || (*headerStack)[headerStack->size() - 2] == &AS_MODULE
2503                 || (*headerStack)[headerStack->size() - 2] == &AS_CLASS
2504                 || (*headerStack)[headerStack->size() - 2] == &AS_INTERFACE
2505                 || (*headerStack)[headerStack->size() - 2] == &AS_STRUCT
2506                 || (*headerStack)[headerStack->size() - 2] == &AS_UNION)
2507             return true;
2508     }
2509     else if (headerStack->back() == &AS_NAMESPACE
2510              || headerStack->back() == &AS_MODULE
2511              || headerStack->back() == &AS_CLASS
2512              || headerStack->back() == &AS_INTERFACE
2513              || headerStack->back() == &AS_STRUCT
2514              || headerStack->back() == &AS_UNION)
2515         return true;
2516     return false;
2517 }
2518 
2519 /**
2520  * Parse the current line to update indentCount and spaceIndentCount.
2521  */
2522 void ASBeautifier::parseCurrentLine(const string& line)
2523 {
2524     bool isInLineComment = false;
2525     bool isInOperator = false;
2526     bool isSpecialChar = false;
2527     bool haveCaseIndent = false;
2528     bool haveAssignmentThisLine = false;
2529     bool closingBraceReached = false;
2530     bool previousLineProbation = (probationHeader != nullptr);
2531     char ch = ' ';
2532     int tabIncrementIn = 0;
2533     if (isInQuote
2534             && !haveLineContinuationChar
2535             && !isInVerbatimQuote
2536             && !isInAsm)
2537         isInQuote = false;              // missing closing quote
2538     haveLineContinuationChar = false;
2539 
2540     for (size_t i = 0; i < line.length(); i++)
2541     {
2542         ch = line[i];
2543 
2544         if (isInBeautifySQL)
2545             continue;
2546 
2547         // handle special characters (i.e. backslash+character such as \n, \t, ...)
2548         if (isInQuote && !isInVerbatimQuote)
2549         {
2550             if (isSpecialChar)
2551             {
2552                 isSpecialChar = false;
2553                 continue;
2554             }
2555             if (line.compare(i, 2, "\\\\") == 0)
2556             {
2557                 i++;
2558                 continue;
2559             }
2560             if (ch == '\\')
2561             {
2562                 if (peekNextChar(line, i) == ' ')   // is this '\' at end of line
2563                     haveLineContinuationChar = true;
2564                 else
2565                     isSpecialChar = true;
2566                 continue;
2567             }
2568         }
2569         else if (isInDefine && ch == '\\')
2570             continue;
2571 
2572         // bypass whitespace here
2573         if (isWhiteSpace(ch))
2574         {
2575             if (ch == '\t')
2576                 tabIncrementIn += convertTabToSpaces(i, tabIncrementIn);
2577             continue;
2578         }
2579 
2580         // handle quotes (such as 'x' and "Hello Dolly")
2581         if (!(isInComment || isInLineComment)
2582                 && (ch == '"'
2583                     || (ch == '\'' && !isDigitSeparator(line, i))))
2584         {
2585             if (!isInQuote)
2586             {
2587                 quoteChar = ch;
2588                 isInQuote = true;
2589                 char prevCh = i > 0 ? line[i - 1] : ' ';
2590                 if (isCStyle() && prevCh == 'R')
2591                 {
2592                     int parenPos = line.find('(', i);
2593                     if (parenPos != -1)
2594                     {
2595                         isInVerbatimQuote = true;
2596                         verbatimDelimiter = line.substr(i + 1, parenPos - i - 1);
2597                     }
2598                 }
2599                 else if (isSharpStyle() && prevCh == '@')
2600                     isInVerbatimQuote = true;
2601                 // check for "C" following "extern"
2602                 else if (g_preprocessorCppExternCBrace == 2 && line.compare(i, 3, "\"C\"") == 0)
2603                     ++g_preprocessorCppExternCBrace;
2604             }
2605             else if (isInVerbatimQuote && ch == '"')
2606             {
2607                 if (isCStyle())
2608                 {
2609                     string delim = ')' + verbatimDelimiter;
2610                     int delimStart = i - delim.length();
2611                     if (delimStart > 0 && line.substr(delimStart, delim.length()) == delim)
2612                     {
2613                         isInQuote = false;
2614                         isInVerbatimQuote = false;
2615                     }
2616                 }
2617                 else if (isSharpStyle())
2618                 {
2619                     if (line.compare(i, 2, "\"\"") == 0)
2620                         i++;
2621                     else
2622                     {
2623                         isInQuote = false;
2624                         isInVerbatimQuote = false;
2625                         continue;
2626                     }
2627                 }
2628             }
2629             else if (quoteChar == ch)
2630             {
2631                 isInQuote = false;
2632                 isContinuation = true;
2633                 continue;
2634             }
2635         }
2636         if (isInQuote)
2637             continue;
2638 
2639         // handle comments
2640 
2641         if (!(isInComment || isInLineComment) && line.compare(i, 2, "//") == 0)
2642         {
2643             // if there is a 'case' statement after these comments unindent by 1
2644             if (isCaseHeaderCommentIndent)
2645                 --indentCount;
2646             // isElseHeaderIndent is set by ASFormatter if shouldBreakElseIfs is requested
2647             // if there is an 'else' after these comments a tempStacks indent is required
2648             if (isElseHeaderIndent && lineOpensWithLineComment && !tempStacks->empty())
2649                 indentCount += adjustIndentCountForBreakElseIfComments();
2650             isInLineComment = true;
2651             i++;
2652             continue;
2653         }
2654         else if (!(isInComment || isInLineComment) && line.compare(i, 2, "/*") == 0)
2655         {
2656             // if there is a 'case' statement after these comments unindent by 1
2657             if (isCaseHeaderCommentIndent && lineOpensWithComment)
2658                 --indentCount;
2659             // isElseHeaderIndent is set by ASFormatter if shouldBreakElseIfs is requested
2660             // if there is an 'else' after these comments a tempStacks indent is required
2661             if (isElseHeaderIndent && lineOpensWithComment && !tempStacks->empty())
2662                 indentCount += adjustIndentCountForBreakElseIfComments();
2663             isInComment = true;
2664             i++;
2665             if (!lineOpensWithComment)              // does line start with comment?
2666                 blockCommentNoIndent = true;        // if no, cannot indent continuation lines
2667             continue;
2668         }
2669         else if ((isInComment || isInLineComment) && line.compare(i, 2, "*/") == 0)
2670         {
2671             size_t firstText = line.find_first_not_of(" \t");
2672             // if there is a 'case' statement after these comments unindent by 1
2673             // only if the ending comment is the first entry on the line
2674             if (isCaseHeaderCommentIndent && firstText == i)
2675                 --indentCount;
2676             // if this comment close starts the line, must check for else-if indent
2677             // isElseHeaderIndent is set by ASFormatter if shouldBreakElseIfs is requested
2678             // if there is an 'else' after these comments a tempStacks indent is required
2679             if (firstText == i)
2680             {
2681                 if (isElseHeaderIndent && !lineOpensWithComment && !tempStacks->empty())
2682                     indentCount += adjustIndentCountForBreakElseIfComments();
2683             }
2684             isInComment = false;
2685             i++;
2686             blockCommentNoIndent = false;           // ok to indent next comment
2687             continue;
2688         }
2689         // treat indented preprocessor lines as a line comment
2690         else if (line[0] == '#' && isIndentedPreprocessor(line, i))
2691         {
2692             isInLineComment = true;
2693         }
2694 
2695         if (isInLineComment)
2696         {
2697             // bypass rest of the comment up to the comment end
2698             while (i + 1 < line.length())
2699                 i++;
2700 
2701             continue;
2702         }
2703         if (isInComment)
2704         {
2705             // if there is a 'case' statement after these comments unindent by 1
2706             if (!lineOpensWithComment && isCaseHeaderCommentIndent)
2707                 --indentCount;
2708             // isElseHeaderIndent is set by ASFormatter if shouldBreakElseIfs is requested
2709             // if there is an 'else' after these comments a tempStacks indent is required
2710             if (!lineOpensWithComment && isElseHeaderIndent && !tempStacks->empty())
2711                 indentCount += adjustIndentCountForBreakElseIfComments();
2712             // bypass rest of the comment up to the comment end
2713             while (i + 1 < line.length()
2714                     && line.compare(i + 1, 2, "*/") != 0)
2715                 i++;
2716 
2717             continue;
2718         }
2719 
2720         // if we have reached this far then we are NOT in a comment or string of special character...
2721 
2722         if (probationHeader != nullptr)
2723         {
2724             if ((probationHeader == &AS_STATIC && ch == '{')
2725                     || (probationHeader == &AS_SYNCHRONIZED && ch == '('))
2726             {
2727                 // insert the probation header as a new header
2728                 isInHeader = true;
2729                 headerStack->emplace_back(probationHeader);
2730 
2731                 // handle the specific probation header
2732                 isInConditional = (probationHeader == &AS_SYNCHRONIZED);
2733 
2734                 isContinuation = false;
2735                 // if the probation comes from the previous line, then indent by 1 tab count.
2736                 if (previousLineProbation
2737                         && ch == '{'
2738                         && !(blockIndent && probationHeader == &AS_STATIC))
2739                 {
2740                     ++indentCount;
2741                     previousLineProbationTab = true;
2742                 }
2743                 previousLineProbation = false;
2744             }
2745 
2746             // dismiss the probation header
2747             probationHeader = nullptr;
2748         }
2749 
2750         prevNonSpaceCh = currentNonSpaceCh;
2751         currentNonSpaceCh = ch;
2752         if (!isLegalNameChar(ch) && ch != ',' && ch != ';')
2753         {
2754             prevNonLegalCh = currentNonLegalCh;
2755             currentNonLegalCh = ch;
2756         }
2757 
2758         if (isInHeader)
2759         {
2760             isInHeader = false;
2761             currentHeader = headerStack->back();
2762         }
2763         else
2764             currentHeader = nullptr;
2765 
2766         if (isCStyle() && isInTemplate
2767                 && (ch == '<' || ch == '>')
2768                 && !(line.length() > i + 1 && line.compare(i, 2, ">=") == 0))
2769         {
2770             if (ch == '<')
2771             {
2772                 ++templateDepth;
2773                 continuationIndentStackSizeStack->push_back(continuationIndentStack->size());
2774                 registerContinuationIndent(line, i, spaceIndentCount, tabIncrementIn, 0, true);
2775             }
2776             else if (ch == '>')
2777             {
2778                 popLastContinuationIndent();
2779                 if (--templateDepth <= 0)
2780                 {
2781                     ch = ';';
2782                     isInTemplate = false;
2783                     templateDepth = 0;
2784                 }
2785             }
2786         }
2787 
2788         // handle parentheses
2789         if (ch == '(' || ch == '[' || ch == ')' || ch == ']')
2790         {
2791             if (ch == '(' || ch == '[')
2792             {
2793                 isInOperator = false;
2794                 // if have a struct header, this is a declaration not a definition
2795                 if (ch == '('
2796                         && !headerStack->empty()
2797                         && headerStack->back() == &AS_STRUCT)
2798                 {
2799                     headerStack->pop_back();
2800                     isInClassHeader = false;
2801                     if (line.find(AS_STRUCT, 0) > i)    // if not on this line
2802                         indentCount -= classInitializerIndents;
2803                     if (indentCount < 0)
2804                         indentCount = 0;
2805                 }
2806 
2807                 if (parenDepth == 0)
2808                 {
2809                     parenStatementStack->push_back(isContinuation);
2810                     isContinuation = true;
2811                 }
2812                 parenDepth++;
2813                 if (ch == '[')
2814                 {
2815                     ++squareBracketCount;
2816                     if (squareBracketCount == 1 && isCStyle())
2817                     {
2818                         isInObjCMethodCall = true;
2819                         isInObjCMethodCallFirst = true;
2820                     }
2821                 }
2822 
2823                 continuationIndentStackSizeStack->push_back(continuationIndentStack->size());
2824 
2825                 if (currentHeader != nullptr)
2826                     registerContinuationIndent(line, i, spaceIndentCount, tabIncrementIn, minConditionalIndent, true);
2827                 else if (!isInObjCMethodDefinition)
2828                     registerContinuationIndent(line, i, spaceIndentCount, tabIncrementIn, 0, true);
2829             }
2830             else if (ch == ')' || ch == ']')
2831             {
2832                 if (ch == ']')
2833                     --squareBracketCount;
2834                 if (squareBracketCount <= 0)
2835                 {
2836                     squareBracketCount = 0;
2837                     if (isInObjCMethodCall)
2838                         isImmediatelyPostObjCMethodCall = true;
2839                 }
2840                 foundPreCommandHeader = false;
2841                 parenDepth--;
2842                 if (parenDepth == 0)
2843                 {
2844                     if (!parenStatementStack->empty())      // in case of unmatched closing parens
2845                     {
2846                         isContinuation = parenStatementStack->back();
2847                         parenStatementStack->pop_back();
2848                     }
2849                     isInAsm = false;
2850                     isInConditional = false;
2851                 }
2852 
2853                 if (!continuationIndentStackSizeStack->empty())
2854                 {
2855                     popLastContinuationIndent();
2856 
2857                     if (!parenIndentStack->empty())
2858                     {
2859                         int poppedIndent = parenIndentStack->back();
2860                         parenIndentStack->pop_back();
2861 
2862                         if (i == 0)
2863                             spaceIndentCount = poppedIndent;
2864                     }
2865                 }
2866             }
2867             continue;
2868         }
2869 
2870         if (ch == '{')
2871         {
2872             // first, check if '{' is a block-opener or a static-array opener
2873             bool isBlockOpener = ((prevNonSpaceCh == '{' && braceBlockStateStack->back())
2874                                   || prevNonSpaceCh == '}'
2875                                   || prevNonSpaceCh == ')'
2876                                   || prevNonSpaceCh == ';'
2877                                   || peekNextChar(line, i) == '{'
2878                                   || isInTrailingReturnType
2879                                   || foundPreCommandHeader
2880                                   || foundPreCommandMacro
2881                                   || isInClassHeader
2882                                   || (isInClassInitializer && !isLegalNameChar(prevNonSpaceCh))
2883                                   || isNonInStatementArray
2884                                   || isInObjCMethodDefinition
2885                                   || isInObjCInterface
2886                                   || isSharpAccessor
2887                                   || isSharpDelegate
2888                                   || isInExternC
2889                                   || isInAsmBlock
2890                                   || getNextWord(line, i) == AS_NEW
2891                                   || (isInDefine
2892                                       && (prevNonSpaceCh == '('
2893                                           || isLegalNameChar(prevNonSpaceCh))));
2894 
2895             if (isInObjCMethodDefinition)
2896             {
2897                 objCColonAlignSubsequent = 0;
2898                 isImmediatelyPostObjCMethodDefinition = true;
2899                 if (lineBeginsWithOpenBrace)        // for run-in braces
2900                     clearObjCMethodDefinitionAlignment();
2901             }
2902 
2903             if (!isBlockOpener && !isContinuation && !isInClassInitializer && !isInEnum)
2904             {
2905                 if (isTopLevel())
2906                     isBlockOpener = true;
2907             }
2908 
2909             if (!isBlockOpener && currentHeader != nullptr)
2910             {
2911                 for (size_t n = 0; n < nonParenHeaders->size(); n++)
2912                     if (currentHeader == (*nonParenHeaders)[n])
2913                     {
2914                         isBlockOpener = true;
2915                         break;
2916                     }
2917             }
2918 
2919             braceBlockStateStack->push_back(isBlockOpener);
2920 
2921             if (!isBlockOpener)
2922             {
2923                 continuationIndentStackSizeStack->push_back(continuationIndentStack->size());
2924                 registerContinuationIndent(line, i, spaceIndentCount, tabIncrementIn, 0, true);
2925                 parenDepth++;
2926                 if (i == 0)
2927                     shouldIndentBracedLine = false;
2928                 isInEnumTypeID = false;
2929 
2930                 continue;
2931             }
2932 
2933             // this brace is a block opener...
2934 
2935             ++lineOpeningBlocksNum;
2936 
2937             if (isInClassInitializer || isInEnumTypeID)
2938             {
2939                 // decrease tab count if brace is broken
2940                 if (lineBeginsWithOpenBrace)
2941                 {
2942                     indentCount -= classInitializerIndents;
2943                     // decrease one more if an empty class
2944                     if (!headerStack->empty()
2945                             && (*headerStack).back() == &AS_CLASS)
2946                     {
2947                         int nextChar = getNextProgramCharDistance(line, i);
2948                         if ((int) line.length() > nextChar && line[nextChar] == '}')
2949                             --indentCount;
2950                     }
2951                 }
2952             }
2953 
2954             if (isInObjCInterface)
2955             {
2956                 isInObjCInterface = false;
2957                 if (lineBeginsWithOpenBrace)
2958                     --indentCount;
2959             }
2960 
2961             if (braceIndent && !namespaceIndent && !headerStack->empty()
2962                     && ((*headerStack).back() == &AS_NAMESPACE
2963                         || (*headerStack).back() == &AS_MODULE))
2964             {
2965                 shouldIndentBracedLine = false;
2966                 --indentCount;
2967             }
2968 
2969             // an indentable struct is treated like a class in the header stack
2970             if (!headerStack->empty()
2971                     && (*headerStack).back() == &AS_STRUCT
2972                     && isInIndentableStruct)
2973                 (*headerStack).back() = &AS_CLASS;
2974 
2975             // is a brace inside a paren?
2976             parenDepthStack->emplace_back(parenDepth);
2977             blockStatementStack->push_back(isContinuation);
2978 
2979             if (!continuationIndentStack->empty())
2980             {
2981                 // completely purge the continuationIndentStack
2982                 while (!continuationIndentStack->empty())
2983                     popLastContinuationIndent();
2984                 if (isInClassInitializer || isInClassHeaderTab)
2985                 {
2986                     if (lineBeginsWithOpenBrace || lineBeginsWithComma)
2987                         spaceIndentCount = 0;
2988                 }
2989                 else
2990                     spaceIndentCount = 0;
2991             }
2992 
2993             blockTabCount += (isContinuation ? 1 : 0);
2994             if (g_preprocessorCppExternCBrace == 3)
2995                 ++g_preprocessorCppExternCBrace;
2996             parenDepth = 0;
2997             isInTrailingReturnType = false;
2998             isInClassHeader = false;
2999             isInClassHeaderTab = false;
3000             isInClassInitializer = false;
3001             isInEnumTypeID = false;
3002             isContinuation = false;
3003             isInQuestion = false;
3004             isInLet = false;
3005             foundPreCommandHeader = false;
3006             foundPreCommandMacro = false;
3007             isInExternC = false;
3008 
3009             tempStacks->emplace_back(new vector<const string*>);
3010             headerStack->emplace_back(&AS_OPEN_BRACE);
3011             lastLineHeader = &AS_OPEN_BRACE;
3012 
3013             continue;
3014         }   // end '{'
3015 
3016         //check if a header has been reached
3017         bool isPotentialHeader = isCharPotentialHeader(line, i);
3018 
3019         if (isPotentialHeader && squareBracketCount == 0)
3020         {
3021             const string* newHeader = findHeader(line, i, headers);
3022 
3023             // java can have a 'default' not in a switch
3024             if (newHeader == &AS_DEFAULT
3025                     && peekNextChar(line, (i + (*newHeader).length() - 1)) != ':')
3026                 newHeader = nullptr;
3027             // Qt headers may be variables in C++
3028             if (isCStyle()
3029                     && (newHeader == &AS_FOREVER || newHeader == &AS_FOREACH))
3030             {
3031                 if (line.find_first_of("=;", i) != string::npos)
3032                     newHeader = nullptr;
3033             }
3034             else if (isSharpStyle()
3035                      && (newHeader == &AS_GET || newHeader == &AS_SET))
3036             {
3037                 if (getNextWord(line, i + (*newHeader).length()) == "is")
3038                     newHeader = nullptr;
3039             }
3040             else if (newHeader == &AS_USING
3041                      && peekNextChar(line, i + (*newHeader).length() - 1) != '(')
3042                 newHeader = nullptr;
3043 
3044             if (newHeader != nullptr)
3045             {
3046                 // if we reached here, then this is a header...
3047                 bool isIndentableHeader = true;
3048 
3049                 isInHeader = true;
3050 
3051                 vector<const string*>* lastTempStack = nullptr;;
3052                 if (!tempStacks->empty())
3053                     lastTempStack = tempStacks->back();
3054 
3055                 // if a new block is opened, push a new stack into tempStacks to hold the
3056                 // future list of headers in the new block.
3057 
3058                 // take care of the special case: 'else if (...)'
3059                 if (newHeader == &AS_IF && lastLineHeader == &AS_ELSE)
3060                 {
3061                     if (!headerStack->empty())
3062                         headerStack->pop_back();
3063                 }
3064 
3065                 // take care of 'else'
3066                 else if (newHeader == &AS_ELSE)
3067                 {
3068                     if (lastTempStack != nullptr)
3069                     {
3070                         int indexOfIf = indexOf(*lastTempStack, &AS_IF);
3071                         if (indexOfIf != -1)
3072                         {
3073                             // recreate the header list in headerStack up to the previous 'if'
3074                             // from the temporary snapshot stored in lastTempStack.
3075                             int restackSize = lastTempStack->size() - indexOfIf - 1;
3076                             for (int r = 0; r < restackSize; r++)
3077                             {
3078                                 headerStack->emplace_back(lastTempStack->back());
3079                                 lastTempStack->pop_back();
3080                             }
3081                             if (!closingBraceReached)
3082                                 indentCount += restackSize;
3083                         }
3084                         /*
3085                          * If the above if is not true, i.e. no 'if' before the 'else',
3086                          * then nothing beautiful will come out of this...
3087                          * I should think about inserting an Exception here to notify the caller of this...
3088                          */
3089                     }
3090                 }
3091 
3092                 // check if 'while' closes a previous 'do'
3093                 else if (newHeader == &AS_WHILE)
3094                 {
3095                     if (lastTempStack != nullptr)
3096                     {
3097                         int indexOfDo = indexOf(*lastTempStack, &AS_DO);
3098                         if (indexOfDo != -1)
3099                         {
3100                             // recreate the header list in headerStack up to the previous 'do'
3101                             // from the temporary snapshot stored in lastTempStack.
3102                             int restackSize = lastTempStack->size() - indexOfDo - 1;
3103                             for (int r = 0; r < restackSize; r++)
3104                             {
3105                                 headerStack->emplace_back(lastTempStack->back());
3106                                 lastTempStack->pop_back();
3107                             }
3108                             if (!closingBraceReached)
3109                                 indentCount += restackSize;
3110                         }
3111                     }
3112                 }
3113                 // check if 'catch' closes a previous 'try' or 'catch'
3114                 else if (newHeader == &AS_CATCH || newHeader == &AS_FINALLY)
3115                 {
3116                     if (lastTempStack != nullptr)
3117                     {
3118                         int indexOfTry = indexOf(*lastTempStack, &AS_TRY);
3119                         if (indexOfTry == -1)
3120                             indexOfTry = indexOf(*lastTempStack, &AS_CATCH);
3121                         if (indexOfTry != -1)
3122                         {
3123                             // recreate the header list in headerStack up to the previous 'try'
3124                             // from the temporary snapshot stored in lastTempStack.
3125                             int restackSize = lastTempStack->size() - indexOfTry - 1;
3126                             for (int r = 0; r < restackSize; r++)
3127                             {
3128                                 headerStack->emplace_back(lastTempStack->back());
3129                                 lastTempStack->pop_back();
3130                             }
3131 
3132                             if (!closingBraceReached)
3133                                 indentCount += restackSize;
3134                         }
3135                     }
3136                 }
3137                 else if (newHeader == &AS_CASE)
3138                 {
3139                     isInCase = true;
3140                     if (!haveCaseIndent)
3141                     {
3142                         haveCaseIndent = true;
3143                         if (!lineBeginsWithOpenBrace)
3144                             --indentCount;
3145                     }
3146                 }
3147                 else if (newHeader == &AS_DEFAULT)
3148                 {
3149                     isInCase = true;
3150                     --indentCount;
3151                 }
3152                 else if (newHeader == &AS_STATIC
3153                          || newHeader == &AS_SYNCHRONIZED)
3154                 {
3155                     if (!headerStack->empty()
3156                             && (headerStack->back() == &AS_STATIC
3157                                 || headerStack->back() == &AS_SYNCHRONIZED))
3158                     {
3159                         isIndentableHeader = false;
3160                     }
3161                     else
3162                     {
3163                         isIndentableHeader = false;
3164                         probationHeader = newHeader;
3165                     }
3166                 }
3167                 else if (newHeader == &AS_TEMPLATE)
3168                 {
3169                     isInTemplate = true;
3170                     isIndentableHeader = false;
3171                 }
3172 
3173                 if (isIndentableHeader)
3174                 {
3175                     headerStack->emplace_back(newHeader);
3176                     isContinuation = false;
3177                     if (indexOf(*nonParenHeaders, newHeader) == -1)
3178                     {
3179                         isInConditional = true;
3180                     }
3181                     lastLineHeader = newHeader;
3182                 }
3183                 else
3184                     isInHeader = false;
3185 
3186                 i += newHeader->length() - 1;
3187 
3188                 continue;
3189             }  // newHeader != nullptr
3190 
3191             if (findHeader(line, i, preCommandHeaders) != nullptr)
3192                 // must be after function arguments
3193                 if (prevNonSpaceCh == ')')
3194                     foundPreCommandHeader = true;
3195 
3196             // Objective-C NSException macros are preCommandHeaders
3197             if (isCStyle() && findKeyword(line, i, AS_NS_DURING))
3198                 foundPreCommandMacro = true;
3199             if (isCStyle() && findKeyword(line, i, AS_NS_HANDLER))
3200                 foundPreCommandMacro = true;
3201 
3202             if (parenDepth == 0 && findKeyword(line, i, AS_ENUM))
3203                 isInEnum = true;
3204 
3205             if (isSharpStyle() && findKeyword(line, i, AS_LET))
3206                 isInLet = true;
3207 
3208         }   // isPotentialHeader
3209 
3210         if (ch == '?')
3211             isInQuestion = true;
3212 
3213         // special handling of colons
3214         if (ch == ':')
3215         {
3216             if (line.length() > i + 1 && line[i + 1] == ':') // look for ::
3217             {
3218                 ++i;
3219                 continue;
3220             }
3221             else if (isInQuestion)
3222             {
3223                 // do nothing special
3224             }
3225             else if (parenDepth > 0)
3226             {
3227                 // found a 'for' loop or an objective-C statement
3228                 // so do nothing special
3229             }
3230             else if (isInEnum)
3231             {
3232                 // found an enum with a base-type
3233                 isInEnumTypeID = true;
3234                 if (i == 0)
3235                     indentCount += classInitializerIndents;
3236             }
3237             else if ((isCStyle() || isSharpStyle())
3238                      && !isInCase
3239                      && (prevNonSpaceCh == ')' || foundPreCommandHeader))
3240             {
3241                 // found a 'class' c'tor initializer
3242                 isInClassInitializer = true;
3243                 registerContinuationIndentColon(line, i, tabIncrementIn);
3244                 if (i == 0)
3245                     indentCount += classInitializerIndents;
3246             }
3247             else if (isInClassHeader || isInObjCInterface)
3248             {
3249                 // is in a 'class A : public B' definition
3250                 isInClassHeaderTab = true;
3251                 registerContinuationIndentColon(line, i, tabIncrementIn);
3252             }
3253             else if (isInAsm || isInAsmOneLine || isInAsmBlock)
3254             {
3255                 // do nothing special
3256             }
3257             else if (isDigit(peekNextChar(line, i)))
3258             {
3259                 // found a bit field - do nothing special
3260             }
3261             else if (isCStyle() && isInClass && prevNonSpaceCh != ')')
3262             {
3263                 // found a 'private:' or 'public:' inside a class definition
3264                 --indentCount;
3265                 if (modifierIndent)
3266                     spaceIndentCount += (indentLength / 2);
3267             }
3268             else if (isCStyle() && !isInClass
3269                      && headerStack->size() >= 2
3270                      && (*headerStack)[headerStack->size() - 2] == &AS_CLASS
3271                      && (*headerStack)[headerStack->size() - 1] == &AS_OPEN_BRACE)
3272             {
3273                 // found a 'private:' or 'public:' inside a class definition
3274                 // and on the same line as the class opening brace
3275                 // do nothing
3276             }
3277             else if (isJavaStyle() && lastLineHeader == &AS_FOR)
3278             {
3279                 // found a java for-each statement
3280                 // so do nothing special
3281             }
3282             else
3283             {
3284                 currentNonSpaceCh = ';'; // so that braces after the ':' will appear as block-openers
3285                 char peekedChar = peekNextChar(line, i);
3286                 if (isInCase)
3287                 {
3288                     isInCase = false;
3289                     ch = ';'; // from here on, treat char as ';'
3290                 }
3291                 else if (isCStyle() || (isSharpStyle() && peekedChar == ';'))
3292                 {
3293                     // is in a label (e.g. 'label1:')
3294                     if (labelIndent)
3295                         --indentCount; // unindent label by one indent
3296                     else if (!lineBeginsWithOpenBrace)
3297                         indentCount = 0; // completely flush indent to left
3298                 }
3299             }
3300         }
3301 
3302         if ((ch == ';' || (parenDepth > 0 && ch == ',')) && !continuationIndentStackSizeStack->empty())
3303             while ((int) continuationIndentStackSizeStack->back() + (parenDepth > 0 ? 1 : 0)
3304                     < (int) continuationIndentStack->size())
3305                 continuationIndentStack->pop_back();
3306 
3307         else if (ch == ',' && isInEnum && isNonInStatementArray && !continuationIndentStack->empty())
3308             continuationIndentStack->pop_back();
3309 
3310         // handle commas
3311         // previous "isInStatement" will be from an assignment operator or class initializer
3312         if (ch == ',' && parenDepth == 0 && !isContinuation && !isNonInStatementArray)
3313         {
3314             // is comma at end of line
3315             size_t nextChar = line.find_first_not_of(" \t", i + 1);
3316             if (nextChar != string::npos)
3317             {
3318                 if (line.compare(nextChar, 2, "//") == 0
3319                         || line.compare(nextChar, 2, "/*") == 0)
3320                     nextChar = string::npos;
3321             }
3322             // register indent
3323             if (nextChar == string::npos)
3324             {
3325                 // register indent at previous word
3326                 if (isJavaStyle() && isInClassHeader)
3327                 {
3328                     // do nothing for now
3329                 }
3330                 // register indent at second word on the line
3331                 else if (!isInTemplate && !isInClassHeaderTab && !isInClassInitializer)
3332                 {
3333                     int prevWord = getContinuationIndentComma(line, i);
3334                     int continuationIndentCount = prevWord + spaceIndentCount + tabIncrementIn;
3335                     continuationIndentStack->emplace_back(continuationIndentCount);
3336                     isContinuation = true;
3337                 }
3338             }
3339         }
3340         // handle comma first initializers
3341         if (ch == ',' && parenDepth == 0 && lineBeginsWithComma
3342                 && (isInClassInitializer || isInClassHeaderTab))
3343             spaceIndentCount = 0;
3344 
3345         // handle ends of statements
3346         if ((ch == ';' && parenDepth == 0) || ch == '}')
3347         {
3348             if (ch == '}')
3349             {
3350                 // first check if this '}' closes a previous block, or a static array...
3351                 if (braceBlockStateStack->size() > 1)
3352                 {
3353                     bool braceBlockState = braceBlockStateStack->back();
3354                     braceBlockStateStack->pop_back();
3355                     if (!braceBlockState)
3356                     {
3357                         if (!continuationIndentStackSizeStack->empty())
3358                         {
3359                             // this brace is a static array
3360                             popLastContinuationIndent();
3361                             parenDepth--;
3362                             if (i == 0)
3363                                 shouldIndentBracedLine = false;
3364 
3365                             if (!parenIndentStack->empty())
3366                             {
3367                                 int poppedIndent = parenIndentStack->back();
3368                                 parenIndentStack->pop_back();
3369                                 if (i == 0)
3370                                     spaceIndentCount = poppedIndent;
3371                             }
3372                         }
3373                         continue;
3374                     }
3375                 }
3376 
3377                 // this brace is block closer...
3378 
3379                 ++lineClosingBlocksNum;
3380 
3381                 if (!continuationIndentStackSizeStack->empty())
3382                     popLastContinuationIndent();
3383 
3384                 if (!parenDepthStack->empty())
3385                 {
3386                     parenDepth = parenDepthStack->back();
3387                     parenDepthStack->pop_back();
3388                     isContinuation = blockStatementStack->back();
3389                     blockStatementStack->pop_back();
3390 
3391                     if (isContinuation)
3392                         blockTabCount--;
3393                 }
3394 
3395                 closingBraceReached = true;
3396                 if (i == 0)
3397                     spaceIndentCount = 0;
3398                 isInAsmBlock = false;
3399                 isInAsm = isInAsmOneLine = isInQuote = false;   // close these just in case
3400 
3401                 int headerPlace = indexOf(*headerStack, &AS_OPEN_BRACE);
3402                 if (headerPlace != -1)
3403                 {
3404                     const string* popped = headerStack->back();
3405                     while (popped != &AS_OPEN_BRACE)
3406                     {
3407                         headerStack->pop_back();
3408                         popped = headerStack->back();
3409                     }
3410                     headerStack->pop_back();
3411 
3412                     if (headerStack->empty())
3413                         g_preprocessorCppExternCBrace = 0;
3414 
3415                     // do not indent namespace brace unless namespaces are indented
3416                     if (!namespaceIndent && !headerStack->empty()
3417                             && ((*headerStack).back() == &AS_NAMESPACE
3418                                 || (*headerStack).back() == &AS_MODULE)
3419                             && i == 0)      // must be the first brace on the line
3420                         shouldIndentBracedLine = false;
3421 
3422                     if (!tempStacks->empty())
3423                     {
3424                         vector<const string*>* temp = tempStacks->back();
3425                         tempStacks->pop_back();
3426                         delete temp;
3427                     }
3428                 }
3429 
3430                 ch = ' '; // needed due to cases such as '}else{', so that headers ('else' in this case) will be identified...
3431             }   // ch == '}'
3432 
3433             /*
3434              * Create a temporary snapshot of the current block's header-list in the
3435              * uppermost inner stack in tempStacks, and clear the headerStack up to
3436              * the beginning of the block.
3437              * Thus, the next future statement will think it comes one indent past
3438              * the block's '{' unless it specifically checks for a companion-header
3439              * (such as a previous 'if' for an 'else' header) within the tempStacks,
3440              * and recreates the temporary snapshot by manipulating the tempStacks.
3441              */
3442             if (!tempStacks->back()->empty())
3443                 while (!tempStacks->back()->empty())
3444                     tempStacks->back()->pop_back();
3445             while (!headerStack->empty() && headerStack->back() != &AS_OPEN_BRACE)
3446             {
3447                 tempStacks->back()->emplace_back(headerStack->back());
3448                 headerStack->pop_back();
3449             }
3450 
3451             if (parenDepth == 0 && ch == ';')
3452             {
3453                 isContinuation = false;
3454                 isInClassInitializer = false;
3455             }
3456 
3457             if (isInObjCMethodDefinition)
3458             {
3459                 objCColonAlignSubsequent = 0;
3460                 isImmediatelyPostObjCMethodDefinition = true;
3461             }
3462 
3463             previousLastLineHeader = nullptr;
3464             isInClassHeader = false;        // for 'friend' class
3465             isInEnum = false;
3466             isInEnumTypeID = false;
3467             isInQuestion = false;
3468             isInTemplate = false;
3469             isInObjCInterface = false;
3470             foundPreCommandHeader = false;
3471             foundPreCommandMacro = false;
3472             squareBracketCount = 0;
3473 
3474             continue;
3475         }
3476 
3477         if (isPotentialHeader)
3478         {
3479             // check for preBlockStatements in C/C++ ONLY if not within parentheses
3480             // (otherwise 'struct XXX' statements would be wrongly interpreted...)
3481             if (!isInTemplate && !(isCStyle() && parenDepth > 0))
3482             {
3483                 const string* newHeader = findHeader(line, i, preBlockStatements);
3484                 // CORBA IDL module
3485                 if (newHeader == &AS_MODULE)
3486                 {
3487                     char nextChar = peekNextChar(line, i + newHeader->length() - 1);
3488                     if (prevNonSpaceCh == ')' || !isalpha(nextChar))
3489                         newHeader = nullptr;
3490                 }
3491                 if (newHeader != nullptr
3492                         && !(isCStyle() && newHeader == &AS_CLASS && isInEnum)  // is not 'enum class'
3493                         && !(isCStyle() && newHeader == &AS_INTERFACE           // CORBA IDL interface
3494                              && (headerStack->empty()
3495                                  || headerStack->back() != &AS_OPEN_BRACE)))
3496                 {
3497                     if (!isSharpStyle())
3498                         headerStack->emplace_back(newHeader);
3499                     // do not need 'where' in the headerStack
3500                     // do not need second 'class' statement in a row
3501                     else if (!(newHeader == &AS_WHERE
3502                                || ((newHeader == &AS_CLASS || newHeader == &AS_STRUCT)
3503                                    && !headerStack->empty()
3504                                    && (headerStack->back() == &AS_CLASS
3505                                        || headerStack->back() == &AS_STRUCT))))
3506                         headerStack->emplace_back(newHeader);
3507 
3508                     if (!headerStack->empty())
3509                     {
3510                         if ((*headerStack).back() == &AS_CLASS
3511                                 || (*headerStack).back() == &AS_STRUCT
3512                                 || (*headerStack).back() == &AS_INTERFACE)
3513                         {
3514                             isInClassHeader = true;
3515                         }
3516                         else if ((*headerStack).back() == &AS_NAMESPACE
3517                                  || (*headerStack).back() == &AS_MODULE)
3518                         {
3519                             // remove continuationIndent from namespace
3520                             if (!continuationIndentStack->empty())
3521                                 continuationIndentStack->pop_back();
3522                             isContinuation = false;
3523                         }
3524                     }
3525 
3526                     i += newHeader->length() - 1;
3527                     continue;
3528                 }
3529             }
3530             const string* foundIndentableHeader = findHeader(line, i, indentableHeaders);
3531 
3532             if (foundIndentableHeader != nullptr)
3533             {
3534                 // must bypass the header before registering the in statement
3535                 i += foundIndentableHeader->length() - 1;
3536                 if (!isInOperator && !isInTemplate && !isNonInStatementArray)
3537                 {
3538                     registerContinuationIndent(line, i, spaceIndentCount, tabIncrementIn, 0, false);
3539                     isContinuation = true;
3540                 }
3541                 continue;
3542             }
3543 
3544             if (isCStyle() && findKeyword(line, i, AS_OPERATOR))
3545                 isInOperator = true;
3546 
3547             if (g_preprocessorCppExternCBrace == 1 && findKeyword(line, i, AS_EXTERN))
3548                 ++g_preprocessorCppExternCBrace;
3549 
3550             if (g_preprocessorCppExternCBrace == 3) // extern "C" is not followed by a '{'
3551                 g_preprocessorCppExternCBrace = 0;
3552 
3553             // "new" operator is a pointer, not a calculation
3554             if (findKeyword(line, i, AS_NEW))
3555             {
3556                 if (isContinuation && !continuationIndentStack->empty() && prevNonSpaceCh == '=')
3557                     continuationIndentStack->back() = 0;
3558             }
3559 
3560             if (isCStyle() && findKeyword(line, i, AS_AUTO) && isTopLevel())
3561             {
3562                 isInTrailingReturnType = true;
3563             }
3564 
3565             if (isCStyle())
3566             {
3567                 if (findKeyword(line, i, AS_ASM)
3568                         || findKeyword(line, i, AS__ASM__))
3569                 {
3570                     isInAsm = true;
3571                 }
3572                 else if (findKeyword(line, i, AS_MS_ASM)        // microsoft specific
3573                          || findKeyword(line, i, AS_MS__ASM))
3574                 {
3575                     int index = 4;
3576                     if (peekNextChar(line, i) == '_')       // check for __asm
3577                         index = 5;
3578 
3579                     char peekedChar = peekNextChar(line, i + index);
3580                     if (peekedChar == '{' || peekedChar == ' ')
3581                         isInAsmBlock = true;
3582                     else
3583                         isInAsmOneLine = true;
3584                 }
3585             }
3586 
3587             // bypass the entire name for all others
3588             string name = getCurrentWord(line, i);
3589             i += name.length() - 1;
3590             continue;
3591         }
3592 
3593         // Handle Objective-C statements
3594 
3595         if (ch == '@'
3596                 && line.length() > i + 1
3597                 && !isWhiteSpace(line[i + 1])
3598                 && isCharPotentialHeader(line, i + 1))
3599         {
3600             string curWord = getCurrentWord(line, i + 1);
3601             if (curWord == AS_INTERFACE)
3602             {
3603                 isInObjCInterface = true;
3604                 string name = '@' + curWord;
3605                 i += name.length() - 1;
3606                 continue;
3607             }
3608             else if (isInObjCInterface)
3609             {
3610                 --indentCount;
3611                 isInObjCInterface = false;
3612             }
3613 
3614             if (curWord == AS_PUBLIC
3615                     || curWord == AS_PRIVATE
3616                     || curWord == AS_PROTECTED)
3617             {
3618                 --indentCount;
3619                 if (modifierIndent)
3620                     spaceIndentCount += (indentLength / 2);
3621                 string name = '@' + curWord;
3622                 i += name.length() - 1;
3623                 continue;
3624             }
3625             else if (curWord == AS_END)
3626             {
3627                 popLastContinuationIndent();
3628                 spaceIndentCount = 0;
3629                 isInObjCMethodDefinition = false;
3630                 string name = '@' + curWord;
3631                 i += name.length() - 1;
3632                 continue;
3633             }
3634         }
3635         else if ((ch == '-' || ch == '+')
3636                  && (prevNonSpaceCh == ';' || prevNonSpaceCh == '{'
3637                      || headerStack->empty() || isInObjCInterface)
3638                  && ASBase::peekNextChar(line, i) != '-'
3639                  && ASBase::peekNextChar(line, i) != '+'
3640                  && line.find_first_not_of(" \t") == i)
3641         {
3642             if (isInObjCInterface)
3643                 --indentCount;
3644             isInObjCInterface = false;
3645             isInObjCMethodDefinition = true;
3646             continue;
3647         }
3648 
3649         // Handle operators
3650 
3651         bool isPotentialOperator = isCharPotentialOperator(ch);
3652 
3653         if (isPotentialOperator)
3654         {
3655             // Check if an operator has been reached.
3656             const string* foundAssignmentOp = findOperator(line, i, assignmentOperators);
3657             const string* foundNonAssignmentOp = findOperator(line, i, nonAssignmentOperators);
3658 
3659             if (foundNonAssignmentOp != nullptr)
3660             {
3661                 if (foundNonAssignmentOp == &AS_LAMBDA)
3662                     foundPreCommandHeader = true;
3663                 if (isInTemplate && foundNonAssignmentOp == &AS_GR_GR)
3664                     foundNonAssignmentOp = nullptr;
3665             }
3666 
3667             // Since findHeader's boundary checking was not used above, it is possible
3668             // that both an assignment op and a non-assignment op where found,
3669             // e.g. '>>' and '>>='. If this is the case, treat the LONGER one as the
3670             // found operator.
3671             if (foundAssignmentOp != nullptr && foundNonAssignmentOp != nullptr)
3672             {
3673                 if (foundAssignmentOp->length() < foundNonAssignmentOp->length())
3674                     foundAssignmentOp = nullptr;
3675                 else
3676                     foundNonAssignmentOp = nullptr;
3677             }
3678 
3679             if (foundNonAssignmentOp != nullptr)
3680             {
3681                 if (foundNonAssignmentOp->length() > 1)
3682                     i += foundNonAssignmentOp->length() - 1;
3683 
3684                 // For C++ input/output, operator<< and >> should be
3685                 // aligned, if we are not in a statement already and
3686                 // also not in the "operator<<(...)" header line
3687                 if (!isInOperator
3688                         && continuationIndentStack->empty()
3689                         && isCStyle()
3690                         && (foundNonAssignmentOp == &AS_GR_GR
3691                             || foundNonAssignmentOp == &AS_LS_LS))
3692                 {
3693                     // this will be true if the line begins with the operator
3694                     if (i < foundNonAssignmentOp->length() && spaceIndentCount == 0)
3695                         spaceIndentCount += 2 * indentLength;
3696                     // align to the beginning column of the operator
3697                     registerContinuationIndent(line, i - foundNonAssignmentOp->length(), spaceIndentCount, tabIncrementIn, 0, false);
3698                 }
3699             }
3700 
3701             else if (foundAssignmentOp != nullptr)
3702             {
3703                 foundPreCommandHeader = false;      // clears this for array assignments
3704                 foundPreCommandMacro = false;
3705 
3706                 if (foundAssignmentOp->length() > 1)
3707                     i += foundAssignmentOp->length() - 1;
3708 
3709                 if (!isInOperator && !isInTemplate && (!isNonInStatementArray || isInEnum))
3710                 {
3711                     // if multiple assignments, align on the previous word
3712                     if (foundAssignmentOp == &AS_ASSIGN
3713                             && prevNonSpaceCh != ']'        // an array
3714                             && statementEndsWithComma(line, i))
3715                     {
3716                         if (!haveAssignmentThisLine)        // only one assignment indent per line
3717                         {
3718                             // register indent at previous word
3719                             haveAssignmentThisLine = true;
3720                             int prevWordIndex = getContinuationIndentAssign(line, i);
3721                             int continuationIndentCount = prevWordIndex + spaceIndentCount + tabIncrementIn;
3722                             continuationIndentStack->emplace_back(continuationIndentCount);
3723                             isContinuation = true;
3724                         }
3725                     }
3726                     // don't indent an assignment if 'let'
3727                     else if (isInLet)
3728                     {
3729                         isInLet = false;
3730                     }
3731                     else if (!lineBeginsWithComma)
3732                     {
3733                         if (i == 0 && spaceIndentCount == 0)
3734                             spaceIndentCount += indentLength;
3735                         registerContinuationIndent(line, i, spaceIndentCount, tabIncrementIn, 0, false);
3736                         isContinuation = true;
3737                     }
3738                 }
3739             }
3740         }
3741     }   // end of for loop * end of for loop * end of for loop * end of for loop * end of for loop *
3742 }
3743 
3744 }   // end namespace astyle