"Fossies" - the Fresh Open Source Software Archive

Member "highlight-3.57-x64/src/core/astyle/ASBeautifier.cpp" (12 May 2020, 110075 Bytes) of package /windows/www/highlight-3.57-x64.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 // ASBeautifier.cpp
    2 // Copyright (c) 2018 by Jim Pattee <jimp03@email.com>.
    3 // This code is licensed under the MIT License.
    4 // License.md describes the conditions under which this software may be distributed.
    5 
    6 //-----------------------------------------------------------------------------
    7 // headers
    8 //-----------------------------------------------------------------------------
    9 
   10 #include "astyle/astyle.h"
   11 
   12 #include <algorithm>
   13 
   14 //-----------------------------------------------------------------------------
   15 // astyle namespace
   16 //-----------------------------------------------------------------------------
   17 
   18 namespace astyle {
   19 //
   20 // this must be global
   21 static int g_preprocessorCppExternCBrace;
   22 
   23 //-----------------------------------------------------------------------------
   24 // ASBeautifier class
   25 //-----------------------------------------------------------------------------
   26 
   27 /**
   28  * ASBeautifier's constructor
   29  * This constructor is called only once for each source file.
   30  * The cloned ASBeautifier objects are created with the copy constructor.
   31  */
   32 ASBeautifier::ASBeautifier()
   33 {
   34     waitingBeautifierStack = nullptr;
   35     activeBeautifierStack = nullptr;
   36     waitingBeautifierStackLengthStack = nullptr;
   37     activeBeautifierStackLengthStack = nullptr;
   38 
   39     headerStack = nullptr;
   40     tempStacks = nullptr;
   41     parenDepthStack = nullptr;
   42     blockStatementStack = nullptr;
   43     parenStatementStack = nullptr;
   44     braceBlockStateStack = nullptr;
   45     continuationIndentStack = nullptr;
   46     continuationIndentStackSizeStack = nullptr;
   47     parenIndentStack = nullptr;
   48     preprocIndentStack = nullptr;
   49     sourceIterator = nullptr;
   50     isModeManuallySet = false;
   51     shouldForceTabIndentation = false;
   52     setSpaceIndentation(4);
   53     setContinuationIndentation(1);
   54     setMinConditionalIndentOption(MINCOND_TWO);
   55     setMaxContinuationIndentLength(40);
   56     classInitializerIndents = 1;
   57     tabLength = 0;
   58     setClassIndent(false);
   59     setModifierIndent(false);
   60     setSwitchIndent(false);
   61     setCaseIndent(false);
   62     setBlockIndent(false);
   63     setBraceIndent(false);
   64     setBraceIndentVtk(false);
   65     setNamespaceIndent(false);
   66     setAfterParenIndent(false);
   67     setLabelIndent(false);
   68     setEmptyLineFill(false);
   69     setCStyle();
   70     setPreprocDefineIndent(false);
   71     setPreprocConditionalIndent(false);
   72     setAlignMethodColon(false);
   73 
   74     // initialize ASBeautifier member vectors
   75     ownsVectors = true;
   76     beautifierFileType = 9;     // reset to an invalid type
   77     headers = new vector<const string*>;
   78     nonParenHeaders = new vector<const string*>;
   79     assignmentOperators = new vector<const string*>;
   80     nonAssignmentOperators = new vector<const string*>;
   81     preBlockStatements = new vector<const string*>;
   82     preCommandHeaders = new vector<const string*>;
   83     indentableHeaders = new vector<const string*>;
   84 }
   85 
   86 /**
   87  * ASBeautifier's copy constructor
   88  * Copy the vector objects to vectors in the new ASBeautifier
   89  * object so the new object can be destroyed without deleting
   90  * the vector objects in the copied vector.
   91  * This is the reason a copy constructor is needed.
   92  *
   93  * Must explicitly call the base class copy constructor.
   94  */
   95 ASBeautifier::ASBeautifier(const ASBeautifier& other) : ASBase(other)
   96 {
   97     // these don't need to copy the stack
   98     waitingBeautifierStack = nullptr;
   99     activeBeautifierStack = nullptr;
  100     waitingBeautifierStackLengthStack = nullptr;
  101     activeBeautifierStackLengthStack = nullptr;
  102 
  103     // vector '=' operator performs a DEEP copy of all elements in the vector
  104 
  105     headerStack = new vector<const string*>;
  106     *headerStack = *other.headerStack;
  107 
  108     tempStacks = copyTempStacks(other);
  109 
  110     parenDepthStack = new vector<int>;
  111     *parenDepthStack = *other.parenDepthStack;
  112 
  113     blockStatementStack = new vector<bool>;
  114     *blockStatementStack = *other.blockStatementStack;
  115 
  116     parenStatementStack = new vector<bool>;
  117     *parenStatementStack = *other.parenStatementStack;
  118 
  119     braceBlockStateStack = new vector<bool>;
  120     *braceBlockStateStack = *other.braceBlockStateStack;
  121 
  122     continuationIndentStack = new vector<int>;
  123     *continuationIndentStack = *other.continuationIndentStack;
  124 
  125     continuationIndentStackSizeStack = new vector<int>;
  126     *continuationIndentStackSizeStack = *other.continuationIndentStackSizeStack;
  127 
  128     parenIndentStack = new vector<int>;
  129     *parenIndentStack = *other.parenIndentStack;
  130 
  131     preprocIndentStack = new vector<pair<int, int> >;
  132     *preprocIndentStack = *other.preprocIndentStack;
  133 
  134     // Copy the pointers to vectors.
  135     // This is ok because the original ASBeautifier object
  136     // is not deleted until end of job.
  137     ownsVectors = false;
  138     beautifierFileType = other.beautifierFileType;
  139     headers = other.headers;
  140     nonParenHeaders = other.nonParenHeaders;
  141     assignmentOperators = other.assignmentOperators;
  142     nonAssignmentOperators = other.nonAssignmentOperators;
  143     preBlockStatements = other.preBlockStatements;
  144     preCommandHeaders = other.preCommandHeaders;
  145     indentableHeaders = other.indentableHeaders;
  146 
  147     // protected variables
  148     // variables set by ASFormatter
  149     // must also be updated in activeBeautifierStack
  150     inLineNumber = other.inLineNumber;
  151     runInIndentContinuation = other.runInIndentContinuation;
  152     nonInStatementBrace = other.nonInStatementBrace;
  153     objCColonAlignSubsequent = other.objCColonAlignSubsequent;
  154     lineCommentNoBeautify = other.lineCommentNoBeautify;
  155     isElseHeaderIndent = other.isElseHeaderIndent;
  156     isCaseHeaderCommentIndent = other.isCaseHeaderCommentIndent;
  157     isNonInStatementArray = other.isNonInStatementArray;
  158     isSharpAccessor = other.isSharpAccessor;
  159     isSharpDelegate = other.isSharpDelegate;
  160     isInExternC = other.isInExternC;
  161     isInBeautifySQL = other.isInBeautifySQL;
  162     isInIndentableStruct = other.isInIndentableStruct;
  163     isInIndentablePreproc = other.isInIndentablePreproc;
  164 
  165     // private variables
  166     sourceIterator = other.sourceIterator;
  167     currentHeader = other.currentHeader;
  168     previousLastLineHeader = other.previousLastLineHeader;
  169     probationHeader = other.probationHeader;
  170     lastLineHeader = other.lastLineHeader;
  171     indentString = other.indentString;
  172     verbatimDelimiter = other.verbatimDelimiter;
  173     isInQuote = other.isInQuote;
  174     isInVerbatimQuote = other.isInVerbatimQuote;
  175     haveLineContinuationChar = other.haveLineContinuationChar;
  176     isInAsm = other.isInAsm;
  177     isInAsmOneLine = other.isInAsmOneLine;
  178     isInAsmBlock = other.isInAsmBlock;
  179     isInComment = other.isInComment;
  180     isInPreprocessorComment = other.isInPreprocessorComment;
  181     isInRunInComment = other.isInRunInComment;
  182     isInCase = other.isInCase;
  183     isInQuestion = other.isInQuestion;
  184     isContinuation = other.isContinuation;
  185     isInHeader = other.isInHeader;
  186     isInTemplate = other.isInTemplate;
  187     isInDefine = other.isInDefine;
  188     isInDefineDefinition = other.isInDefineDefinition;
  189     classIndent = other.classIndent;
  190     isIndentModeOff = other.isIndentModeOff;
  191     isInClassHeader = other.isInClassHeader;
  192     isInClassHeaderTab = other.isInClassHeaderTab;
  193     isInClassInitializer = other.isInClassInitializer;
  194     isInClass = other.isInClass;
  195     isInObjCMethodDefinition = other.isInObjCMethodDefinition;
  196     isInObjCMethodCall = other.isInObjCMethodCall;
  197     isInObjCMethodCallFirst = other.isInObjCMethodCallFirst;
  198     isImmediatelyPostObjCMethodDefinition = other.isImmediatelyPostObjCMethodDefinition;
  199     isImmediatelyPostObjCMethodCall = other.isImmediatelyPostObjCMethodCall;
  200     isInIndentablePreprocBlock = other.isInIndentablePreprocBlock;
  201     isInObjCInterface = other.isInObjCInterface;
  202     isInEnum = other.isInEnum;
  203     isInEnumTypeID = other.isInEnumTypeID;
  204     isInLet = other.isInLet;
  205     isInTrailingReturnType = other.isInTrailingReturnType;
  206     modifierIndent = other.modifierIndent;
  207     switchIndent = other.switchIndent;
  208     caseIndent = other.caseIndent;
  209     namespaceIndent = other.namespaceIndent;
  210     braceIndent = other.braceIndent;
  211     braceIndentVtk = other.braceIndentVtk;
  212     blockIndent = other.blockIndent;
  213     shouldIndentAfterParen = other.shouldIndentAfterParen;
  214     labelIndent = other.labelIndent;
  215     isInConditional = other.isInConditional;
  216     isModeManuallySet = other.isModeManuallySet;
  217     shouldForceTabIndentation = other.shouldForceTabIndentation;
  218     emptyLineFill = other.emptyLineFill;
  219     lineOpensWithLineComment = other.lineOpensWithLineComment;
  220     lineOpensWithComment = other.lineOpensWithComment;
  221     lineStartsInComment = other.lineStartsInComment;
  222     backslashEndsPrevLine = other.backslashEndsPrevLine;
  223     blockCommentNoIndent = other.blockCommentNoIndent;
  224     blockCommentNoBeautify = other.blockCommentNoBeautify;
  225     previousLineProbationTab = other.previousLineProbationTab;
  226     lineBeginsWithOpenBrace = other.lineBeginsWithOpenBrace;
  227     lineBeginsWithCloseBrace = other.lineBeginsWithCloseBrace;
  228     lineBeginsWithComma = other.lineBeginsWithComma;
  229     lineIsCommentOnly = other.lineIsCommentOnly;
  230     lineIsLineCommentOnly = other.lineIsLineCommentOnly;
  231     shouldIndentBracedLine = other.shouldIndentBracedLine;
  232     isInSwitch = other.isInSwitch;
  233     foundPreCommandHeader = other.foundPreCommandHeader;
  234     foundPreCommandMacro = other.foundPreCommandMacro;
  235     shouldAlignMethodColon = other.shouldAlignMethodColon;
  236     shouldIndentPreprocDefine = other.shouldIndentPreprocDefine;
  237     shouldIndentPreprocConditional = other.shouldIndentPreprocConditional;
  238     indentCount = other.indentCount;
  239     spaceIndentCount = other.spaceIndentCount;
  240     spaceIndentObjCMethodAlignment = other.spaceIndentObjCMethodAlignment;
  241     bracePosObjCMethodAlignment = other.bracePosObjCMethodAlignment;
  242     colonIndentObjCMethodAlignment = other.colonIndentObjCMethodAlignment;
  243     lineOpeningBlocksNum = other.lineOpeningBlocksNum;
  244     lineClosingBlocksNum = other.lineClosingBlocksNum;
  245     fileType = other.fileType;
  246     minConditionalOption = other.minConditionalOption;
  247     minConditionalIndent = other.minConditionalIndent;
  248     parenDepth = other.parenDepth;
  249     indentLength = other.indentLength;
  250     tabLength = other.tabLength;
  251     continuationIndent = other.continuationIndent;
  252     blockTabCount = other.blockTabCount;
  253     maxContinuationIndent = other.maxContinuationIndent;
  254     classInitializerIndents = other.classInitializerIndents;
  255     templateDepth = other.templateDepth;
  256     squareBracketCount = other.squareBracketCount;
  257     prevFinalLineSpaceIndentCount = other.prevFinalLineSpaceIndentCount;
  258     prevFinalLineIndentCount = other.prevFinalLineIndentCount;
  259     defineIndentCount = other.defineIndentCount;
  260     preprocBlockIndent = other.preprocBlockIndent;
  261     quoteChar = other.quoteChar;
  262     prevNonSpaceCh = other.prevNonSpaceCh;
  263     currentNonSpaceCh = other.currentNonSpaceCh;
  264     currentNonLegalCh = other.currentNonLegalCh;
  265     prevNonLegalCh = other.prevNonLegalCh;
  266 }
  267 
  268 /**
  269  * ASBeautifier's destructor
  270  */
  271 ASBeautifier::~ASBeautifier()
  272 {
  273     deleteBeautifierContainer(waitingBeautifierStack);
  274     deleteBeautifierContainer(activeBeautifierStack);
  275     deleteContainer(waitingBeautifierStackLengthStack);
  276     deleteContainer(activeBeautifierStackLengthStack);
  277     deleteContainer(headerStack);
  278     deleteTempStacksContainer(tempStacks);
  279     deleteContainer(parenDepthStack);
  280     deleteContainer(blockStatementStack);
  281     deleteContainer(parenStatementStack);
  282     deleteContainer(braceBlockStateStack);
  283     deleteContainer(continuationIndentStack);
  284     deleteContainer(continuationIndentStackSizeStack);
  285     deleteContainer(parenIndentStack);
  286     deleteContainer(preprocIndentStack);
  287 
  288     if (ownsVectors)
  289         deleteBeautifierVectors();
  290 }
  291 
  292 /**
  293  * initialize the ASBeautifier.
  294  *
  295  * This init() should be called every time a ABeautifier object is to start
  296  * beautifying a NEW source file.
  297  * It is called only when a new ASFormatter object is created.
  298  * init() receives a pointer to a ASSourceIterator object that will be
  299  * used to iterate through the source code.
  300  *
  301  * @param iter     a pointer to the ASSourceIterator or ASStreamIterator object.
  302  */
  303 void ASBeautifier::init(ASSourceIterator* iter)
  304 {
  305     sourceIterator = iter;
  306     initVectors();
  307     ASBase::init(getFileType());
  308     g_preprocessorCppExternCBrace = 0;
  309 
  310     initContainer(waitingBeautifierStack, new vector<ASBeautifier*>);
  311     initContainer(activeBeautifierStack, new vector<ASBeautifier*>);
  312 
  313     initContainer(waitingBeautifierStackLengthStack, new vector<int>);
  314     initContainer(activeBeautifierStackLengthStack, new vector<int>);
  315 
  316     initContainer(headerStack, new vector<const string*>);
  317 
  318     initTempStacksContainer(tempStacks, new vector<vector<const string*>*>);
  319     tempStacks->emplace_back(new vector<const string*>);
  320 
  321     initContainer(parenDepthStack, new vector<int>);
  322     initContainer(blockStatementStack, new vector<bool>);
  323     initContainer(parenStatementStack, new vector<bool>);
  324     initContainer(braceBlockStateStack, new vector<bool>);
  325     braceBlockStateStack->push_back(true);
  326     initContainer(continuationIndentStack, new vector<int>);
  327     initContainer(continuationIndentStackSizeStack, new vector<int>);
  328     continuationIndentStackSizeStack->emplace_back(0);
  329     initContainer(parenIndentStack, new vector<int>);
  330     initContainer(preprocIndentStack, new vector<pair<int, int> >);
  331 
  332     previousLastLineHeader = nullptr;
  333     currentHeader = nullptr;
  334 
  335     isInQuote = false;
  336     isInVerbatimQuote = false;
  337     haveLineContinuationChar = false;
  338     isInAsm = false;
  339     isInAsmOneLine = false;
  340     isInAsmBlock = false;
  341     isInComment = false;
  342     isInPreprocessorComment = false;
  343     isInRunInComment = false;
  344     isContinuation = false;
  345     isInCase = false;
  346     isInQuestion = false;
  347     isIndentModeOff = false;
  348     isInClassHeader = false;
  349     isInClassHeaderTab = false;
  350     isInClassInitializer = false;
  351     isInClass = false;
  352     isInObjCMethodDefinition = false;
  353     isInObjCMethodCall = false;
  354     isInObjCMethodCallFirst = false;
  355     isImmediatelyPostObjCMethodDefinition = false;
  356     isImmediatelyPostObjCMethodCall = false;
  357     isInIndentablePreprocBlock = false;
  358     isInObjCInterface = false;
  359     isInEnum = false;
  360     isInEnumTypeID = false;
  361     isInLet = false;
  362     isInHeader = false;
  363     isInTemplate = false;
  364     isInConditional = false;
  365     isInTrailingReturnType = false;
  366 
  367     indentCount = 0;
  368     spaceIndentCount = 0;
  369     spaceIndentObjCMethodAlignment = 0;
  370     bracePosObjCMethodAlignment = 0;
  371     colonIndentObjCMethodAlignment = 0;
  372     lineOpeningBlocksNum = 0;
  373     lineClosingBlocksNum = 0;
  374     templateDepth = 0;
  375     squareBracketCount = 0;
  376     parenDepth = 0;
  377     blockTabCount = 0;
  378     prevFinalLineSpaceIndentCount = 0;
  379     prevFinalLineIndentCount = 0;
  380     defineIndentCount = 0;
  381     preprocBlockIndent = 0;
  382     prevNonSpaceCh = '{';
  383     currentNonSpaceCh = '{';
  384     prevNonLegalCh = '{';
  385     currentNonLegalCh = '{';
  386     quoteChar = ' ';
  387     probationHeader = nullptr;
  388     lastLineHeader = nullptr;
  389     backslashEndsPrevLine = false;
  390     lineOpensWithLineComment = false;
  391     lineOpensWithComment = false;
  392     lineStartsInComment = false;
  393     isInDefine = false;
  394     isInDefineDefinition = false;
  395     lineCommentNoBeautify = false;
  396     isElseHeaderIndent = false;
  397     isCaseHeaderCommentIndent = false;
  398     blockCommentNoIndent = false;
  399     blockCommentNoBeautify = false;
  400     previousLineProbationTab = false;
  401     lineBeginsWithOpenBrace = false;
  402     lineBeginsWithCloseBrace = false;
  403     lineBeginsWithComma = false;
  404     lineIsCommentOnly = false;
  405     lineIsLineCommentOnly = false;
  406     shouldIndentBracedLine = true;
  407     isInSwitch = false;
  408     foundPreCommandHeader = false;
  409     foundPreCommandMacro = false;
  410 
  411     isNonInStatementArray = false;
  412     isSharpAccessor = false;
  413     isSharpDelegate = false;
  414     isInExternC = false;
  415     isInBeautifySQL = false;
  416     isInIndentableStruct = false;
  417     isInIndentablePreproc = false;
  418     inLineNumber = 0;
  419     runInIndentContinuation = 0;
  420     nonInStatementBrace = 0;
  421     objCColonAlignSubsequent = 0;
  422 }
  423 
  424 /*
  425  * initialize the vectors
  426  */
  427 void ASBeautifier::initVectors()
  428 {
  429     if (fileType == beautifierFileType)    // don't build unless necessary
  430         return;
  431 
  432     beautifierFileType = fileType;
  433 
  434     headers->clear();
  435     nonParenHeaders->clear();
  436     assignmentOperators->clear();
  437     nonAssignmentOperators->clear();
  438     preBlockStatements->clear();
  439     preCommandHeaders->clear();
  440     indentableHeaders->clear();
  441 
  442     ASResource::buildHeaders(headers, fileType, true);
  443     ASResource::buildNonParenHeaders(nonParenHeaders, fileType, true);
  444     ASResource::buildAssignmentOperators(assignmentOperators);
  445     ASResource::buildNonAssignmentOperators(nonAssignmentOperators);
  446     ASResource::buildPreBlockStatements(preBlockStatements, fileType);
  447     ASResource::buildPreCommandHeaders(preCommandHeaders, fileType);
  448     ASResource::buildIndentableHeaders(indentableHeaders);
  449 }
  450 
  451 /**
  452  * beautify a line of source code.
  453  * every line of source code in a source code file should be sent
  454  * one after the other to the beautify method.
  455  *
  456  * @return      the indented line.
  457  * @param originalLine       the original unindented line.
  458  */
  459 string ASBeautifier::beautify(const string& originalLine)
  460 {
  461     string line;
  462     bool isInQuoteContinuation = isInVerbatimQuote || haveLineContinuationChar;
  463 
  464     currentHeader = nullptr;
  465     lastLineHeader = nullptr;
  466     blockCommentNoBeautify = blockCommentNoIndent;
  467     isInClass = false;
  468     isInSwitch = false;
  469     lineBeginsWithOpenBrace = false;
  470     lineBeginsWithCloseBrace = false;
  471     lineBeginsWithComma = false;
  472     lineIsCommentOnly = false;
  473     lineIsLineCommentOnly = false;
  474     shouldIndentBracedLine = true;
  475     isInAsmOneLine = false;
  476     lineOpensWithLineComment = false;
  477     lineOpensWithComment = false;
  478     lineStartsInComment = isInComment;
  479     previousLineProbationTab = false;
  480     lineOpeningBlocksNum = 0;
  481     lineClosingBlocksNum = 0;
  482     if (isImmediatelyPostObjCMethodDefinition)
  483         clearObjCMethodDefinitionAlignment();
  484     if (isImmediatelyPostObjCMethodCall)
  485     {
  486         isImmediatelyPostObjCMethodCall = false;
  487         isInObjCMethodCall = false;
  488         objCColonAlignSubsequent = 0;
  489     }
  490 
  491     // handle and remove white spaces around the line:
  492     // If not in comment, first find out size of white space before line,
  493     // so that possible comments starting in the line continue in
  494     // relation to the preliminary white-space.
  495     if (isInQuoteContinuation)
  496     {
  497         // trim a single space added by ASFormatter, otherwise leave it alone
  498         if (!(originalLine.length() == 1 && originalLine[0] == ' '))
  499             line = originalLine;
  500     }
  501     else if (isInComment || isInBeautifySQL)
  502     {
  503         // trim the end of comment and SQL lines
  504         line = originalLine;
  505         size_t trimEnd = line.find_last_not_of(" \t");
  506         if (trimEnd == string::npos)
  507             trimEnd = 0;
  508         else
  509             trimEnd++;
  510         if (trimEnd < line.length())
  511             line.erase(trimEnd);
  512         // does a brace open the line
  513         size_t firstChar = line.find_first_not_of(" \t");
  514         if (firstChar != string::npos)
  515         {
  516             if (line[firstChar] == '{')
  517                 lineBeginsWithOpenBrace = true;
  518             else if (line[firstChar] == '}')
  519                 lineBeginsWithCloseBrace = true;
  520             else if (line[firstChar] == ',')
  521                 lineBeginsWithComma = true;
  522         }
  523     }
  524     else
  525     {
  526         line = trim(originalLine);
  527         if (line.length() > 0)
  528         {
  529             if (line[0] == '{')
  530                 lineBeginsWithOpenBrace = true;
  531             else if (line[0] == '}')
  532                 lineBeginsWithCloseBrace = true;
  533             else if (line[0] == ',')
  534                 lineBeginsWithComma = true;
  535             else if (line.compare(0, 2, "//") == 0)
  536                 lineIsLineCommentOnly = true;
  537             else if (line.compare(0, 2, "/*") == 0)
  538             {
  539                 if (line.find("*/", 2) != string::npos)
  540                     lineIsCommentOnly = true;
  541             }
  542         }
  543 
  544         isInRunInComment = false;
  545         size_t j = line.find_first_not_of(" \t{");
  546         if (j != string::npos && line.compare(j, 2, "//") == 0)
  547             lineOpensWithLineComment = true;
  548         if (j != string::npos && line.compare(j, 2, "/*") == 0)
  549         {
  550             lineOpensWithComment = true;
  551             size_t k = line.find_first_not_of(" \t");
  552             if (k != string::npos && line.compare(k, 1, "{") == 0)
  553                 isInRunInComment = true;
  554         }
  555     }
  556 
  557     // When indent is OFF the lines must still be processed by ASBeautifier.
  558     // Otherwise the lines immediately following may not be indented correctly.
  559     if ((lineIsLineCommentOnly || lineIsCommentOnly)
  560             && line.find("*INDENT-OFF*", 0) != string::npos)
  561         isIndentModeOff = true;
  562 
  563     if (line.length() == 0)
  564     {
  565         if (backslashEndsPrevLine)
  566         {
  567             backslashEndsPrevLine = false;
  568             // check if this line ends a multi-line #define
  569             // if so, remove the #define's cloned beautifier from the active
  570             // beautifier stack and delete it.
  571             if (isInDefineDefinition && !isInDefine)
  572             {
  573                 isInDefineDefinition = false;
  574                 if (!activeBeautifierStack->empty())
  575                 {
  576                     ASBeautifier* defineBeautifier = activeBeautifierStack->back();
  577                     activeBeautifierStack->pop_back();
  578                     delete defineBeautifier;
  579                 }
  580             }
  581         }
  582         if (emptyLineFill && !isInQuoteContinuation)
  583         {
  584             if (isInIndentablePreprocBlock)
  585                 return preLineWS(preprocBlockIndent, 0);
  586             if (!headerStack->empty() || isInEnum)
  587                 return preLineWS(prevFinalLineIndentCount, prevFinalLineSpaceIndentCount);
  588             // must fall thru here
  589         }
  590         else
  591             return line;
  592     }
  593 
  594     // handle preprocessor commands
  595     if (isInIndentablePreprocBlock
  596             && line.length() > 0
  597             && line[0] != '#')
  598     {
  599         string indentedLine;
  600         if (isInClassHeaderTab || isInClassInitializer)
  601         {
  602             // parsing is turned off in ASFormatter by indent-off
  603             // the originalLine will probably never be returned here
  604             indentedLine = preLineWS(prevFinalLineIndentCount, prevFinalLineSpaceIndentCount) + line;
  605             return getIndentedLineReturn(indentedLine, originalLine);
  606         }
  607         indentedLine = preLineWS(preprocBlockIndent, 0) + line;
  608         return getIndentedLineReturn(indentedLine, originalLine);
  609     }
  610 
  611     if (!isInComment
  612             && !isInQuoteContinuation
  613             && line.length() > 0
  614             && ((line[0] == '#' && !isIndentedPreprocessor(line, 0))
  615                 || backslashEndsPrevLine))
  616     {
  617         if (line[0] == '#' && !isInDefine)
  618         {
  619             string preproc = extractPreprocessorStatement(line);
  620             processPreprocessor(preproc, line);
  621             if (isInIndentablePreprocBlock || isInIndentablePreproc)
  622             {
  623                 string indentedLine;
  624                 if ((preproc.length() >= 2 && preproc.substr(0, 2) == "if")) // #if, #ifdef, #ifndef
  625                 {
  626                     indentedLine = preLineWS(preprocBlockIndent, 0) + line;
  627                     preprocBlockIndent += 1;
  628                     isInIndentablePreprocBlock = true;
  629                 }
  630                 else if (preproc == "else" || preproc == "elif")
  631                 {
  632                     indentedLine = preLineWS(preprocBlockIndent - 1, 0) + line;
  633                 }
  634                 else if (preproc == "endif")
  635                 {
  636                     preprocBlockIndent -= 1;
  637                     indentedLine = preLineWS(preprocBlockIndent, 0) + line;
  638                     if (preprocBlockIndent == 0)
  639                         isInIndentablePreprocBlock = false;
  640                 }
  641                 else
  642                     indentedLine = preLineWS(preprocBlockIndent, 0) + line;
  643                 return getIndentedLineReturn(indentedLine, originalLine);
  644             }
  645             if (shouldIndentPreprocConditional && preproc.length() > 0)
  646             {
  647                 string indentedLine;
  648                 if (preproc.length() >= 2 && preproc.substr(0, 2) == "if") // #if, #ifdef, #ifndef
  649                 {
  650                     pair<int, int> entry;   // indentCount, spaceIndentCount
  651                     if (!isInDefine && activeBeautifierStack != nullptr && !activeBeautifierStack->empty())
  652                         entry = activeBeautifierStack->back()->computePreprocessorIndent();
  653                     else
  654                         entry = computePreprocessorIndent();
  655                     preprocIndentStack->emplace_back(entry);
  656                     indentedLine = preLineWS(preprocIndentStack->back().first,
  657                                              preprocIndentStack->back().second) + line;
  658                     return getIndentedLineReturn(indentedLine, originalLine);
  659                 }
  660                 if (preproc == "else" || preproc == "elif")
  661                 {
  662                     if (!preprocIndentStack->empty())   // if no entry don't indent
  663                     {
  664                         indentedLine = preLineWS(preprocIndentStack->back().first,
  665                                                  preprocIndentStack->back().second) + line;
  666                         return getIndentedLineReturn(indentedLine, originalLine);
  667                     }
  668                 }
  669                 else if (preproc == "endif")
  670                 {
  671                     if (!preprocIndentStack->empty())   // if no entry don't indent
  672                     {
  673                         indentedLine = preLineWS(preprocIndentStack->back().first,
  674                                                  preprocIndentStack->back().second) + line;
  675                         preprocIndentStack->pop_back();
  676                         return getIndentedLineReturn(indentedLine, originalLine);
  677                     }
  678                 }
  679             }
  680         }
  681 
  682         // check if the last char is a backslash
  683         if (line.length() > 0)
  684             backslashEndsPrevLine = (line[line.length() - 1] == '\\');
  685         // comments within the definition line can be continued without the backslash
  686         if (isInPreprocessorUnterminatedComment(line))
  687             backslashEndsPrevLine = true;
  688 
  689         // check if this line ends a multi-line #define
  690         // if so, use the #define's cloned beautifier for the line's indentation
  691         // and then remove it from the active beautifier stack and delete it.
  692         if (!backslashEndsPrevLine && isInDefineDefinition && !isInDefine)
  693         {
  694             isInDefineDefinition = false;
  695             // this could happen with invalid input
  696             if (activeBeautifierStack->empty())
  697                 return originalLine;
  698             ASBeautifier* defineBeautifier = activeBeautifierStack->back();
  699             activeBeautifierStack->pop_back();
  700 
  701             string indentedLine = defineBeautifier->beautify(line);
  702             delete defineBeautifier;
  703             return getIndentedLineReturn(indentedLine, originalLine);
  704         }
  705 
  706         // unless this is a multi-line #define, return this precompiler line as is.
  707         if (!isInDefine && !isInDefineDefinition)
  708             return originalLine;
  709     }
  710 
  711     // if there exists any worker beautifier in the activeBeautifierStack,
  712     // then use it instead of me to indent the current line.
  713     // variables set by ASFormatter must be updated.
  714     if (!isInDefine && activeBeautifierStack != nullptr && !activeBeautifierStack->empty())
  715     {
  716         activeBeautifierStack->back()->inLineNumber = inLineNumber;
  717         activeBeautifierStack->back()->runInIndentContinuation = runInIndentContinuation;
  718         activeBeautifierStack->back()->nonInStatementBrace = nonInStatementBrace;
  719         activeBeautifierStack->back()->objCColonAlignSubsequent = objCColonAlignSubsequent;
  720         activeBeautifierStack->back()->lineCommentNoBeautify = lineCommentNoBeautify;
  721         activeBeautifierStack->back()->isElseHeaderIndent = isElseHeaderIndent;
  722         activeBeautifierStack->back()->isCaseHeaderCommentIndent = isCaseHeaderCommentIndent;
  723         activeBeautifierStack->back()->isNonInStatementArray = isNonInStatementArray;
  724         activeBeautifierStack->back()->isSharpAccessor = isSharpAccessor;
  725         activeBeautifierStack->back()->isSharpDelegate = isSharpDelegate;
  726         activeBeautifierStack->back()->isInExternC = isInExternC;
  727         activeBeautifierStack->back()->isInBeautifySQL = isInBeautifySQL;
  728         activeBeautifierStack->back()->isInIndentableStruct = isInIndentableStruct;
  729         activeBeautifierStack->back()->isInIndentablePreproc = isInIndentablePreproc;
  730         // must return originalLine not the trimmed line
  731         return activeBeautifierStack->back()->beautify(originalLine);
  732     }
  733 
  734     // Flag an indented header in case this line is a one-line block.
  735     // The header in the header stack will be deleted by a one-line block.
  736     bool isInExtraHeaderIndent = false;
  737     if (!headerStack->empty()
  738             && lineBeginsWithOpenBrace
  739             && (headerStack->back() != &AS_OPEN_BRACE
  740                 || probationHeader != nullptr))
  741         isInExtraHeaderIndent = true;
  742 
  743     size_t iPrelim = headerStack->size();
  744 
  745     // calculate preliminary indentation based on headerStack and data from past lines
  746     computePreliminaryIndentation();
  747 
  748     // parse characters in the current line.
  749     parseCurrentLine(line);
  750 
  751     // handle special cases of indentation
  752     adjustParsedLineIndentation(iPrelim, isInExtraHeaderIndent);
  753 
  754     if (isInObjCMethodDefinition)
  755         adjustObjCMethodDefinitionIndentation(line);
  756 
  757     if (isInObjCMethodCall)
  758         adjustObjCMethodCallIndentation(line);
  759 
  760     if (isInDefine)
  761     {
  762         if (line.length() > 0 && line[0] == '#')
  763         {
  764             // the 'define' does not have to be attached to the '#'
  765             string preproc = trim(line.substr(1));
  766             if (preproc.compare(0, 6, "define") == 0)
  767             {
  768                 if (!continuationIndentStack->empty()
  769                         && continuationIndentStack->back() > 0)
  770                 {
  771                     defineIndentCount = indentCount;
  772                 }
  773                 else
  774                 {
  775                     defineIndentCount = indentCount - 1;
  776                     --indentCount;
  777                 }
  778             }
  779         }
  780 
  781         indentCount -= defineIndentCount;
  782     }
  783 
  784     if (indentCount < 0)
  785         indentCount = 0;
  786 
  787     if (lineCommentNoBeautify || blockCommentNoBeautify || isInQuoteContinuation)
  788         indentCount = spaceIndentCount = 0;
  789 
  790     // finally, insert indentations into beginning of line
  791 
  792     string indentedLine = preLineWS(indentCount, spaceIndentCount) + line;
  793     indentedLine = getIndentedLineReturn(indentedLine, originalLine);
  794 
  795     prevFinalLineSpaceIndentCount = spaceIndentCount;
  796     prevFinalLineIndentCount = indentCount;
  797 
  798     if (lastLineHeader != nullptr)
  799         previousLastLineHeader = lastLineHeader;
  800 
  801     if ((lineIsLineCommentOnly || lineIsCommentOnly)
  802             && line.find("*INDENT-ON*", 0) != string::npos)
  803         isIndentModeOff = false;
  804 
  805     return indentedLine;
  806 }
  807 
  808 /**
  809  * set indentation style to C/C++.
  810  */
  811 void ASBeautifier::setCStyle()
  812 {
  813     fileType = C_TYPE;
  814 }
  815 
  816 /**
  817  * set indentation style to Java.
  818  */
  819 void ASBeautifier::setJavaStyle()
  820 {
  821     fileType = JAVA_TYPE;
  822 }
  823 
  824 /**
  825  * set indentation style to C#.
  826  */
  827 void ASBeautifier::setSharpStyle()
  828 {
  829     fileType = SHARP_TYPE;
  830 }
  831 
  832 /**
  833  * set mode manually set flag
  834  */
  835 void ASBeautifier::setModeManuallySet(bool state)
  836 {
  837     isModeManuallySet = state;
  838 }
  839 
  840 /**
  841  * set tabLength equal to indentLength.
  842  * This is done when tabLength is not explicitly set by
  843  * "indent=force-tab-x"
  844  *
  845  */
  846 void ASBeautifier::setDefaultTabLength()
  847 {
  848     tabLength = indentLength;
  849 }
  850 
  851 /**
  852  * indent using a different tab setting for indent=force-tab
  853  *
  854  * @param   length     number of spaces per tab.
  855  */
  856 void ASBeautifier::setForceTabXIndentation(int length)
  857 {
  858     // set tabLength instead of indentLength
  859     indentString = "\t";
  860     tabLength = length;
  861     shouldForceTabIndentation = true;
  862 }
  863 
  864 /**
  865  * indent using one tab per indentation
  866  */
  867 void ASBeautifier::setTabIndentation(int length, bool forceTabs)
  868 {
  869     indentString = "\t";
  870     indentLength = length;
  871     shouldForceTabIndentation = forceTabs;
  872 }
  873 
  874 /**
  875  * indent using a number of spaces per indentation.
  876  *
  877  * @param   length     number of spaces per indent.
  878  */
  879 void ASBeautifier::setSpaceIndentation(int length)
  880 {
  881     indentString = string(length, ' ');
  882     indentLength = length;
  883 }
  884 
  885 /**
  886 * indent continuation lines using a number of indents.
  887 *
  888 * @param   indent     number of indents per line.
  889 */
  890 void ASBeautifier::setContinuationIndentation(int indent)
  891 {
  892     continuationIndent = indent;
  893 }
  894 
  895 /**
  896  * set the maximum indentation between two lines in a multi-line statement.
  897  *
  898  * @param   max     maximum indentation length.
  899  */
  900 void ASBeautifier::setMaxContinuationIndentLength(int max)
  901 {
  902     maxContinuationIndent = max;
  903 }
  904 
  905 // retained for compatibility with release 2.06
  906 // "MaxInStatementIndent" has been changed to "MaxContinuationIndent" in 3.0
  907 // it is referenced only by the old "MaxInStatementIndent" options
  908 void ASBeautifier::setMaxInStatementIndentLength(int max)
  909 {
  910     setMaxContinuationIndentLength(max);
  911 }
  912 
  913 /**
  914  * set the minimum conditional indentation option.
  915  *
  916  * @param   min     minimal indentation option.
  917  */
  918 void ASBeautifier::setMinConditionalIndentOption(int min)
  919 {
  920     minConditionalOption = min;
  921 }
  922 
  923 /**
  924  * set minConditionalIndent from the minConditionalOption.
  925  */
  926 void ASBeautifier::setMinConditionalIndentLength()
  927 {
  928     if (minConditionalOption == MINCOND_ZERO)
  929         minConditionalIndent = 0;
  930     else if (minConditionalOption == MINCOND_ONE)
  931         minConditionalIndent = indentLength;
  932     else if (minConditionalOption == MINCOND_ONEHALF)
  933         minConditionalIndent = indentLength / 2;
  934     // minConditionalOption = INDENT_TWO
  935     else
  936         minConditionalIndent = indentLength * 2;
  937 }
  938 
  939 /**
  940  * set the state of the brace indent option. If true, braces will
  941  * be indented one additional indent.
  942  *
  943  * @param   state             state of option.
  944  */
  945 void ASBeautifier::setBraceIndent(bool state)
  946 {
  947     braceIndent = state;
  948 }
  949 
  950 /**
  951 * set the state of the brace indent VTK option. If true, braces will
  952 * be indented one additional indent, except for the opening brace.
  953 *
  954 * @param   state             state of option.
  955 */
  956 void ASBeautifier::setBraceIndentVtk(bool state)
  957 {
  958     // need to set both of these
  959     setBraceIndent(state);
  960     braceIndentVtk = state;
  961 }
  962 
  963 /**
  964  * set the state of the block indentation option. If true, entire blocks
  965  * will be indented one additional indent, similar to the GNU indent style.
  966  *
  967  * @param   state             state of option.
  968  */
  969 void ASBeautifier::setBlockIndent(bool state)
  970 {
  971     blockIndent = state;
  972 }
  973 
  974 /**
  975  * set the state of the class indentation option. If true, C++ class
  976  * definitions will be indented one additional indent.
  977  *
  978  * @param   state             state of option.
  979  */
  980 void ASBeautifier::setClassIndent(bool state)
  981 {
  982     classIndent = state;
  983 }
  984 
  985 /**
  986  * set the state of the modifier indentation option. If true, C++ class
  987  * access modifiers will be indented one-half an indent.
  988  *
  989  * @param   state             state of option.
  990  */
  991 void ASBeautifier::setModifierIndent(bool state)
  992 {
  993     modifierIndent = state;
  994 }
  995 
  996 /**
  997  * set the state of the switch indentation option. If true, blocks of 'switch'
  998  * statements will be indented one additional indent.
  999  *
 1000  * @param   state             state of option.
 1001  */
 1002 void ASBeautifier::setSwitchIndent(bool state)
 1003 {
 1004     switchIndent = state;
 1005 }
 1006 
 1007 /**
 1008  * set the state of the case indentation option. If true, lines of 'case'
 1009  * statements will be indented one additional indent.
 1010  *
 1011  * @param   state             state of option.
 1012  */
 1013 void ASBeautifier::setCaseIndent(bool state)
 1014 {
 1015     caseIndent = state;
 1016 }
 1017 
 1018 /**
 1019  * set the state of the namespace indentation option.
 1020  * If true, blocks of 'namespace' statements will be indented one
 1021  * additional indent. Otherwise, NO indentation will be added.
 1022  *
 1023  * @param   state             state of option.
 1024  */
 1025 void ASBeautifier::setNamespaceIndent(bool state)
 1026 {
 1027     namespaceIndent = state;
 1028 }
 1029 
 1030 /**
 1031 * set the state of the indent after parens option.
 1032 *
 1033 * @param   state             state of option.
 1034 */
 1035 void ASBeautifier::setAfterParenIndent(bool state)
 1036 {
 1037     shouldIndentAfterParen = state;
 1038 }
 1039 
 1040 /**
 1041  * set the state of the label indentation option.
 1042  * If true, labels will be indented one indent LESS than the
 1043  * current indentation level.
 1044  * If false, labels will be flushed to the left with NO
 1045  * indent at all.
 1046  *
 1047  * @param   state             state of option.
 1048  */
 1049 void ASBeautifier::setLabelIndent(bool state)
 1050 {
 1051     labelIndent = state;
 1052 }
 1053 
 1054 /**
 1055  * set the state of the preprocessor indentation option.
 1056  * If true, multi-line #define statements will be indented.
 1057  *
 1058  * @param   state             state of option.
 1059  */
 1060 void ASBeautifier::setPreprocDefineIndent(bool state)
 1061 {
 1062     shouldIndentPreprocDefine = state;
 1063 }
 1064 
 1065 void ASBeautifier::setPreprocConditionalIndent(bool state)
 1066 {
 1067     shouldIndentPreprocConditional = state;
 1068 }
 1069 
 1070 /**
 1071  * set the state of the empty line fill option.
 1072  * If true, empty lines will be filled with the whitespace.
 1073  * of their previous lines.
 1074  * If false, these lines will remain empty.
 1075  *
 1076  * @param   state             state of option.
 1077  */
 1078 void ASBeautifier::setEmptyLineFill(bool state)
 1079 {
 1080     emptyLineFill = state;
 1081 }
 1082 
 1083 void ASBeautifier::setAlignMethodColon(bool state)
 1084 {
 1085     shouldAlignMethodColon = state;
 1086 }
 1087 
 1088 /**
 1089  * get the file type.
 1090  */
 1091 int ASBeautifier::getFileType() const
 1092 {
 1093     return fileType;
 1094 }
 1095 
 1096 /**
 1097  * get the number of spaces per indent
 1098  *
 1099  * @return   value of indentLength option.
 1100  */
 1101 int ASBeautifier::getIndentLength() const
 1102 {
 1103     return indentLength;
 1104 }
 1105 
 1106 /**
 1107  * get the char used for indentation, space or tab
 1108  *
 1109  * @return   the char used for indentation.
 1110  */
 1111 string ASBeautifier::getIndentString() const
 1112 {
 1113     return indentString;
 1114 }
 1115 
 1116 /**
 1117  * get mode manually set flag
 1118  */
 1119 bool ASBeautifier::getModeManuallySet() const
 1120 {
 1121     return isModeManuallySet;
 1122 }
 1123 
 1124 /**
 1125  * get the state of the force tab indentation option.
 1126  *
 1127  * @return   state of force tab indentation.
 1128  */
 1129 bool ASBeautifier::getForceTabIndentation() const
 1130 {
 1131     return shouldForceTabIndentation;
 1132 }
 1133 
 1134 /**
 1135 * Get the state of the Objective-C align method colon option.
 1136 *
 1137 * @return   state of shouldAlignMethodColon option.
 1138 */
 1139 bool ASBeautifier::getAlignMethodColon() const
 1140 {
 1141     return shouldAlignMethodColon;
 1142 }
 1143 
 1144 /**
 1145  * get the state of the block indentation option.
 1146  *
 1147  * @return   state of blockIndent option.
 1148  */
 1149 bool ASBeautifier::getBlockIndent() const
 1150 {
 1151     return blockIndent;
 1152 }
 1153 
 1154 /**
 1155  * get the state of the brace indentation option.
 1156  *
 1157  * @return   state of braceIndent option.
 1158  */
 1159 bool ASBeautifier::getBraceIndent() const
 1160 {
 1161     return braceIndent;
 1162 }
 1163 
 1164 /**
 1165 * Get the state of the namespace indentation option. If true, blocks
 1166 * of the 'namespace' statement will be indented one additional indent.
 1167 *
 1168 * @return   state of namespaceIndent option.
 1169 */
 1170 bool ASBeautifier::getNamespaceIndent() const
 1171 {
 1172     return namespaceIndent;
 1173 }
 1174 
 1175 /**
 1176  * Get the state of the class indentation option. If true, blocks of
 1177  * the 'class' statement will be indented one additional indent.
 1178  *
 1179  * @return   state of classIndent option.
 1180  */
 1181 bool ASBeautifier::getClassIndent() const
 1182 {
 1183     return classIndent;
 1184 }
 1185 
 1186 /**
 1187  * Get the state of the class access modifier indentation option.
 1188  * If true, the class access modifiers will be indented one-half indent.
 1189  *
 1190  * @return   state of modifierIndent option.
 1191  */
 1192 bool ASBeautifier::getModifierIndent() const
 1193 {
 1194     return modifierIndent;
 1195 }
 1196 
 1197 /**
 1198  * get the state of the switch indentation option. If true, blocks of
 1199  * the 'switch' statement will be indented one additional indent.
 1200  *
 1201  * @return   state of switchIndent option.
 1202  */
 1203 bool ASBeautifier::getSwitchIndent() const
 1204 {
 1205     return switchIndent;
 1206 }
 1207 
 1208 /**
 1209  * get the state of the case indentation option. If true, lines of 'case'
 1210  * statements will be indented one additional indent.
 1211  *
 1212  * @return   state of caseIndent option.
 1213  */
 1214 bool ASBeautifier::getCaseIndent() const
 1215 {
 1216     return caseIndent;
 1217 }
 1218 
 1219 /**
 1220  * get the state of the empty line fill option.
 1221  * If true, empty lines will be filled with the whitespace.
 1222  * of their previous lines.
 1223  * If false, these lines will remain empty.
 1224  *
 1225  * @return   state of emptyLineFill option.
 1226  */
 1227 bool ASBeautifier::getEmptyLineFill() const
 1228 {
 1229     return emptyLineFill;
 1230 }
 1231 
 1232 /**
 1233  * get the state of the preprocessor indentation option.
 1234  * If true, preprocessor "define" lines will be indented.
 1235  * If false, preprocessor "define" lines will be unchanged.
 1236  *
 1237  * @return   state of shouldIndentPreprocDefine option.
 1238  */
 1239 bool ASBeautifier::getPreprocDefineIndent() const
 1240 {
 1241     return shouldIndentPreprocDefine;
 1242 }
 1243 
 1244 /**
 1245  * get the length of the tab indentation option.
 1246  *
 1247  * @return   length of tab indent option.
 1248  */
 1249 int ASBeautifier::getTabLength() const
 1250 {
 1251     return tabLength;
 1252 }
 1253 
 1254 const string& ASBeautifier::getIndentedLineReturn(const string& newLine, const string& originalLine) const
 1255 {
 1256     if (isIndentModeOff)
 1257         return originalLine;
 1258     return newLine;
 1259 }
 1260 
 1261 string ASBeautifier::preLineWS(int lineIndentCount, int lineSpaceIndentCount) const
 1262 {
 1263     if (shouldForceTabIndentation)
 1264     {
 1265         if (tabLength != indentLength)
 1266         {
 1267             // adjust for different tab length
 1268             int indentCountOrig = lineIndentCount;
 1269             int spaceIndentCountOrig = lineSpaceIndentCount;
 1270             lineIndentCount = ((indentCountOrig * indentLength) + spaceIndentCountOrig) / tabLength;
 1271             lineSpaceIndentCount = ((indentCountOrig * indentLength) + spaceIndentCountOrig) % tabLength;
 1272         }
 1273         else
 1274         {
 1275             lineIndentCount += lineSpaceIndentCount / indentLength;
 1276             lineSpaceIndentCount = lineSpaceIndentCount % indentLength;
 1277         }
 1278     }
 1279 
 1280     string ws;
 1281     for (int i = 0; i < lineIndentCount; i++)
 1282         ws += indentString;
 1283     while ((lineSpaceIndentCount--) > 0)
 1284         ws += string(" ");
 1285     return ws;
 1286 }
 1287 
 1288 /**
 1289  * register a continuation indent.
 1290  */
 1291 void ASBeautifier::registerContinuationIndent(const string& line, int i, int spaceIndentCount_,
 1292                                               int tabIncrementIn, int minIndent, bool updateParenStack)
 1293 {
 1294     assert(i >= -1);
 1295     int remainingCharNum = line.length() - i;
 1296     int nextNonWSChar = getNextProgramCharDistance(line, i);
 1297 
 1298     // if indent is around the last char in the line OR indent-after-paren is requested,
 1299     // indent with the continuation indent
 1300     if (nextNonWSChar == remainingCharNum || shouldIndentAfterParen)
 1301     {
 1302         int previousIndent = spaceIndentCount_;
 1303         if (!continuationIndentStack->empty())
 1304             previousIndent = continuationIndentStack->back();
 1305         int currIndent = continuationIndent * indentLength + previousIndent;
 1306         if (currIndent > maxContinuationIndent && line[i] != '{')
 1307             currIndent = indentLength * 2 + spaceIndentCount_;
 1308         continuationIndentStack->emplace_back(currIndent);
 1309         if (updateParenStack)
 1310             parenIndentStack->emplace_back(previousIndent);
 1311         return;
 1312     }
 1313 
 1314     if (updateParenStack)
 1315     {
 1316         parenIndentStack->emplace_back(i + spaceIndentCount_ - runInIndentContinuation);
 1317         if (parenIndentStack->back() < 0)
 1318             parenIndentStack->back() = 0;
 1319     }
 1320 
 1321     int tabIncrement = tabIncrementIn;
 1322 
 1323     // check for following tabs
 1324     for (int j = i + 1; j < (i + nextNonWSChar); j++)
 1325     {
 1326         if (line[j] == '\t')
 1327             tabIncrement += convertTabToSpaces(j, tabIncrement);
 1328     }
 1329 
 1330     int continuationIndentCount = i + nextNonWSChar + spaceIndentCount_ + tabIncrement;
 1331 
 1332     // check for run-in statement
 1333     if (i > 0 && line[0] == '{')
 1334         continuationIndentCount -= indentLength;
 1335 
 1336     if (continuationIndentCount < minIndent)
 1337         continuationIndentCount = minIndent + spaceIndentCount_;
 1338 
 1339     // this is not done for an in-statement array
 1340     if (continuationIndentCount > maxContinuationIndent
 1341             && !(prevNonLegalCh == '=' && currentNonLegalCh == '{'))
 1342         continuationIndentCount = indentLength * 2 + spaceIndentCount_;
 1343 
 1344     if (!continuationIndentStack->empty()
 1345             && continuationIndentCount < continuationIndentStack->back())
 1346         continuationIndentCount = continuationIndentStack->back();
 1347 
 1348     // the block opener is not indented for a NonInStatementArray
 1349     if ((isNonInStatementArray && i >= 0 && line[i] == '{')
 1350             && !isInEnum && !braceBlockStateStack->empty() && braceBlockStateStack->back())
 1351         continuationIndentCount = 0;
 1352 
 1353     continuationIndentStack->emplace_back(continuationIndentCount);
 1354 }
 1355 
 1356 /**
 1357 * Register a continuation indent for a class header or a class initializer colon.
 1358 */
 1359 void ASBeautifier::registerContinuationIndentColon(const string& line, int i, int tabIncrementIn)
 1360 {
 1361     assert(line[i] == ':');
 1362     assert(isInClassInitializer || isInClassHeaderTab);
 1363 
 1364     // register indent at first word after the colon
 1365     size_t firstChar = line.find_first_not_of(" \t");
 1366     if (firstChar == (size_t) i)        // firstChar is ':'
 1367     {
 1368         size_t firstWord = line.find_first_not_of(" \t", firstChar + 1);
 1369         if (firstWord != string::npos)
 1370         {
 1371             int continuationIndentCount = firstWord + spaceIndentCount + tabIncrementIn;
 1372             continuationIndentStack->emplace_back(continuationIndentCount);
 1373             isContinuation = true;
 1374         }
 1375     }
 1376 }
 1377 
 1378 /**
 1379  * Compute indentation for a preprocessor #if statement.
 1380  * This may be called for the activeBeautiferStack
 1381  * instead of the active ASBeautifier object.
 1382  */
 1383 pair<int, int> ASBeautifier::computePreprocessorIndent()
 1384 {
 1385     computePreliminaryIndentation();
 1386     pair<int, int> entry(indentCount, spaceIndentCount);
 1387     if (!headerStack->empty()
 1388             && entry.first > 0
 1389             && (headerStack->back() == &AS_IF
 1390                 || headerStack->back() == &AS_ELSE
 1391                 || headerStack->back() == &AS_FOR
 1392                 || headerStack->back() == &AS_WHILE))
 1393         --entry.first;
 1394     return entry;
 1395 }
 1396 
 1397 /**
 1398  * get distance to the next non-white space, non-comment character in the line.
 1399  * if no such character exists, return the length remaining to the end of the line.
 1400  */
 1401 int ASBeautifier::getNextProgramCharDistance(const string& line, int i) const
 1402 {
 1403     bool inComment = false;
 1404     int  remainingCharNum = line.length() - i;
 1405     int  charDistance;
 1406     char ch;
 1407 
 1408     for (charDistance = 1; charDistance < remainingCharNum; charDistance++)
 1409     {
 1410         ch = line[i + charDistance];
 1411         if (inComment)
 1412         {
 1413             if (line.compare(i + charDistance, 2, "*/") == 0)
 1414             {
 1415                 charDistance++;
 1416                 inComment = false;
 1417             }
 1418             continue;
 1419         }
 1420         if (isWhiteSpace(ch))
 1421             continue;
 1422         if (ch == '/')
 1423         {
 1424             if (line.compare(i + charDistance, 2, "//") == 0)
 1425                 return remainingCharNum;
 1426             if (line.compare(i + charDistance, 2, "/*") == 0)
 1427             {
 1428                 charDistance++;
 1429                 inComment = true;
 1430             }
 1431         }
 1432         else
 1433             return charDistance;
 1434     }
 1435 
 1436     return charDistance;
 1437 }
 1438 
 1439 /**
 1440  * find the index number of a string element in a container of strings
 1441  *
 1442  * @return              the index number of element in the container. -1 if element not found.
 1443  * @param container     a vector of strings.
 1444  * @param element       the element to find .
 1445  */
 1446 int ASBeautifier::indexOf(const vector<const string*>& container, const string* element) const
 1447 {
 1448     vector<const string*>::const_iterator where;
 1449 
 1450     where = find(container.begin(), container.end(), element);
 1451     if (where == container.end())
 1452         return -1;
 1453     return (int) (where - container.begin());
 1454 }
 1455 
 1456 /**
 1457  * convert tabs to spaces.
 1458  * i is the position of the character to convert to spaces.
 1459  * tabIncrementIn is the increment that must be added for tab indent characters
 1460  *     to get the correct column for the current tab.
 1461  */
 1462 int ASBeautifier::convertTabToSpaces(int i, int tabIncrementIn) const
 1463 {
 1464     int tabToSpacesAdjustment = indentLength - 1 - ((tabIncrementIn + i) % indentLength);
 1465     return tabToSpacesAdjustment;
 1466 }
 1467 
 1468 /**
 1469  * trim removes the white space surrounding a line.
 1470  *
 1471  * @return          the trimmed line.
 1472  * @param str       the line to trim.
 1473  */
 1474 string ASBeautifier::trim(const string& str) const
 1475 {
 1476     int start = 0;
 1477     int end = str.length() - 1;
 1478 
 1479     while (start < end && isWhiteSpace(str[start]))
 1480         start++;
 1481 
 1482     while (start <= end && isWhiteSpace(str[end]))
 1483         end--;
 1484 
 1485     // don't trim if it ends in a continuation
 1486     if (end >= 0 && str[end] == '\\')
 1487         end = str.length() - 1;
 1488 
 1489     string returnStr(str, start, end + 1 - start);
 1490     return returnStr;
 1491 }
 1492 
 1493 /**
 1494  * rtrim removes the white space from the end of a line.
 1495  *
 1496  * @return          the trimmed line.
 1497  * @param str       the line to trim.
 1498  */
 1499 string ASBeautifier::rtrim(const string& str) const
 1500 {
 1501     size_t len = str.length();
 1502     size_t end = str.find_last_not_of(" \t");
 1503     if (end == string::npos
 1504             || end == len - 1)
 1505         return str;
 1506     string returnStr(str, 0, end + 1);
 1507     return returnStr;
 1508 }
 1509 
 1510 /**
 1511  * Copy tempStacks for the copy constructor.
 1512  * The value of the vectors must also be copied.
 1513  */
 1514 vector<vector<const string*>*>* ASBeautifier::copyTempStacks(const ASBeautifier& other) const
 1515 {
 1516     vector<vector<const string*>*>* tempStacksNew = new vector<vector<const string*>*>;
 1517     vector<vector<const string*>*>::iterator iter;
 1518     for (iter = other.tempStacks->begin();
 1519             iter != other.tempStacks->end();
 1520             ++iter)
 1521     {
 1522         vector<const string*>* newVec = new vector<const string*>;
 1523         *newVec = **iter;
 1524         tempStacksNew->emplace_back(newVec);
 1525     }
 1526     return tempStacksNew;
 1527 }
 1528 
 1529 /**
 1530  * delete a member vectors to eliminate memory leak reporting
 1531  */
 1532 void ASBeautifier::deleteBeautifierVectors()
 1533 {
 1534     ownsVectors = false;
 1535     beautifierFileType = 9;     // reset to an invalid type
 1536     delete headers;
 1537     delete nonParenHeaders;
 1538     delete preBlockStatements;
 1539     delete preCommandHeaders;
 1540     delete assignmentOperators;
 1541     delete nonAssignmentOperators;
 1542     delete indentableHeaders;
 1543 }
 1544 
 1545 /**
 1546  * delete a vector object
 1547  * T is the type of vector
 1548  * used for all vectors except tempStacks
 1549  */
 1550 template<typename T>
 1551 void ASBeautifier::deleteContainer(T& container)
 1552 {
 1553     if (container != nullptr)
 1554     {
 1555         container->clear();
 1556         delete (container);
 1557         container = nullptr;
 1558     }
 1559 }
 1560 
 1561 /**
 1562  * Delete the ASBeautifier vector object.
 1563  * This is a vector of pointers to ASBeautifier objects allocated with the 'new' operator.
 1564  * Therefore the ASBeautifier objects have to be deleted in addition to the
 1565  * ASBeautifier pointer entries.
 1566  */
 1567 void ASBeautifier::deleteBeautifierContainer(vector<ASBeautifier*>*& container)
 1568 {
 1569     if (container != nullptr)
 1570     {
 1571         vector<ASBeautifier*>::iterator iter = container->begin();
 1572         while (iter < container->end())
 1573         {
 1574             delete *iter;
 1575             ++iter;
 1576         }
 1577         container->clear();
 1578         delete (container);
 1579         container = nullptr;
 1580     }
 1581 }
 1582 
 1583 /**
 1584  * Delete the tempStacks vector object.
 1585  * The tempStacks is a vector of pointers to strings allocated with the 'new' operator.
 1586  * Therefore the strings have to be deleted in addition to the tempStacks entries.
 1587  */
 1588 void ASBeautifier::deleteTempStacksContainer(vector<vector<const string*>*>*& container)
 1589 {
 1590     if (container != nullptr)
 1591     {
 1592         vector<vector<const string*>*>::iterator iter = container->begin();
 1593         while (iter < container->end())
 1594         {
 1595             delete *iter;
 1596             ++iter;
 1597         }
 1598         container->clear();
 1599         delete (container);
 1600         container = nullptr;
 1601     }
 1602 }
 1603 
 1604 /**
 1605  * initialize a vector object
 1606  * T is the type of vector used for all vectors
 1607  */
 1608 template<typename T>
 1609 void ASBeautifier::initContainer(T& container, T value)
 1610 {
 1611     // since the ASFormatter object is never deleted,
 1612     // the existing vectors must be deleted before creating new ones
 1613     if (container != nullptr)
 1614         deleteContainer(container);
 1615     container = value;
 1616 }
 1617 
 1618 /**
 1619  * Initialize the tempStacks vector object.
 1620  * The tempStacks is a vector of pointers to strings allocated with the 'new' operator.
 1621  * Any residual entries are deleted before the vector is initialized.
 1622  */
 1623 void ASBeautifier::initTempStacksContainer(vector<vector<const string*>*>*& container,
 1624                                            vector<vector<const string*>*>* value)
 1625 {
 1626     if (container != nullptr)
 1627         deleteTempStacksContainer(container);
 1628     container = value;
 1629 }
 1630 
 1631 /**
 1632  * Determine if an assignment statement ends with a comma
 1633  *     that is not in a function argument. It ends with a
 1634  *     comma if a comma is the last char on the line.
 1635  *
 1636  * @return  true if line ends with a comma, otherwise false.
 1637  */
 1638 bool ASBeautifier::statementEndsWithComma(const string& line, int index) const
 1639 {
 1640     assert(line[index] == '=');
 1641 
 1642     bool isInComment_ = false;
 1643     bool isInQuote_ = false;
 1644     int parenCount = 0;
 1645     size_t lineLength = line.length();
 1646     size_t i = 0;
 1647     char quoteChar_ = ' ';
 1648 
 1649     for (i = index + 1; i < lineLength; ++i)
 1650     {
 1651         char ch = line[i];
 1652 
 1653         if (isInComment_)
 1654         {
 1655             if (line.compare(i, 2, "*/") == 0)
 1656             {
 1657                 isInComment_ = false;
 1658                 ++i;
 1659             }
 1660             continue;
 1661         }
 1662 
 1663         if (ch == '\\')
 1664         {
 1665             ++i;
 1666             continue;
 1667         }
 1668 
 1669         if (isInQuote_)
 1670         {
 1671             if (ch == quoteChar_)
 1672                 isInQuote_ = false;
 1673             continue;
 1674         }
 1675 
 1676         if (ch == '"'
 1677                 || (ch == '\'' && !isDigitSeparator(line, i)))
 1678         {
 1679             isInQuote_ = true;
 1680             quoteChar_ = ch;
 1681             continue;
 1682         }
 1683 
 1684         if (line.compare(i, 2, "//") == 0)
 1685             break;
 1686 
 1687         if (line.compare(i, 2, "/*") == 0)
 1688         {
 1689             if (isLineEndComment(line, i))
 1690                 break;
 1691             isInComment_ = true;
 1692             ++i;
 1693             continue;
 1694         }
 1695 
 1696         if (ch == '(')
 1697             parenCount++;
 1698         if (ch == ')')
 1699             parenCount--;
 1700     }
 1701     if (isInComment_
 1702             || isInQuote_
 1703             || parenCount > 0)
 1704         return false;
 1705 
 1706     size_t lastChar = line.find_last_not_of(" \t", i - 1);
 1707 
 1708     if (lastChar == string::npos || line[lastChar] != ',')
 1709         return false;
 1710 
 1711     return true;
 1712 }
 1713 
 1714 /**
 1715  * check if current comment is a line-end comment
 1716  *
 1717  * @return     is before a line-end comment.
 1718  */
 1719 bool ASBeautifier::isLineEndComment(const string& line, int startPos) const
 1720 {
 1721     assert(line.compare(startPos, 2, "/*") == 0);
 1722 
 1723     // comment must be closed on this line with nothing after it
 1724     size_t endNum = line.find("*/", startPos + 2);
 1725     if (endNum != string::npos)
 1726     {
 1727         size_t nextChar = line.find_first_not_of(" \t", endNum + 2);
 1728         if (nextChar == string::npos)
 1729             return true;
 1730     }
 1731     return false;
 1732 }
 1733 
 1734 /**
 1735  * get the previous word index for an assignment operator
 1736  *
 1737  * @return is the index to the previous word (the in statement indent).
 1738  */
 1739 int ASBeautifier::getContinuationIndentAssign(const string& line, size_t currPos) const
 1740 {
 1741     assert(line[currPos] == '=');
 1742 
 1743     if (currPos == 0)
 1744         return 0;
 1745 
 1746     // get the last legal word (may be a number)
 1747     size_t end = line.find_last_not_of(" \t", currPos - 1);
 1748     if (end == string::npos || !isLegalNameChar(line[end]))
 1749         return 0;
 1750 
 1751     int start;          // start of the previous word
 1752     for (start = end; start > -1; start--)
 1753     {
 1754         if (!isLegalNameChar(line[start]))
 1755             break;
 1756     }
 1757     start++;
 1758 
 1759     return start;
 1760 }
 1761 
 1762 /**
 1763  * get the instatement indent for a comma
 1764  *
 1765  * @return is the indent to the second word on the line (the in statement indent).
 1766  */
 1767 int ASBeautifier::getContinuationIndentComma(const string& line, size_t currPos) const
 1768 {
 1769     assert(line[currPos] == ',');
 1770 
 1771     // get first word on a line
 1772     size_t indent = line.find_first_not_of(" \t");
 1773     if (indent == string::npos || !isLegalNameChar(line[indent]))
 1774         return 0;
 1775 
 1776     // bypass first word
 1777     for (; indent < currPos; indent++)
 1778     {
 1779         if (!isLegalNameChar(line[indent]))
 1780             break;
 1781     }
 1782     indent++;
 1783     if (indent >= currPos || indent < 4)
 1784         return 0;
 1785 
 1786     // point to second word or assignment operator
 1787     indent = line.find_first_not_of(" \t", indent);
 1788     if (indent == string::npos || indent >= currPos)
 1789         return 0;
 1790 
 1791     return indent;
 1792 }
 1793 
 1794 /**
 1795  * get the next word on a line
 1796  * the argument 'currPos' must point to the current position.
 1797  *
 1798  * @return is the next word or an empty string if none found.
 1799  */
 1800 string ASBeautifier::getNextWord(const string& line, size_t currPos) const
 1801 {
 1802     size_t lineLength = line.length();
 1803     // get the last legal word (may be a number)
 1804     if (currPos == lineLength - 1)
 1805         return string();
 1806 
 1807     size_t start = line.find_first_not_of(" \t", currPos + 1);
 1808     if (start == string::npos || !isLegalNameChar(line[start]))
 1809         return string();
 1810 
 1811     size_t end;         // end of the current word
 1812     for (end = start + 1; end <= lineLength; end++)
 1813     {
 1814         if (!isLegalNameChar(line[end]) || line[end] == '.')
 1815             break;
 1816     }
 1817 
 1818     return line.substr(start, end - start);
 1819 }
 1820 
 1821 /**
 1822  * Check if a preprocessor directive is always indented.
 1823  * C# "region" and "endregion" are always indented.
 1824  * C/C++ "pragma omp" is always indented.
 1825  *
 1826  * @return is true or false.
 1827  */
 1828 bool ASBeautifier::isIndentedPreprocessor(const string& line, size_t currPos) const
 1829 {
 1830     assert(line[0] == '#');
 1831     string nextWord = getNextWord(line, currPos);
 1832     if (nextWord == "region" || nextWord == "endregion")
 1833         return true;
 1834     // is it #pragma omp
 1835     if (nextWord == "pragma")
 1836     {
 1837         // find pragma
 1838         size_t start = line.find("pragma");
 1839         if (start == string::npos || !isLegalNameChar(line[start]))
 1840             return false;
 1841         // bypass pragma
 1842         for (; start < line.length(); start++)
 1843         {
 1844             if (!isLegalNameChar(line[start]))
 1845                 break;
 1846         }
 1847         start++;
 1848         if (start >= line.length())
 1849             return false;
 1850         // point to start of second word
 1851         start = line.find_first_not_of(" \t", start);
 1852         if (start == string::npos)
 1853             return false;
 1854         // point to end of second word
 1855         size_t end;
 1856         for (end = start; end < line.length(); end++)
 1857         {
 1858             if (!isLegalNameChar(line[end]))
 1859                 break;
 1860         }
 1861         // check for "pragma omp"
 1862         string word = line.substr(start, end - start);
 1863         if (word == "omp" || word == "region" || word == "endregion")
 1864             return true;
 1865     }
 1866     return false;
 1867 }
 1868 
 1869 /**
 1870  * Check if a preprocessor directive is checking for __cplusplus defined.
 1871  *
 1872  * @return is true or false.
 1873  */
 1874 bool ASBeautifier::isPreprocessorConditionalCplusplus(const string& line) const
 1875 {
 1876     string preproc = trim(line.substr(1));
 1877     if (preproc.compare(0, 5, "ifdef") == 0 && getNextWord(preproc, 4) == "__cplusplus")
 1878         return true;
 1879     if (preproc.compare(0, 2, "if") == 0)
 1880     {
 1881         // check for " #if defined(__cplusplus)"
 1882         size_t charNum = 2;
 1883         charNum = preproc.find_first_not_of(" \t", charNum);
 1884         if (charNum != string::npos && preproc.compare(charNum, 7, "defined") == 0)
 1885         {
 1886             charNum += 7;
 1887             charNum = preproc.find_first_not_of(" \t", charNum);
 1888             if (charNum != string::npos && preproc.compare(charNum, 1, "(") == 0)
 1889             {
 1890                 ++charNum;
 1891                 charNum = preproc.find_first_not_of(" \t", charNum);
 1892                 if (charNum != string::npos && preproc.compare(charNum, 11, "__cplusplus") == 0)
 1893                     return true;
 1894             }
 1895         }
 1896     }
 1897     return false;
 1898 }
 1899 
 1900 /**
 1901  * Check if a preprocessor definition contains an unterminated comment.
 1902  * Comments within a preprocessor definition can be continued without the backslash.
 1903  *
 1904  * @return is true or false.
 1905  */
 1906 bool ASBeautifier::isInPreprocessorUnterminatedComment(const string& line)
 1907 {
 1908     if (!isInPreprocessorComment)
 1909     {
 1910         size_t startPos = line.find("/*");
 1911         if (startPos == string::npos)
 1912             return false;
 1913     }
 1914     size_t endNum = line.find("*/");
 1915     if (endNum != string::npos)
 1916     {
 1917         isInPreprocessorComment = false;
 1918         return false;
 1919     }
 1920     isInPreprocessorComment = true;
 1921     return true;
 1922 }
 1923 
 1924 void ASBeautifier::popLastContinuationIndent()
 1925 {
 1926     assert(!continuationIndentStackSizeStack->empty());
 1927     int previousIndentStackSize = continuationIndentStackSizeStack->back();
 1928     if (continuationIndentStackSizeStack->size() > 1)
 1929         continuationIndentStackSizeStack->pop_back();
 1930     while (previousIndentStackSize < (int) continuationIndentStack->size())
 1931         continuationIndentStack->pop_back();
 1932 }
 1933 
 1934 // for unit testing
 1935 int ASBeautifier::getBeautifierFileType() const
 1936 { return beautifierFileType; }
 1937 
 1938 /**
 1939  * Process preprocessor statements and update the beautifier stacks.
 1940  */
 1941 void ASBeautifier::processPreprocessor(const string& preproc, const string& line)
 1942 {
 1943     // When finding a multi-lined #define statement, the original beautifier
 1944     // 1. sets its isInDefineDefinition flag
 1945     // 2. clones a new beautifier that will be used for the actual indentation
 1946     //    of the #define. This clone is put into the activeBeautifierStack in order
 1947     //    to be called for the actual indentation.
 1948     // The original beautifier will have isInDefineDefinition = true, isInDefine = false
 1949     // The cloned beautifier will have   isInDefineDefinition = true, isInDefine = true
 1950     if (shouldIndentPreprocDefine && preproc == "define" && line[line.length() - 1] == '\\')
 1951     {
 1952         if (!isInDefineDefinition)
 1953         {
 1954             // this is the original beautifier
 1955             isInDefineDefinition = true;
 1956 
 1957             // push a new beautifier into the active stack
 1958             // this beautifier will be used for the indentation of this define
 1959             ASBeautifier* defineBeautifier = new ASBeautifier(*this);
 1960             activeBeautifierStack->emplace_back(defineBeautifier);
 1961         }
 1962         else
 1963         {
 1964             // the is the cloned beautifier that is in charge of indenting the #define.
 1965             isInDefine = true;
 1966         }
 1967     }
 1968     else if (preproc.length() >= 2 && preproc.substr(0, 2) == "if")
 1969     {
 1970         if (isPreprocessorConditionalCplusplus(line) && !g_preprocessorCppExternCBrace)
 1971             g_preprocessorCppExternCBrace = 1;
 1972         // push a new beautifier into the stack
 1973         waitingBeautifierStackLengthStack->push_back(waitingBeautifierStack->size());
 1974         activeBeautifierStackLengthStack->push_back(activeBeautifierStack->size());
 1975         if (activeBeautifierStackLengthStack->back() == 0)
 1976             waitingBeautifierStack->emplace_back(new ASBeautifier(*this));
 1977         else
 1978             waitingBeautifierStack->emplace_back(new ASBeautifier(*activeBeautifierStack->back()));
 1979     }
 1980     else if (preproc == "else")
 1981     {
 1982         if ((waitingBeautifierStack != nullptr) && !waitingBeautifierStack->empty())
 1983         {
 1984             // MOVE current waiting beautifier to active stack.
 1985             activeBeautifierStack->emplace_back(waitingBeautifierStack->back());
 1986             waitingBeautifierStack->pop_back();
 1987         }
 1988     }
 1989     else if (preproc == "elif")
 1990     {
 1991         if ((waitingBeautifierStack != nullptr) && !waitingBeautifierStack->empty())
 1992         {
 1993             // append a COPY current waiting beautifier to active stack, WITHOUT deleting the original.
 1994             activeBeautifierStack->emplace_back(new ASBeautifier(*(waitingBeautifierStack->back())));
 1995         }
 1996     }
 1997     else if (preproc == "endif")
 1998     {
 1999         int stackLength = 0;
 2000         ASBeautifier* beautifier = nullptr;
 2001 
 2002         if (waitingBeautifierStackLengthStack != nullptr && !waitingBeautifierStackLengthStack->empty())
 2003         {
 2004             stackLength = waitingBeautifierStackLengthStack->back();
 2005             waitingBeautifierStackLengthStack->pop_back();
 2006             while ((int) waitingBeautifierStack->size() > stackLength)
 2007             {
 2008                 beautifier = waitingBeautifierStack->back();
 2009                 waitingBeautifierStack->pop_back();
 2010                 delete beautifier;
 2011             }
 2012         }
 2013 
 2014         if (!activeBeautifierStackLengthStack->empty())
 2015         {
 2016             stackLength = activeBeautifierStackLengthStack->back();
 2017             activeBeautifierStackLengthStack->pop_back();
 2018             while ((int) activeBeautifierStack->size() > stackLength)
 2019             {
 2020                 beautifier = activeBeautifierStack->back();
 2021                 activeBeautifierStack->pop_back();
 2022                 delete beautifier;
 2023             }
 2024         }
 2025     }
 2026 }
 2027 
 2028 // Compute the preliminary indentation based on data in the headerStack
 2029 // and data from previous lines.
 2030 // Update the class variable indentCount.
 2031 void ASBeautifier::computePreliminaryIndentation()
 2032 {
 2033     indentCount = 0;
 2034     spaceIndentCount = 0;
 2035     isInClassHeaderTab = false;
 2036 
 2037     if (isInObjCMethodDefinition && !continuationIndentStack->empty())
 2038         spaceIndentObjCMethodAlignment = continuationIndentStack->back();
 2039 
 2040     if (!continuationIndentStack->empty())
 2041         spaceIndentCount = continuationIndentStack->back();
 2042 
 2043     for (size_t i = 0; i < headerStack->size(); i++)
 2044     {
 2045         isInClass = false;
 2046 
 2047         if (blockIndent)
 2048         {
 2049             // do NOT indent opening block for these headers
 2050             if (!((*headerStack)[i] == &AS_NAMESPACE
 2051                     || (*headerStack)[i] == &AS_MODULE
 2052                     || (*headerStack)[i] == &AS_CLASS
 2053                     || (*headerStack)[i] == &AS_STRUCT
 2054                     || (*headerStack)[i] == &AS_UNION
 2055                     || (*headerStack)[i] == &AS_INTERFACE
 2056                     || (*headerStack)[i] == &AS_THROWS
 2057                     || (*headerStack)[i] == &AS_STATIC))
 2058                 ++indentCount;
 2059         }
 2060         else if (!(i > 0 && (*headerStack)[i - 1] != &AS_OPEN_BRACE
 2061                    && (*headerStack)[i] == &AS_OPEN_BRACE))
 2062             ++indentCount;
 2063 
 2064         if (!isJavaStyle() && !namespaceIndent && i > 0
 2065                 && ((*headerStack)[i - 1] == &AS_NAMESPACE
 2066                     || (*headerStack)[i - 1] == &AS_MODULE)
 2067                 && (*headerStack)[i] == &AS_OPEN_BRACE)
 2068             --indentCount;
 2069 
 2070         if (isCStyle() && i >= 1
 2071                 && (*headerStack)[i - 1] == &AS_CLASS
 2072                 && (*headerStack)[i] == &AS_OPEN_BRACE)
 2073         {
 2074             if (classIndent)
 2075                 ++indentCount;
 2076             isInClass = true;
 2077         }
 2078 
 2079         // is the switchIndent option is on, indent switch statements an additional indent.
 2080         else if (switchIndent && i > 1
 2081                  && (*headerStack)[i - 1] == &AS_SWITCH
 2082                  && (*headerStack)[i] == &AS_OPEN_BRACE)
 2083         {
 2084             ++indentCount;
 2085             isInSwitch = true;
 2086         }
 2087 
 2088     }   // end of for loop
 2089 
 2090     if (isInClassHeader)
 2091     {
 2092         if (!isJavaStyle())
 2093             isInClassHeaderTab = true;
 2094         if (lineOpensWithLineComment || lineStartsInComment || lineOpensWithComment)
 2095         {
 2096             if (!lineBeginsWithOpenBrace)
 2097                 --indentCount;
 2098             if (!continuationIndentStack->empty())
 2099                 spaceIndentCount -= continuationIndentStack->back();
 2100         }
 2101         else if (blockIndent)
 2102         {
 2103             if (!lineBeginsWithOpenBrace)
 2104                 ++indentCount;
 2105         }
 2106     }
 2107 
 2108     if (isInClassInitializer || isInEnumTypeID)
 2109     {
 2110         indentCount += classInitializerIndents;
 2111     }
 2112 
 2113     if (isInEnum && lineBeginsWithComma && !continuationIndentStack->empty())
 2114     {
 2115         // unregister '=' indent from the previous line
 2116         continuationIndentStack->pop_back();
 2117         isContinuation = false;
 2118         spaceIndentCount = 0;
 2119     }
 2120 
 2121     // Objective-C interface continuation line
 2122     if (isInObjCInterface)
 2123         ++indentCount;
 2124 
 2125     // unindent a class closing brace...
 2126     if (!lineStartsInComment
 2127             && isCStyle()
 2128             && isInClass
 2129             && classIndent
 2130             && headerStack->size() >= 2
 2131             && (*headerStack)[headerStack->size() - 2] == &AS_CLASS
 2132             && (*headerStack)[headerStack->size() - 1] == &AS_OPEN_BRACE
 2133             && lineBeginsWithCloseBrace
 2134             && braceBlockStateStack->back())
 2135         --indentCount;
 2136 
 2137     // unindent an indented switch closing brace...
 2138     else if (!lineStartsInComment
 2139              && isInSwitch
 2140              && switchIndent
 2141              && headerStack->size() >= 2
 2142              && (*headerStack)[headerStack->size() - 2] == &AS_SWITCH
 2143              && (*headerStack)[headerStack->size() - 1] == &AS_OPEN_BRACE
 2144              && lineBeginsWithCloseBrace)
 2145         --indentCount;
 2146 
 2147     // handle special case of run-in comment in an indented class statement
 2148     if (isInClass
 2149             && classIndent
 2150             && isInRunInComment
 2151             && !lineOpensWithComment
 2152             && headerStack->size() > 1
 2153             && (*headerStack)[headerStack->size() - 2] == &AS_CLASS)
 2154         --indentCount;
 2155 
 2156     if (isInConditional)
 2157         --indentCount;
 2158     if (g_preprocessorCppExternCBrace >= 4)
 2159         --indentCount;
 2160 }
 2161 
 2162 void ASBeautifier::adjustParsedLineIndentation(size_t iPrelim, bool isInExtraHeaderIndent)
 2163 {
 2164     if (lineStartsInComment)
 2165         return;
 2166 
 2167     // unindent a one-line statement in a header indent
 2168     if (!blockIndent
 2169             && lineBeginsWithOpenBrace
 2170             && headerStack->size() < iPrelim
 2171             && isInExtraHeaderIndent
 2172             && (lineOpeningBlocksNum > 0 && lineOpeningBlocksNum <= lineClosingBlocksNum)
 2173             && shouldIndentBracedLine)
 2174         --indentCount;
 2175 
 2176     /*
 2177      * if '{' doesn't follow an immediately previous '{' in the headerStack
 2178      * (but rather another header such as "for" or "if", then unindent it
 2179      * by one indentation relative to its block.
 2180      */
 2181     else if (!blockIndent
 2182              && lineBeginsWithOpenBrace
 2183              && !(lineOpeningBlocksNum > 0 && lineOpeningBlocksNum <= lineClosingBlocksNum)
 2184              && (headerStack->size() > 1 && (*headerStack)[headerStack->size() - 2] != &AS_OPEN_BRACE)
 2185              && shouldIndentBracedLine)
 2186         --indentCount;
 2187 
 2188     // must check one less in headerStack if more than one header on a line (allow-addins)...
 2189     else if (headerStack->size() > iPrelim + 1
 2190              && !blockIndent
 2191              && lineBeginsWithOpenBrace
 2192              && !(lineOpeningBlocksNum > 0 && lineOpeningBlocksNum <= lineClosingBlocksNum)
 2193              && (headerStack->size() > 2 && (*headerStack)[headerStack->size() - 3] != &AS_OPEN_BRACE)
 2194              && shouldIndentBracedLine)
 2195         --indentCount;
 2196 
 2197     // unindent a closing brace...
 2198     else if (lineBeginsWithCloseBrace
 2199              && shouldIndentBracedLine)
 2200         --indentCount;
 2201 
 2202     // correctly indent one-line-blocks...
 2203     else if (lineOpeningBlocksNum > 0
 2204              && lineOpeningBlocksNum == lineClosingBlocksNum
 2205              && previousLineProbationTab)
 2206         --indentCount;
 2207 
 2208     if (indentCount < 0)
 2209         indentCount = 0;
 2210 
 2211     // take care of extra brace indentation option...
 2212     if (!lineStartsInComment
 2213             && braceIndent
 2214             && shouldIndentBracedLine
 2215             && (lineBeginsWithOpenBrace || lineBeginsWithCloseBrace))
 2216     {
 2217         if (!braceIndentVtk)
 2218             ++indentCount;
 2219         else
 2220         {
 2221             // determine if a style VTK brace is indented
 2222             bool haveUnindentedBrace = false;
 2223             for (size_t i = 0; i < headerStack->size(); i++)
 2224             {
 2225                 if (((*headerStack)[i] == &AS_NAMESPACE
 2226                         || (*headerStack)[i] == &AS_MODULE
 2227                         || (*headerStack)[i] == &AS_CLASS
 2228                         || (*headerStack)[i] == &AS_STRUCT)
 2229                         && i + 1 < headerStack->size()
 2230                         && (*headerStack)[i + 1] == &AS_OPEN_BRACE)
 2231                     i++;
 2232                 else if (lineBeginsWithOpenBrace)
 2233                 {
 2234                     // don't double count the current brace
 2235                     if (i + 1 < headerStack->size()
 2236                             && (*headerStack)[i] == &AS_OPEN_BRACE)
 2237                         haveUnindentedBrace = true;
 2238                 }
 2239                 else if ((*headerStack)[i] == &AS_OPEN_BRACE)
 2240                     haveUnindentedBrace = true;
 2241             }   // end of for loop
 2242             if (haveUnindentedBrace)
 2243                 ++indentCount;
 2244         }
 2245     }
 2246 }
 2247 
 2248 /**
 2249  * Compute indentCount adjustment when in a series of else-if statements
 2250  * and shouldBreakElseIfs is requested.
 2251  * It increments by one for each 'else' in the tempStack.
 2252  */
 2253 int ASBeautifier::adjustIndentCountForBreakElseIfComments() const
 2254 {
 2255     assert(isElseHeaderIndent && !tempStacks->empty());
 2256     int indentCountIncrement = 0;
 2257     vector<const string*>* lastTempStack = tempStacks->back();
 2258     if (lastTempStack != nullptr)
 2259     {
 2260         for (size_t i = 0; i < lastTempStack->size(); i++)
 2261         {
 2262             if (*lastTempStack->at(i) == AS_ELSE)
 2263                 indentCountIncrement++;
 2264         }
 2265     }
 2266     return indentCountIncrement;
 2267 }
 2268 
 2269 /**
 2270  * Extract a preprocessor statement without the #.
 2271  * If a error occurs an empty string is returned.
 2272  */
 2273 string ASBeautifier::extractPreprocessorStatement(const string& line) const
 2274 {
 2275     string preproc;
 2276     size_t start = line.find_first_not_of("#/ \t");
 2277     if (start == string::npos)
 2278         return preproc;
 2279     size_t end = line.find_first_of("/ \t", start);
 2280     if (end == string::npos)
 2281         end = line.length();
 2282     preproc = line.substr(start, end - start);
 2283     return preproc;
 2284 }
 2285 
 2286 void ASBeautifier::adjustObjCMethodDefinitionIndentation(const string& line_)
 2287 {
 2288     // register indent for Objective-C continuation line
 2289     if (line_.length() > 0
 2290             && (line_[0] == '-' || line_[0] == '+'))
 2291     {
 2292         if (shouldAlignMethodColon && objCColonAlignSubsequent != -1)
 2293         {
 2294             string convertedLine = getIndentedSpaceEquivalent(line_);
 2295             colonIndentObjCMethodAlignment = findObjCColonAlignment(convertedLine);
 2296             int objCColonAlignSubsequentIndent = objCColonAlignSubsequent + indentLength;
 2297             if (objCColonAlignSubsequentIndent > colonIndentObjCMethodAlignment)
 2298                 colonIndentObjCMethodAlignment = objCColonAlignSubsequentIndent;
 2299         }
 2300         else if (continuationIndentStack->empty()
 2301                  || continuationIndentStack->back() == 0)
 2302         {
 2303             continuationIndentStack->emplace_back(indentLength);
 2304             isContinuation = true;
 2305         }
 2306     }
 2307     // set indent for last definition line
 2308     else if (!lineBeginsWithOpenBrace)
 2309     {
 2310         if (shouldAlignMethodColon)
 2311             spaceIndentCount = computeObjCColonAlignment(line_, colonIndentObjCMethodAlignment);
 2312         else if (continuationIndentStack->empty())
 2313             spaceIndentCount = spaceIndentObjCMethodAlignment;
 2314     }
 2315 }
 2316 
 2317 void ASBeautifier::adjustObjCMethodCallIndentation(const string& line_)
 2318 {
 2319     static int keywordIndentObjCMethodAlignment = 0;
 2320     if (shouldAlignMethodColon && objCColonAlignSubsequent != -1)
 2321     {
 2322         if (isInObjCMethodCallFirst)
 2323         {
 2324             isInObjCMethodCallFirst = false;
 2325             string convertedLine = getIndentedSpaceEquivalent(line_);
 2326             bracePosObjCMethodAlignment = convertedLine.find('[');
 2327             keywordIndentObjCMethodAlignment =
 2328                 getObjCFollowingKeyword(convertedLine, bracePosObjCMethodAlignment);
 2329             colonIndentObjCMethodAlignment = findObjCColonAlignment(convertedLine);
 2330             if (colonIndentObjCMethodAlignment >= 0)
 2331             {
 2332                 int objCColonAlignSubsequentIndent = objCColonAlignSubsequent + indentLength;
 2333                 if (objCColonAlignSubsequentIndent > colonIndentObjCMethodAlignment)
 2334                     colonIndentObjCMethodAlignment = objCColonAlignSubsequentIndent;
 2335                 if (lineBeginsWithOpenBrace)
 2336                     colonIndentObjCMethodAlignment -= indentLength;
 2337             }
 2338         }
 2339         else
 2340         {
 2341             if (findObjCColonAlignment(line_) != -1)
 2342             {
 2343                 if (colonIndentObjCMethodAlignment < 0)
 2344                     spaceIndentCount += computeObjCColonAlignment(line_, objCColonAlignSubsequent);
 2345                 else if (objCColonAlignSubsequent > colonIndentObjCMethodAlignment)
 2346                     spaceIndentCount = computeObjCColonAlignment(line_, objCColonAlignSubsequent);
 2347                 else
 2348                     spaceIndentCount = computeObjCColonAlignment(line_, colonIndentObjCMethodAlignment);
 2349             }
 2350             else
 2351             {
 2352                 if (spaceIndentCount < colonIndentObjCMethodAlignment)
 2353                     spaceIndentCount += keywordIndentObjCMethodAlignment;
 2354             }
 2355         }
 2356     }
 2357     else    // align keywords instead of colons
 2358     {
 2359         if (isInObjCMethodCallFirst)
 2360         {
 2361             isInObjCMethodCallFirst = false;
 2362             string convertedLine = getIndentedSpaceEquivalent(line_);
 2363             bracePosObjCMethodAlignment = convertedLine.find('[');
 2364             keywordIndentObjCMethodAlignment =
 2365                 getObjCFollowingKeyword(convertedLine, bracePosObjCMethodAlignment);
 2366         }
 2367         else
 2368         {
 2369             if (spaceIndentCount < keywordIndentObjCMethodAlignment + bracePosObjCMethodAlignment)
 2370                 spaceIndentCount += keywordIndentObjCMethodAlignment;
 2371         }
 2372     }
 2373 }
 2374 
 2375 /**
 2376  * Clear the variables used to align the Objective-C method definitions.
 2377  */
 2378 void ASBeautifier::clearObjCMethodDefinitionAlignment()
 2379 {
 2380     assert(isImmediatelyPostObjCMethodDefinition);
 2381     spaceIndentCount = 0;
 2382     spaceIndentObjCMethodAlignment = 0;
 2383     colonIndentObjCMethodAlignment = 0;
 2384     isInObjCMethodDefinition = false;
 2385     isImmediatelyPostObjCMethodDefinition = false;
 2386     if (!continuationIndentStack->empty())
 2387         continuationIndentStack->pop_back();
 2388 }
 2389 
 2390 /**
 2391  * Find the first alignment colon on a line.
 2392  * Ternary operators (?) are bypassed.
 2393  */
 2394 int ASBeautifier::findObjCColonAlignment(const string& line) const
 2395 {
 2396     bool haveTernary = false;
 2397     for (size_t i = 0; i < line.length(); i++)
 2398     {
 2399         i = line.find_first_of(":?", i);
 2400         if (i == string::npos)
 2401             break;
 2402 
 2403         if (line[i] == '?')
 2404         {
 2405             haveTernary = true;
 2406             continue;
 2407         }
 2408         if (haveTernary)
 2409         {
 2410             haveTernary = false;
 2411             continue;
 2412         }
 2413         return i;
 2414     }
 2415     return -1;
 2416 }
 2417 
 2418 /**
 2419  * Compute the spaceIndentCount necessary to align the current line colon
 2420  * with the colon position in the argument.
 2421  * If it cannot be aligned indentLength is returned and a new colon
 2422  * position is calculated.
 2423  */
 2424 int ASBeautifier::computeObjCColonAlignment(const string& line, int colonAlignPosition) const
 2425 {
 2426     int colonPosition = findObjCColonAlignment(line);
 2427     if (colonPosition < 0 || colonPosition > colonAlignPosition)
 2428         return indentLength;
 2429     return (colonAlignPosition - colonPosition);
 2430 }
 2431 
 2432 /*
 2433  * Compute position of the keyword following the method call object.
 2434  * This is oversimplified to find unusual method calls.
 2435  * Use for now and see what happens.
 2436  * Most programmers will probably use align-method-colon anyway.
 2437  */
 2438 int ASBeautifier::getObjCFollowingKeyword(const string& line, int bracePos) const
 2439 {
 2440     assert(bracePos >= 0);
 2441     assert(line[bracePos] == '[');
 2442     size_t firstText = line.find_first_not_of(" \t", bracePos + 1);
 2443     if (firstText == string::npos)
 2444         return -(indentCount * indentLength - 1);
 2445     size_t searchBeg = firstText;
 2446     size_t objectEnd = 0;   // end of object text
 2447     if (line[searchBeg] == '[')
 2448     {
 2449         objectEnd = line.find(']', searchBeg + 1);
 2450         if (objectEnd == string::npos)
 2451             return 0;
 2452     }
 2453     else
 2454     {
 2455         if (line[searchBeg] == '(')
 2456         {
 2457             searchBeg = line.find(')', searchBeg + 1);
 2458             if (searchBeg == string::npos)
 2459                 return 0;
 2460         }
 2461         // bypass the object name
 2462         objectEnd = line.find_first_of(" \t", searchBeg + 1);
 2463         if (objectEnd == string::npos)
 2464             return 0;
 2465         --objectEnd;
 2466     }
 2467     size_t keyPos = line.find_first_not_of(" \t", objectEnd + 1);
 2468     if (keyPos == string::npos)
 2469         return 0;
 2470     return keyPos - firstText;
 2471 }
 2472 
 2473 /**
 2474  * Get a line using the current space indent with all tabs replaced by spaces.
 2475  * The indentCount is NOT included
 2476  * Needed to compute an accurate alignment.
 2477  */
 2478 string ASBeautifier::getIndentedSpaceEquivalent(const string& line_) const
 2479 {
 2480     string spaceIndent;
 2481     spaceIndent.append(spaceIndentCount, ' ');
 2482     string convertedLine = spaceIndent + line_;
 2483     for (size_t i = spaceIndent.length(); i < convertedLine.length(); i++)
 2484     {
 2485         if (convertedLine[i] == '\t')
 2486         {
 2487             size_t numSpaces = indentLength - (i % indentLength);
 2488             convertedLine.replace(i, 1, numSpaces, ' ');
 2489             i += indentLength - 1;
 2490         }
 2491     }
 2492     return convertedLine;
 2493 }
 2494 
 2495 /**
 2496  * Determine if an item is at a top level.
 2497  */
 2498 bool ASBeautifier::isTopLevel() const
 2499 {
 2500     if (headerStack->empty())
 2501         return true;
 2502     if (headerStack->back() == &AS_OPEN_BRACE
 2503             && headerStack->size() >= 2)
 2504     {
 2505         if ((*headerStack)[headerStack->size() - 2] == &AS_NAMESPACE
 2506                 || (*headerStack)[headerStack->size() - 2] == &AS_MODULE
 2507                 || (*headerStack)[headerStack->size() - 2] == &AS_CLASS
 2508                 || (*headerStack)[headerStack->size() - 2] == &AS_INTERFACE
 2509                 || (*headerStack)[headerStack->size() - 2] == &AS_STRUCT
 2510                 || (*headerStack)[headerStack->size() - 2] == &AS_UNION)
 2511             return true;
 2512     }
 2513     if (headerStack->back() == &AS_NAMESPACE
 2514             || headerStack->back() == &AS_MODULE
 2515             || headerStack->back() == &AS_CLASS
 2516             || headerStack->back() == &AS_INTERFACE
 2517             || headerStack->back() == &AS_STRUCT
 2518             || headerStack->back() == &AS_UNION)
 2519         return true;
 2520     return false;
 2521 }
 2522 
 2523 /**
 2524  * Parse the current line to update indentCount and spaceIndentCount.
 2525  */
 2526 void ASBeautifier::parseCurrentLine(const string& line)
 2527 {
 2528     bool isInLineComment = false;
 2529     bool isInOperator = false;
 2530     bool isSpecialChar = false;
 2531     bool haveCaseIndent = false;
 2532     bool haveAssignmentThisLine = false;
 2533     bool closingBraceReached = false;
 2534     bool previousLineProbation = (probationHeader != nullptr);
 2535     char ch = ' ';
 2536     int tabIncrementIn = 0;
 2537     if (isInQuote
 2538             && !haveLineContinuationChar
 2539             && !isInVerbatimQuote
 2540             && !isInAsm)
 2541         isInQuote = false;              // missing closing quote
 2542     haveLineContinuationChar = false;
 2543 
 2544     for (size_t i = 0; i < line.length(); i++)
 2545     {
 2546         ch = line[i];
 2547 
 2548         if (isInBeautifySQL)
 2549             continue;
 2550 
 2551         // handle special characters (i.e. backslash+character such as \n, \t, ...)
 2552         if (isInQuote && !isInVerbatimQuote)
 2553         {
 2554             if (isSpecialChar)
 2555             {
 2556                 isSpecialChar = false;
 2557                 continue;
 2558             }
 2559             if (line.compare(i, 2, "\\\\") == 0)
 2560             {
 2561                 i++;
 2562                 continue;
 2563             }
 2564             if (ch == '\\')
 2565             {
 2566                 if (peekNextChar(line, i) == ' ')   // is this '\' at end of line
 2567                     haveLineContinuationChar = true;
 2568                 else
 2569                     isSpecialChar = true;
 2570                 continue;
 2571             }
 2572         }
 2573         else if (isInDefine && ch == '\\')
 2574             continue;
 2575 
 2576         // bypass whitespace here
 2577         if (isWhiteSpace(ch))
 2578         {
 2579             if (ch == '\t')
 2580                 tabIncrementIn += convertTabToSpaces(i, tabIncrementIn);
 2581             continue;
 2582         }
 2583 
 2584         // handle quotes (such as 'x' and "Hello Dolly")
 2585         if (!(isInComment || isInLineComment)
 2586                 && (ch == '"'
 2587                     || (ch == '\'' && !isDigitSeparator(line, i))))
 2588         {
 2589             if (!isInQuote)
 2590             {
 2591                 quoteChar = ch;
 2592                 isInQuote = true;
 2593                 char prevCh = i > 0 ? line[i - 1] : ' ';
 2594                 if (isCStyle() && prevCh == 'R')
 2595                 {
 2596                     int parenPos = line.find('(', i);
 2597                     if (parenPos != -1)
 2598                     {
 2599                         isInVerbatimQuote = true;
 2600                         verbatimDelimiter = line.substr(i + 1, parenPos - i - 1);
 2601                     }
 2602                 }
 2603                 else if (isSharpStyle() && prevCh == '@')
 2604                     isInVerbatimQuote = true;
 2605                 // check for "C" following "extern"
 2606                 else if (g_preprocessorCppExternCBrace == 2 && line.compare(i, 3, "\"C\"") == 0)
 2607                     ++g_preprocessorCppExternCBrace;
 2608             }
 2609             else if (isInVerbatimQuote && ch == '"')
 2610             {
 2611                 if (isCStyle())
 2612                 {
 2613                     string delim = ')' + verbatimDelimiter;
 2614                     int delimStart = i - delim.length();
 2615                     if (delimStart > 0 && line.substr(delimStart, delim.length()) == delim)
 2616                     {
 2617                         isInQuote = false;
 2618                         isInVerbatimQuote = false;
 2619                     }
 2620                 }
 2621                 else if (isSharpStyle())
 2622                 {
 2623                     if (line.compare(i, 2, "\"\"") == 0)
 2624                         i++;
 2625                     else
 2626                     {
 2627                         isInQuote = false;
 2628                         isInVerbatimQuote = false;
 2629                         continue;
 2630                     }
 2631                 }
 2632             }
 2633             else if (quoteChar == ch)
 2634             {
 2635                 isInQuote = false;
 2636                 isContinuation = true;
 2637                 continue;
 2638             }
 2639         }
 2640         if (isInQuote)
 2641             continue;
 2642 
 2643         // handle comments
 2644 
 2645         if (!(isInComment || isInLineComment) && line.compare(i, 2, "//") == 0)
 2646         {
 2647             // if there is a 'case' statement after these comments unindent by 1
 2648             if (isCaseHeaderCommentIndent)
 2649                 --indentCount;
 2650             // isElseHeaderIndent is set by ASFormatter if shouldBreakElseIfs is requested
 2651             // if there is an 'else' after these comments a tempStacks indent is required
 2652             if (isElseHeaderIndent && lineOpensWithLineComment && !tempStacks->empty())
 2653                 indentCount += adjustIndentCountForBreakElseIfComments();
 2654             isInLineComment = true;
 2655             i++;
 2656             continue;
 2657         }
 2658         if (!(isInComment || isInLineComment) && line.compare(i, 2, "/*") == 0)
 2659         {
 2660             // if there is a 'case' statement after these comments unindent by 1
 2661             if (isCaseHeaderCommentIndent && lineOpensWithComment)
 2662                 --indentCount;
 2663             // isElseHeaderIndent is set by ASFormatter if shouldBreakElseIfs is requested
 2664             // if there is an 'else' after these comments a tempStacks indent is required
 2665             if (isElseHeaderIndent && lineOpensWithComment && !tempStacks->empty())
 2666                 indentCount += adjustIndentCountForBreakElseIfComments();
 2667             isInComment = true;
 2668             i++;
 2669             if (!lineOpensWithComment)              // does line start with comment?
 2670                 blockCommentNoIndent = true;        // if no, cannot indent continuation lines
 2671             continue;
 2672         }
 2673         if ((isInComment || isInLineComment) && line.compare(i, 2, "*/") == 0)
 2674         {
 2675             size_t firstText = line.find_first_not_of(" \t");
 2676             // if there is a 'case' statement after these comments unindent by 1
 2677             // only if the ending comment is the first entry on the line
 2678             if (isCaseHeaderCommentIndent && firstText == i)
 2679                 --indentCount;
 2680             // if this comment close starts the line, must check for else-if indent
 2681             // isElseHeaderIndent is set by ASFormatter if shouldBreakElseIfs is requested
 2682             // if there is an 'else' after these comments a tempStacks indent is required
 2683             if (firstText == i)
 2684             {
 2685                 if (isElseHeaderIndent && !lineOpensWithComment && !tempStacks->empty())
 2686                     indentCount += adjustIndentCountForBreakElseIfComments();
 2687             }
 2688             isInComment = false;
 2689             i++;
 2690             blockCommentNoIndent = false;           // ok to indent next comment
 2691             continue;
 2692         }
 2693         // treat indented preprocessor lines as a line comment
 2694         if (line[0] == '#' && isIndentedPreprocessor(line, i))
 2695         {
 2696             isInLineComment = true;
 2697         }
 2698 
 2699         if (isInLineComment)
 2700         {
 2701             // bypass rest of the comment up to the comment end
 2702             while (i + 1 < line.length())
 2703                 i++;
 2704 
 2705             continue;
 2706         }
 2707         if (isInComment)
 2708         {
 2709             // if there is a 'case' statement after these comments unindent by 1
 2710             if (!lineOpensWithComment && isCaseHeaderCommentIndent)
 2711                 --indentCount;
 2712             // isElseHeaderIndent is set by ASFormatter if shouldBreakElseIfs is requested
 2713             // if there is an 'else' after these comments a tempStacks indent is required
 2714             if (!lineOpensWithComment && isElseHeaderIndent && !tempStacks->empty())
 2715                 indentCount += adjustIndentCountForBreakElseIfComments();
 2716             // bypass rest of the comment up to the comment end
 2717             while (i + 1 < line.length()
 2718                     && line.compare(i + 1, 2, "*/") != 0)
 2719                 i++;
 2720 
 2721             continue;
 2722         }
 2723 
 2724         // if we have reached this far then we are NOT in a comment or string of special character...
 2725 
 2726         if (probationHeader != nullptr)
 2727         {
 2728             if ((probationHeader == &AS_STATIC && ch == '{')
 2729                     || (probationHeader == &AS_SYNCHRONIZED && ch == '('))
 2730             {
 2731                 // insert the probation header as a new header
 2732                 isInHeader = true;
 2733                 headerStack->emplace_back(probationHeader);
 2734 
 2735                 // handle the specific probation header
 2736                 isInConditional = (probationHeader == &AS_SYNCHRONIZED);
 2737 
 2738                 isContinuation = false;
 2739                 // if the probation comes from the previous line, then indent by 1 tab count.
 2740                 if (previousLineProbation
 2741                         && ch == '{'
 2742                         && !(blockIndent && probationHeader == &AS_STATIC))
 2743                 {
 2744                     ++indentCount;
 2745                     previousLineProbationTab = true;
 2746                 }
 2747                 previousLineProbation = false;
 2748             }
 2749 
 2750             // dismiss the probation header
 2751             probationHeader = nullptr;
 2752         }
 2753 
 2754         prevNonSpaceCh = currentNonSpaceCh;
 2755         currentNonSpaceCh = ch;
 2756         if (!isLegalNameChar(ch) && ch != ',' && ch != ';')
 2757         {
 2758             prevNonLegalCh = currentNonLegalCh;
 2759             currentNonLegalCh = ch;
 2760         }
 2761 
 2762         if (isInHeader)
 2763         {
 2764             isInHeader = false;
 2765             currentHeader = headerStack->back();
 2766         }
 2767         else
 2768             currentHeader = nullptr;
 2769 
 2770         if (isCStyle() && isInTemplate
 2771                 && (ch == '<' || ch == '>')
 2772                 && !(line.length() > i + 1 && line.compare(i, 2, ">=") == 0))
 2773         {
 2774             if (ch == '<')
 2775             {
 2776                 ++templateDepth;
 2777                 continuationIndentStackSizeStack->push_back(continuationIndentStack->size());
 2778                 registerContinuationIndent(line, i, spaceIndentCount, tabIncrementIn, 0, true);
 2779             }
 2780             else if (ch == '>')
 2781             {
 2782                 popLastContinuationIndent();
 2783                 if (--templateDepth <= 0)
 2784                 {
 2785                     ch = ';';
 2786                     isInTemplate = false;
 2787                     templateDepth = 0;
 2788                 }
 2789             }
 2790         }
 2791 
 2792         // handle parentheses
 2793         if (ch == '(' || ch == '[' || ch == ')' || ch == ']')
 2794         {
 2795             if (ch == '(' || ch == '[')
 2796             {
 2797                 isInOperator = false;
 2798                 // if have a struct header, this is a declaration not a definition
 2799                 if (ch == '('
 2800                         && !headerStack->empty()
 2801                         && headerStack->back() == &AS_STRUCT)
 2802                 {
 2803                     headerStack->pop_back();
 2804                     isInClassHeader = false;
 2805                     if (line.find(AS_STRUCT, 0) > i)    // if not on this line
 2806                         indentCount -= classInitializerIndents;
 2807                     if (indentCount < 0)
 2808                         indentCount = 0;
 2809                 }
 2810 
 2811                 if (parenDepth == 0)
 2812                 {
 2813                     parenStatementStack->push_back(isContinuation);
 2814                     isContinuation = true;
 2815                 }
 2816                 parenDepth++;
 2817                 if (ch == '[')
 2818                 {
 2819                     ++squareBracketCount;
 2820                     if (squareBracketCount == 1 && isCStyle())
 2821                     {
 2822                         isInObjCMethodCall = true;
 2823                         isInObjCMethodCallFirst = true;
 2824                     }
 2825                 }
 2826 
 2827                 continuationIndentStackSizeStack->push_back(continuationIndentStack->size());
 2828 
 2829                 if (currentHeader != nullptr)
 2830                     registerContinuationIndent(line, i, spaceIndentCount, tabIncrementIn, minConditionalIndent, true);
 2831                 else if (!isInObjCMethodDefinition)
 2832                     registerContinuationIndent(line, i, spaceIndentCount, tabIncrementIn, 0, true);
 2833             }
 2834             else if (ch == ')' || ch == ']')
 2835             {
 2836                 if (ch == ']')
 2837                     --squareBracketCount;
 2838                 if (squareBracketCount <= 0)
 2839                 {
 2840                     squareBracketCount = 0;
 2841                     if (isInObjCMethodCall)
 2842                         isImmediatelyPostObjCMethodCall = true;
 2843                 }
 2844                 foundPreCommandHeader = false;
 2845                 parenDepth--;
 2846                 if (parenDepth == 0)
 2847                 {
 2848                     if (!parenStatementStack->empty())      // in case of unmatched closing parens
 2849                     {
 2850                         isContinuation = parenStatementStack->back();
 2851                         parenStatementStack->pop_back();
 2852                     }
 2853                     isInAsm = false;
 2854                     isInConditional = false;
 2855                 }
 2856 
 2857                 if (!continuationIndentStackSizeStack->empty())
 2858                 {
 2859                     popLastContinuationIndent();
 2860 
 2861                     if (!parenIndentStack->empty())
 2862                     {
 2863                         int poppedIndent = parenIndentStack->back();
 2864                         parenIndentStack->pop_back();
 2865 
 2866                         if (i == 0)
 2867                             spaceIndentCount = poppedIndent;
 2868                     }
 2869                 }
 2870             }
 2871             continue;
 2872         }
 2873 
 2874         if (ch == '{')
 2875         {
 2876             // first, check if '{' is a block-opener or a static-array opener
 2877             bool isBlockOpener = ((prevNonSpaceCh == '{' && braceBlockStateStack->back())
 2878                                   || prevNonSpaceCh == '}'
 2879                                   || prevNonSpaceCh == ')'
 2880                                   || prevNonSpaceCh == ';'
 2881                                   || peekNextChar(line, i) == '{'
 2882                                   || isInTrailingReturnType
 2883                                   || foundPreCommandHeader
 2884                                   || foundPreCommandMacro
 2885                                   || isInClassHeader
 2886                                   || (isInClassInitializer && !isLegalNameChar(prevNonSpaceCh))
 2887                                   || isNonInStatementArray
 2888                                   || isInObjCMethodDefinition
 2889                                   || isInObjCInterface
 2890                                   || isSharpAccessor
 2891                                   || isSharpDelegate
 2892                                   || isInExternC
 2893                                   || isInAsmBlock
 2894                                   || getNextWord(line, i) == AS_NEW
 2895                                   || (isInDefine
 2896                                       && (prevNonSpaceCh == '('
 2897                                           || isLegalNameChar(prevNonSpaceCh))));
 2898 
 2899             if (isInObjCMethodDefinition)
 2900             {
 2901                 objCColonAlignSubsequent = 0;
 2902                 isImmediatelyPostObjCMethodDefinition = true;
 2903                 if (lineBeginsWithOpenBrace)        // for run-in braces
 2904                     clearObjCMethodDefinitionAlignment();
 2905             }
 2906 
 2907             if (!isBlockOpener && !isContinuation && !isInClassInitializer && !isInEnum)
 2908             {
 2909                 if (isTopLevel())
 2910                     isBlockOpener = true;
 2911             }
 2912 
 2913             if (!isBlockOpener && currentHeader != nullptr)
 2914             {
 2915                 for (size_t n = 0; n < nonParenHeaders->size(); n++)
 2916                     if (currentHeader == (*nonParenHeaders)[n])
 2917                     {
 2918                         isBlockOpener = true;
 2919                         break;
 2920                     }
 2921             }
 2922 
 2923             braceBlockStateStack->push_back(isBlockOpener);
 2924 
 2925             if (!isBlockOpener)
 2926             {
 2927                 continuationIndentStackSizeStack->push_back(continuationIndentStack->size());
 2928                 registerContinuationIndent(line, i, spaceIndentCount, tabIncrementIn, 0, true);
 2929                 parenDepth++;
 2930                 if (i == 0)
 2931                     shouldIndentBracedLine = false;
 2932                 isInEnumTypeID = false;
 2933 
 2934                 continue;
 2935             }
 2936 
 2937             // this brace is a block opener...
 2938 
 2939             ++lineOpeningBlocksNum;
 2940 
 2941             if (isInClassInitializer || isInEnumTypeID)
 2942             {
 2943                 // decrease tab count if brace is broken
 2944                 if (lineBeginsWithOpenBrace)
 2945                 {
 2946                     indentCount -= classInitializerIndents;
 2947                     // decrease one more if an empty class
 2948                     if (!headerStack->empty()
 2949                             && (*headerStack).back() == &AS_CLASS)
 2950                     {
 2951                         int nextChar = getNextProgramCharDistance(line, i);
 2952                         if ((int) line.length() > nextChar && line[nextChar] == '}')
 2953                             --indentCount;
 2954                     }
 2955                 }
 2956             }
 2957 
 2958             if (isInObjCInterface)
 2959             {
 2960                 isInObjCInterface = false;
 2961                 if (lineBeginsWithOpenBrace)
 2962                     --indentCount;
 2963             }
 2964 
 2965             if (braceIndent && !namespaceIndent && !headerStack->empty()
 2966                     && ((*headerStack).back() == &AS_NAMESPACE
 2967                         || (*headerStack).back() == &AS_MODULE))
 2968             {
 2969                 shouldIndentBracedLine = false;
 2970                 --indentCount;
 2971             }
 2972 
 2973             // an indentable struct is treated like a class in the header stack
 2974             if (!headerStack->empty()
 2975                     && (*headerStack).back() == &AS_STRUCT
 2976                     && isInIndentableStruct)
 2977                 (*headerStack).back() = &AS_CLASS;
 2978 
 2979             // is a brace inside a paren?
 2980             parenDepthStack->emplace_back(parenDepth);
 2981             blockStatementStack->push_back(isContinuation);
 2982 
 2983             if (!continuationIndentStack->empty())
 2984             {
 2985                 // completely purge the continuationIndentStack
 2986                 while (!continuationIndentStack->empty())
 2987                     popLastContinuationIndent();
 2988                 if (isInClassInitializer || isInClassHeaderTab)
 2989                 {
 2990                     if (lineBeginsWithOpenBrace || lineBeginsWithComma)
 2991                         spaceIndentCount = 0;
 2992                 }
 2993                 else
 2994                     spaceIndentCount = 0;
 2995             }
 2996 
 2997             blockTabCount += (isContinuation ? 1 : 0);
 2998             if (g_preprocessorCppExternCBrace == 3)
 2999                 ++g_preprocessorCppExternCBrace;
 3000             parenDepth = 0;
 3001             isInTrailingReturnType = false;
 3002             isInClassHeader = false;
 3003             isInClassHeaderTab = false;
 3004             isInClassInitializer = false;
 3005             isInEnumTypeID = false;
 3006             isContinuation = false;
 3007             isInQuestion = false;
 3008             isInLet = false;
 3009             foundPreCommandHeader = false;
 3010             foundPreCommandMacro = false;
 3011             isInExternC = false;
 3012 
 3013             tempStacks->emplace_back(new vector<const string*>);
 3014             headerStack->emplace_back(&AS_OPEN_BRACE);
 3015             lastLineHeader = &AS_OPEN_BRACE;
 3016 
 3017             continue;
 3018         }   // end '{'
 3019 
 3020         //check if a header has been reached
 3021         bool isPotentialHeader = isCharPotentialHeader(line, i);
 3022 
 3023         if (isPotentialHeader && squareBracketCount == 0)
 3024         {
 3025             const string* newHeader = findHeader(line, i, headers);
 3026 
 3027             // java can have a 'default' not in a switch
 3028             if (newHeader == &AS_DEFAULT
 3029                     && peekNextChar(line, (i + (*newHeader).length() - 1)) != ':')
 3030                 newHeader = nullptr;
 3031             // Qt headers may be variables in C++
 3032             if (isCStyle()
 3033                     && (newHeader == &AS_FOREVER || newHeader == &AS_FOREACH))
 3034             {
 3035                 if (line.find_first_of("=;", i) != string::npos)
 3036                     newHeader = nullptr;
 3037             }
 3038             else if (isSharpStyle()
 3039                      && (newHeader == &AS_GET || newHeader == &AS_SET))
 3040             {
 3041                 if (getNextWord(line, i + (*newHeader).length()) == "is")
 3042                     newHeader = nullptr;
 3043             }
 3044             else if (newHeader == &AS_USING
 3045                      && peekNextChar(line, i + (*newHeader).length() - 1) != '(')
 3046                 newHeader = nullptr;
 3047 
 3048             if (newHeader != nullptr)
 3049             {
 3050                 // if we reached here, then this is a header...
 3051                 bool isIndentableHeader = true;
 3052 
 3053                 isInHeader = true;
 3054 
 3055                 vector<const string*>* lastTempStack = nullptr;;
 3056                 if (!tempStacks->empty())
 3057                     lastTempStack = tempStacks->back();
 3058 
 3059                 // if a new block is opened, push a new stack into tempStacks to hold the
 3060                 // future list of headers in the new block.
 3061 
 3062                 // take care of the special case: 'else if (...)'
 3063                 if (newHeader == &AS_IF && lastLineHeader == &AS_ELSE)
 3064                 {
 3065                     if (!headerStack->empty())
 3066                         headerStack->pop_back();
 3067                 }
 3068 
 3069                 // take care of 'else'
 3070                 else if (newHeader == &AS_ELSE)
 3071                 {
 3072                     if (lastTempStack != nullptr)
 3073                     {
 3074                         int indexOfIf = indexOf(*lastTempStack, &AS_IF);
 3075                         if (indexOfIf != -1)
 3076                         {
 3077                             // recreate the header list in headerStack up to the previous 'if'
 3078                             // from the temporary snapshot stored in lastTempStack.
 3079                             int restackSize = lastTempStack->size() - indexOfIf - 1;
 3080                             for (int r = 0; r < restackSize; r++)
 3081                             {
 3082                                 headerStack->emplace_back(lastTempStack->back());
 3083                                 lastTempStack->pop_back();
 3084                             }
 3085                             if (!closingBraceReached)
 3086                                 indentCount += restackSize;
 3087                         }
 3088                         /*
 3089                          * If the above if is not true, i.e. no 'if' before the 'else',
 3090                          * then nothing beautiful will come out of this...
 3091                          * I should think about inserting an Exception here to notify the caller of this...
 3092                          */
 3093                     }
 3094                 }
 3095 
 3096                 // check if 'while' closes a previous 'do'
 3097                 else if (newHeader == &AS_WHILE)
 3098                 {
 3099                     if (lastTempStack != nullptr)
 3100                     {
 3101                         int indexOfDo = indexOf(*lastTempStack, &AS_DO);
 3102                         if (indexOfDo != -1)
 3103                         {
 3104                             // recreate the header list in headerStack up to the previous 'do'
 3105                             // from the temporary snapshot stored in lastTempStack.
 3106                             int restackSize = lastTempStack->size() - indexOfDo - 1;
 3107                             for (int r = 0; r < restackSize; r++)
 3108                             {
 3109                                 headerStack->emplace_back(lastTempStack->back());
 3110                                 lastTempStack->pop_back();
 3111                             }
 3112                             if (!closingBraceReached)
 3113                                 indentCount += restackSize;
 3114                         }
 3115                     }
 3116                 }
 3117                 // check if 'catch' closes a previous 'try' or 'catch'
 3118                 else if (newHeader == &AS_CATCH || newHeader == &AS_FINALLY)
 3119                 {
 3120                     if (lastTempStack != nullptr)
 3121                     {
 3122                         int indexOfTry = indexOf(*lastTempStack, &AS_TRY);
 3123                         if (indexOfTry == -1)
 3124                             indexOfTry = indexOf(*lastTempStack, &AS_CATCH);
 3125                         if (indexOfTry != -1)
 3126                         {
 3127                             // recreate the header list in headerStack up to the previous 'try'
 3128                             // from the temporary snapshot stored in lastTempStack.
 3129                             int restackSize = lastTempStack->size() - indexOfTry - 1;
 3130                             for (int r = 0; r < restackSize; r++)
 3131                             {
 3132                                 headerStack->emplace_back(lastTempStack->back());
 3133                                 lastTempStack->pop_back();
 3134                             }
 3135 
 3136                             if (!closingBraceReached)
 3137                                 indentCount += restackSize;
 3138                         }
 3139                     }
 3140                 }
 3141                 else if (newHeader == &AS_CASE)
 3142                 {
 3143                     isInCase = true;
 3144                     if (!haveCaseIndent)
 3145                     {
 3146                         haveCaseIndent = true;
 3147                         if (!lineBeginsWithOpenBrace)
 3148                             --indentCount;
 3149                     }
 3150                 }
 3151                 else if (newHeader == &AS_DEFAULT)
 3152                 {
 3153                     isInCase = true;
 3154                     --indentCount;
 3155                 }
 3156                 else if (newHeader == &AS_STATIC
 3157                          || newHeader == &AS_SYNCHRONIZED)
 3158                 {
 3159                     if (!headerStack->empty()
 3160                             && (headerStack->back() == &AS_STATIC
 3161                                 || headerStack->back() == &AS_SYNCHRONIZED))
 3162                     {
 3163                         isIndentableHeader = false;
 3164                     }
 3165                     else
 3166                     {
 3167                         isIndentableHeader = false;
 3168                         probationHeader = newHeader;
 3169                     }
 3170                 }
 3171                 else if (newHeader == &AS_TEMPLATE)
 3172                 {
 3173                     isInTemplate = true;
 3174                     isIndentableHeader = false;
 3175                 }
 3176 
 3177                 if (isIndentableHeader)
 3178                 {
 3179                     headerStack->emplace_back(newHeader);
 3180                     isContinuation = false;
 3181                     if (indexOf(*nonParenHeaders, newHeader) == -1)
 3182                     {
 3183                         isInConditional = true;
 3184                     }
 3185                     lastLineHeader = newHeader;
 3186                 }
 3187                 else
 3188                     isInHeader = false;
 3189 
 3190                 i += newHeader->length() - 1;
 3191 
 3192                 continue;
 3193             }  // newHeader != nullptr
 3194 
 3195             if (findHeader(line, i, preCommandHeaders) != nullptr)
 3196                 // must be after function arguments
 3197                 if (prevNonSpaceCh == ')')
 3198                     foundPreCommandHeader = true;
 3199 
 3200             // Objective-C NSException macros are preCommandHeaders
 3201             if (isCStyle() && findKeyword(line, i, AS_NS_DURING))
 3202                 foundPreCommandMacro = true;
 3203             if (isCStyle() && findKeyword(line, i, AS_NS_HANDLER))
 3204                 foundPreCommandMacro = true;
 3205 
 3206             if (parenDepth == 0 && findKeyword(line, i, AS_ENUM))
 3207                 isInEnum = true;
 3208 
 3209             if (isSharpStyle() && findKeyword(line, i, AS_LET))
 3210                 isInLet = true;
 3211 
 3212         }   // isPotentialHeader
 3213 
 3214         if (ch == '?')
 3215             isInQuestion = true;
 3216 
 3217         // special handling of colons
 3218         if (ch == ':')
 3219         {
 3220             if (line.length() > i + 1 && line[i + 1] == ':') // look for ::
 3221             {
 3222                 ++i;
 3223                 continue;
 3224             }
 3225             else if (isInQuestion)
 3226             {
 3227                 // do nothing special
 3228             }
 3229             else if (parenDepth > 0)
 3230             {
 3231                 // found a 'for' loop or an objective-C statement
 3232                 // so do nothing special
 3233             }
 3234             else if (isInEnum)
 3235             {
 3236                 // found an enum with a base-type
 3237                 isInEnumTypeID = true;
 3238                 if (i == 0)
 3239                     indentCount += classInitializerIndents;
 3240             }
 3241             else if ((isCStyle() || isSharpStyle())
 3242                      && !isInCase
 3243                      && (prevNonSpaceCh == ')' || foundPreCommandHeader))
 3244             {
 3245                 // found a 'class' c'tor initializer
 3246                 isInClassInitializer = true;
 3247                 registerContinuationIndentColon(line, i, tabIncrementIn);
 3248                 if (i == 0)
 3249                     indentCount += classInitializerIndents;
 3250             }
 3251             else if (isInClassHeader || isInObjCInterface)
 3252             {
 3253                 // is in a 'class A : public B' definition
 3254                 isInClassHeaderTab = true;
 3255                 registerContinuationIndentColon(line, i, tabIncrementIn);
 3256             }
 3257             else if (isInAsm || isInAsmOneLine || isInAsmBlock)
 3258             {
 3259                 // do nothing special
 3260             }
 3261             else if (isDigit(peekNextChar(line, i)))
 3262             {
 3263                 // found a bit field - do nothing special
 3264             }
 3265             else if (isCStyle() && isInClass && prevNonSpaceCh != ')')
 3266             {
 3267                 // found a 'private:' or 'public:' inside a class definition
 3268                 --indentCount;
 3269                 if (modifierIndent)
 3270                     spaceIndentCount += (indentLength / 2);
 3271             }
 3272             else if (isCStyle() && !isInClass
 3273                      && headerStack->size() >= 2
 3274                      && (*headerStack)[headerStack->size() - 2] == &AS_CLASS
 3275                      && (*headerStack)[headerStack->size() - 1] == &AS_OPEN_BRACE)
 3276             {
 3277                 // found a 'private:' or 'public:' inside a class definition
 3278                 // and on the same line as the class opening brace
 3279                 // do nothing
 3280             }
 3281             else if (isJavaStyle() && lastLineHeader == &AS_FOR)
 3282             {
 3283                 // found a java for-each statement
 3284                 // so do nothing special
 3285             }
 3286             else
 3287             {
 3288                 currentNonSpaceCh = ';'; // so that braces after the ':' will appear as block-openers
 3289                 char peekedChar = peekNextChar(line, i);
 3290                 if (isInCase)
 3291                 {
 3292                     isInCase = false;
 3293                     ch = ';'; // from here on, treat char as ';'
 3294                 }
 3295                 else if (isCStyle() || (isSharpStyle() && peekedChar == ';'))
 3296                 {
 3297                     // is in a label (e.g. 'label1:')
 3298                     if (labelIndent)
 3299                         --indentCount; // unindent label by one indent
 3300                     else if (!lineBeginsWithOpenBrace)
 3301                         indentCount = 0; // completely flush indent to left
 3302                 }
 3303             }
 3304         }
 3305 
 3306         if ((ch == ';' || (parenDepth > 0 && ch == ',')) && !continuationIndentStackSizeStack->empty())
 3307             while ((int) continuationIndentStackSizeStack->back() + (parenDepth > 0 ? 1 : 0)
 3308                     < (int) continuationIndentStack->size())
 3309                 continuationIndentStack->pop_back();
 3310 
 3311         else if (ch == ',' && isInEnum && isNonInStatementArray && !continuationIndentStack->empty())
 3312             continuationIndentStack->pop_back();
 3313 
 3314         // handle commas
 3315         // previous "isInStatement" will be from an assignment operator or class initializer
 3316         if (ch == ',' && parenDepth == 0 && !isContinuation && !isNonInStatementArray)
 3317         {
 3318             // is comma at end of line
 3319             size_t nextChar = line.find_first_not_of(" \t", i + 1);
 3320             if (nextChar != string::npos)
 3321             {
 3322                 if (line.compare(nextChar, 2, "//") == 0
 3323                         || line.compare(nextChar, 2, "/*") == 0)
 3324                     nextChar = string::npos;
 3325             }
 3326             // register indent
 3327             if (nextChar == string::npos)
 3328             {
 3329                 // register indent at previous word
 3330                 if (isJavaStyle() && isInClassHeader)
 3331                 {
 3332                     // do nothing for now
 3333                 }
 3334                 // register indent at second word on the line
 3335                 else if (!isInTemplate && !isInClassHeaderTab && !isInClassInitializer)
 3336                 {
 3337                     int prevWord = getContinuationIndentComma(line, i);
 3338                     int continuationIndentCount = prevWord + spaceIndentCount + tabIncrementIn;
 3339                     continuationIndentStack->emplace_back(continuationIndentCount);
 3340                     isContinuation = true;
 3341                 }
 3342             }
 3343         }
 3344         // handle comma first initializers
 3345         if (ch == ',' && parenDepth == 0 && lineBeginsWithComma
 3346                 && (isInClassInitializer || isInClassHeaderTab))
 3347             spaceIndentCount = 0;
 3348 
 3349         // handle ends of statements
 3350         if ((ch == ';' && parenDepth == 0) || ch == '}')
 3351         {
 3352             if (ch == '}')
 3353             {
 3354                 // first check if this '}' closes a previous block, or a static array...
 3355                 if (braceBlockStateStack->size() > 1)
 3356                 {
 3357                     bool braceBlockState = braceBlockStateStack->back();
 3358                     braceBlockStateStack->pop_back();
 3359                     if (!braceBlockState)
 3360                     {
 3361                         if (!continuationIndentStackSizeStack->empty())
 3362                         {
 3363                             // this brace is a static array
 3364                             popLastContinuationIndent();
 3365                             parenDepth--;
 3366                             if (i == 0)
 3367                                 shouldIndentBracedLine = false;
 3368 
 3369                             if (!parenIndentStack->empty())
 3370                             {
 3371                                 int poppedIndent = parenIndentStack->back();
 3372                                 parenIndentStack->pop_back();
 3373                                 if (i == 0)
 3374                                     spaceIndentCount = poppedIndent;
 3375                             }
 3376                         }
 3377                         continue;
 3378                     }
 3379                 }
 3380 
 3381                 // this brace is block closer...
 3382 
 3383                 ++lineClosingBlocksNum;
 3384 
 3385                 if (!continuationIndentStackSizeStack->empty())
 3386                     popLastContinuationIndent();
 3387 
 3388                 if (!parenDepthStack->empty())
 3389                 {
 3390                     parenDepth = parenDepthStack->back();
 3391                     parenDepthStack->pop_back();
 3392                     isContinuation = blockStatementStack->back();
 3393                     blockStatementStack->pop_back();
 3394 
 3395                     if (isContinuation)
 3396                         blockTabCount--;
 3397                 }
 3398 
 3399                 closingBraceReached = true;
 3400                 if (i == 0)
 3401                     spaceIndentCount = 0;
 3402                 isInAsmBlock = false;
 3403                 isInAsm = isInAsmOneLine = isInQuote = false;   // close these just in case
 3404 
 3405                 int headerPlace = indexOf(*headerStack, &AS_OPEN_BRACE);
 3406                 if (headerPlace != -1)
 3407                 {
 3408                     const string* popped = headerStack->back();
 3409                     while (popped != &AS_OPEN_BRACE)
 3410                     {
 3411                         headerStack->pop_back();
 3412                         popped = headerStack->back();
 3413                     }
 3414                     headerStack->pop_back();
 3415 
 3416                     if (headerStack->empty())
 3417                         g_preprocessorCppExternCBrace = 0;
 3418 
 3419                     // do not indent namespace brace unless namespaces are indented
 3420                     if (!namespaceIndent && !headerStack->empty()
 3421                             && ((*headerStack).back() == &AS_NAMESPACE
 3422                                 || (*headerStack).back() == &AS_MODULE)
 3423                             && i == 0)      // must be the first brace on the line
 3424                         shouldIndentBracedLine = false;
 3425 
 3426                     if (!tempStacks->empty())
 3427                     {
 3428                         vector<const string*>* temp = tempStacks->back();
 3429                         tempStacks->pop_back();
 3430                         delete temp;
 3431                     }
 3432                 }
 3433 
 3434                 ch = ' '; // needed due to cases such as '}else{', so that headers ('else' in this case) will be identified...
 3435             }   // ch == '}'
 3436 
 3437             /*
 3438              * Create a temporary snapshot of the current block's header-list in the
 3439              * uppermost inner stack in tempStacks, and clear the headerStack up to
 3440              * the beginning of the block.
 3441              * Thus, the next future statement will think it comes one indent past
 3442              * the block's '{' unless it specifically checks for a companion-header
 3443              * (such as a previous 'if' for an 'else' header) within the tempStacks,
 3444              * and recreates the temporary snapshot by manipulating the tempStacks.
 3445              */
 3446             if (!tempStacks->back()->empty())
 3447                 while (!tempStacks->back()->empty())
 3448                     tempStacks->back()->pop_back();
 3449             while (!headerStack->empty() && headerStack->back() != &AS_OPEN_BRACE)
 3450             {
 3451                 tempStacks->back()->emplace_back(headerStack->back());
 3452                 headerStack->pop_back();
 3453             }
 3454 
 3455             if (parenDepth == 0 && ch == ';')
 3456             {
 3457                 isContinuation = false;
 3458                 isInClassInitializer = false;
 3459             }
 3460 
 3461             if (isInObjCMethodDefinition)
 3462             {
 3463                 objCColonAlignSubsequent = 0;
 3464                 isImmediatelyPostObjCMethodDefinition = true;
 3465             }
 3466 
 3467             previousLastLineHeader = nullptr;
 3468             isInClassHeader = false;        // for 'friend' class
 3469             isInEnum = false;
 3470             isInEnumTypeID = false;
 3471             isInQuestion = false;
 3472             isInTemplate = false;
 3473             isInObjCInterface = false;
 3474             foundPreCommandHeader = false;
 3475             foundPreCommandMacro = false;
 3476             squareBracketCount = 0;
 3477 
 3478             continue;
 3479         }
 3480 
 3481         if (isPotentialHeader)
 3482         {
 3483             // check for preBlockStatements in C/C++ ONLY if not within parentheses
 3484             // (otherwise 'struct XXX' statements would be wrongly interpreted...)
 3485             if (!isInTemplate && !(isCStyle() && parenDepth > 0))
 3486             {
 3487                 const string* newHeader = findHeader(line, i, preBlockStatements);
 3488                 // CORBA IDL module
 3489                 if (newHeader == &AS_MODULE)
 3490                 {
 3491                     char nextChar = peekNextChar(line, i + newHeader->length() - 1);
 3492                     if (prevNonSpaceCh == ')' || !isalpha(nextChar))
 3493                         newHeader = nullptr;
 3494                 }
 3495                 if (newHeader != nullptr
 3496                         && !(isCStyle() && newHeader == &AS_CLASS && isInEnum)  // is not 'enum class'
 3497                         && !(isCStyle() && newHeader == &AS_INTERFACE           // CORBA IDL interface
 3498                              && (headerStack->empty()
 3499                                  || headerStack->back() != &AS_OPEN_BRACE)))
 3500                 {
 3501                     if (!isSharpStyle())
 3502                         headerStack->emplace_back(newHeader);
 3503                     // do not need 'where' in the headerStack
 3504                     // do not need second 'class' statement in a row
 3505                     else if (!(newHeader == &AS_WHERE
 3506                                || ((newHeader == &AS_CLASS || newHeader == &AS_STRUCT)
 3507                                    && !headerStack->empty()
 3508                                    && (headerStack->back() == &AS_CLASS
 3509                                        || headerStack->back() == &AS_STRUCT))))
 3510                         headerStack->emplace_back(newHeader);
 3511 
 3512                     if (!headerStack->empty())
 3513                     {
 3514                         if ((*headerStack).back() == &AS_CLASS
 3515                                 || (*headerStack).back() == &AS_STRUCT
 3516                                 || (*headerStack).back() == &AS_INTERFACE)
 3517                         {
 3518                             isInClassHeader = true;
 3519                         }
 3520                         else if ((*headerStack).back() == &AS_NAMESPACE
 3521                                  || (*headerStack).back() == &AS_MODULE)
 3522                         {
 3523                             // remove continuationIndent from namespace
 3524                             if (!continuationIndentStack->empty())
 3525                                 continuationIndentStack->pop_back();
 3526                             isContinuation = false;
 3527                         }
 3528                     }
 3529 
 3530                     i += newHeader->length() - 1;
 3531                     continue;
 3532                 }
 3533             }
 3534             const string* foundIndentableHeader = findHeader(line, i, indentableHeaders);
 3535 
 3536             if (foundIndentableHeader != nullptr)
 3537             {
 3538                 // must bypass the header before registering the in statement
 3539                 i += foundIndentableHeader->length() - 1;
 3540                 if (!isInOperator && !isInTemplate && !isNonInStatementArray)
 3541                 {
 3542                     registerContinuationIndent(line, i, spaceIndentCount, tabIncrementIn, 0, false);
 3543                     isContinuation = true;
 3544                 }
 3545                 continue;
 3546             }
 3547 
 3548             if (isCStyle() && findKeyword(line, i, AS_OPERATOR))
 3549                 isInOperator = true;
 3550 
 3551             if (g_preprocessorCppExternCBrace == 1 && findKeyword(line, i, AS_EXTERN))
 3552                 ++g_preprocessorCppExternCBrace;
 3553 
 3554             if (g_preprocessorCppExternCBrace == 3) // extern "C" is not followed by a '{'
 3555                 g_preprocessorCppExternCBrace = 0;
 3556 
 3557             // "new" operator is a pointer, not a calculation
 3558             if (findKeyword(line, i, AS_NEW))
 3559             {
 3560                 if (isContinuation && !continuationIndentStack->empty() && prevNonSpaceCh == '=')
 3561                     continuationIndentStack->back() = 0;
 3562             }
 3563 
 3564             if (isCStyle() && findKeyword(line, i, AS_AUTO) && isTopLevel())
 3565             {
 3566                 isInTrailingReturnType = true;
 3567             }
 3568 
 3569             if (isCStyle())
 3570             {
 3571                 if (findKeyword(line, i, AS_ASM)
 3572                         || findKeyword(line, i, AS__ASM__))
 3573                 {
 3574                     isInAsm = true;
 3575                 }
 3576                 else if (findKeyword(line, i, AS_MS_ASM)        // microsoft specific
 3577                          || findKeyword(line, i, AS_MS__ASM))
 3578                 {
 3579                     int index = 4;
 3580                     if (peekNextChar(line, i) == '_')       // check for __asm
 3581                         index = 5;
 3582 
 3583                     char peekedChar = peekNextChar(line, i + index);
 3584                     if (peekedChar == '{' || peekedChar == ' ')
 3585                         isInAsmBlock = true;
 3586                     else
 3587                         isInAsmOneLine = true;
 3588                 }
 3589             }
 3590 
 3591             // bypass the entire name for all others
 3592             string name = getCurrentWord(line, i);
 3593             i += name.length() - 1;
 3594             continue;
 3595         }
 3596 
 3597         // Handle Objective-C statements
 3598 
 3599         if (ch == '@'
 3600                 && line.length() > i + 1
 3601                 && !isWhiteSpace(line[i + 1])
 3602                 && isCharPotentialHeader(line, i + 1))
 3603         {
 3604             string curWord = getCurrentWord(line, i + 1);
 3605             if (curWord == AS_INTERFACE || curWord == AS_AUTORELEASEPOOL)
 3606             {
 3607                 isInObjCInterface = true;
 3608                 string name = '@' + curWord;
 3609                 i += name.length() - 1;
 3610                 continue;
 3611             }
 3612             else if (isInObjCInterface)
 3613             {
 3614                 --indentCount;
 3615                 isInObjCInterface = false;
 3616             }
 3617 
 3618             if (curWord == AS_PUBLIC
 3619                     || curWord == AS_PRIVATE
 3620                     || curWord == AS_PROTECTED)
 3621             {
 3622                 --indentCount;
 3623                 if (modifierIndent)
 3624                     spaceIndentCount += (indentLength / 2);
 3625                 string name = '@' + curWord;
 3626                 i += name.length() - 1;
 3627                 continue;
 3628             }
 3629             else if (curWord == AS_END)
 3630             {
 3631                 popLastContinuationIndent();
 3632                 spaceIndentCount = 0;
 3633                 isInObjCMethodDefinition = false;
 3634                 string name = '@' + curWord;
 3635                 i += name.length() - 1;
 3636                 continue;
 3637             }
 3638         }
 3639         else if ((ch == '-' || ch == '+')
 3640                  && (prevNonSpaceCh == ';' || prevNonSpaceCh == '{'
 3641                      || headerStack->empty() || isInObjCInterface)
 3642                  && ASBase::peekNextChar(line, i) != '-'
 3643                  && ASBase::peekNextChar(line, i) != '+'
 3644                  && line.find_first_not_of(" \t") == i)
 3645         {
 3646             if (isInObjCInterface)
 3647                 --indentCount;
 3648             isInObjCInterface = false;
 3649             isInObjCMethodDefinition = true;
 3650             continue;
 3651         }
 3652 
 3653         // Handle operators
 3654 
 3655         bool isPotentialOperator = isCharPotentialOperator(ch);
 3656 
 3657         if (isPotentialOperator)
 3658         {
 3659             // Check if an operator has been reached.
 3660             const string* foundAssignmentOp = findOperator(line, i, assignmentOperators);
 3661             const string* foundNonAssignmentOp = findOperator(line, i, nonAssignmentOperators);
 3662 
 3663             if (foundNonAssignmentOp != nullptr)
 3664             {
 3665                 if (foundNonAssignmentOp == &AS_LAMBDA)
 3666                     foundPreCommandHeader = true;
 3667                 if (isInTemplate && foundNonAssignmentOp == &AS_GR_GR)
 3668                     foundNonAssignmentOp = nullptr;
 3669             }
 3670 
 3671             // Since findHeader's boundary checking was not used above, it is possible
 3672             // that both an assignment op and a non-assignment op where found,
 3673             // e.g. '>>' and '>>='. If this is the case, treat the LONGER one as the
 3674             // found operator.
 3675             if (foundAssignmentOp != nullptr && foundNonAssignmentOp != nullptr)
 3676             {
 3677                 if (foundAssignmentOp->length() < foundNonAssignmentOp->length())
 3678                     foundAssignmentOp = nullptr;
 3679                 else
 3680                     foundNonAssignmentOp = nullptr;
 3681             }
 3682 
 3683             if (foundNonAssignmentOp != nullptr)
 3684             {
 3685                 if (foundNonAssignmentOp->length() > 1)
 3686                     i += foundNonAssignmentOp->length() - 1;
 3687 
 3688                 // For C++ input/output, operator<< and >> should be
 3689                 // aligned, if we are not in a statement already and
 3690                 // also not in the "operator<<(...)" header line
 3691                 if (!isInOperator
 3692                         && continuationIndentStack->empty()
 3693                         && isCStyle()
 3694                         && (foundNonAssignmentOp == &AS_GR_GR
 3695                             || foundNonAssignmentOp == &AS_LS_LS))
 3696                 {
 3697                     // this will be true if the line begins with the operator
 3698                     if (i < foundNonAssignmentOp->length() && spaceIndentCount == 0)
 3699                         spaceIndentCount += 2 * indentLength;
 3700                     // align to the beginning column of the operator
 3701                     registerContinuationIndent(line, i - foundNonAssignmentOp->length(), spaceIndentCount, tabIncrementIn, 0, false);
 3702                 }
 3703             }
 3704 
 3705             else if (foundAssignmentOp != nullptr)
 3706             {
 3707                 foundPreCommandHeader = false;      // clears this for array assignments
 3708                 foundPreCommandMacro = false;
 3709 
 3710                 if (foundAssignmentOp->length() > 1)
 3711                     i += foundAssignmentOp->length() - 1;
 3712 
 3713                 if (!isInOperator && !isInTemplate && (!isNonInStatementArray || isInEnum))
 3714                 {
 3715                     // if multiple assignments, align on the previous word
 3716                     if (foundAssignmentOp == &AS_ASSIGN
 3717                             && prevNonSpaceCh != ']'        // an array
 3718                             && statementEndsWithComma(line, i))
 3719                     {
 3720                         if (!haveAssignmentThisLine)        // only one assignment indent per line
 3721                         {
 3722                             // register indent at previous word
 3723                             haveAssignmentThisLine = true;
 3724                             int prevWordIndex = getContinuationIndentAssign(line, i);
 3725                             int continuationIndentCount = prevWordIndex + spaceIndentCount + tabIncrementIn;
 3726                             continuationIndentStack->emplace_back(continuationIndentCount);
 3727                             isContinuation = true;
 3728                         }
 3729                     }
 3730                     // don't indent an assignment if 'let'
 3731                     else if (isInLet)
 3732                     {
 3733                         isInLet = false;
 3734                     }
 3735                     else if (!lineBeginsWithComma)
 3736                     {
 3737                         if (i == 0 && spaceIndentCount == 0)
 3738                             spaceIndentCount += indentLength;
 3739                         registerContinuationIndent(line, i, spaceIndentCount, tabIncrementIn, 0, false);
 3740                         isContinuation = true;
 3741                     }
 3742                 }
 3743             }
 3744         }
 3745     }   // end of for loop * end of for loop * end of for loop * end of for loop * end of for loop *
 3746 }
 3747 
 3748 }   // end namespace astyle