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

0001 // ASFormatter.cpp
0002 // Copyright (c) 2018 by Jim Pattee <jimp03@email.com>.
0003 // This code is licensed under the MIT License.
0004 // License.md describes the conditions under which this software may be distributed.
0005 
0006 //-----------------------------------------------------------------------------
0007 // headers
0008 //-----------------------------------------------------------------------------
0009 
0010 #include "astyle.h"
0011 
0012 #include <algorithm>
0013 #include <fstream>
0014 
0015 //-----------------------------------------------------------------------------
0016 // astyle namespace
0017 //-----------------------------------------------------------------------------
0018 
0019 namespace astyle {
0020 //
0021 //-----------------------------------------------------------------------------
0022 // ASFormatter class
0023 //-----------------------------------------------------------------------------
0024 
0025 /**
0026  * Constructor of ASFormatter
0027  */
0028 ASFormatter::ASFormatter()
0029 {
0030     sourceIterator = nullptr;
0031     enhancer = new ASEnhancer;
0032     preBraceHeaderStack = nullptr;
0033     braceTypeStack = nullptr;
0034     parenStack = nullptr;
0035     structStack = nullptr;
0036     questionMarkStack = nullptr;
0037     lineCommentNoIndent = false;
0038     formattingStyle = STYLE_NONE;
0039     braceFormatMode = NONE_MODE;
0040     pointerAlignment = PTR_ALIGN_NONE;
0041     referenceAlignment = REF_SAME_AS_PTR;
0042     objCColonPadMode = COLON_PAD_NO_CHANGE;
0043     lineEnd = LINEEND_DEFAULT;
0044     maxCodeLength = string::npos;
0045     shouldPadCommas = false;
0046     shouldPadOperators = false;
0047     shouldPadParensOutside = false;
0048     shouldPadFirstParen = false;
0049     shouldPadParensInside = false;
0050     shouldPadHeader = false;
0051     shouldStripCommentPrefix = false;
0052     shouldUnPadParens = false;
0053     attachClosingBraceMode = false;
0054     shouldBreakOneLineBlocks = true;
0055     shouldBreakOneLineHeaders = false;
0056     shouldBreakOneLineStatements = true;
0057     shouldConvertTabs = false;
0058     shouldIndentCol1Comments = false;
0059     shouldIndentPreprocBlock = false;
0060     shouldCloseTemplates = false;
0061     shouldAttachExternC = false;
0062     shouldAttachNamespace = false;
0063     shouldAttachClass = false;
0064     shouldAttachClosingWhile = false;
0065     shouldAttachInline = false;
0066     shouldBreakBlocks = false;
0067     shouldBreakClosingHeaderBlocks = false;
0068     shouldBreakClosingHeaderBraces = false;
0069     shouldDeleteEmptyLines = false;
0070     shouldBreakReturnType = false;
0071     shouldBreakReturnTypeDecl = false;
0072     shouldAttachReturnType = false;
0073     shouldAttachReturnTypeDecl = false;
0074     shouldBreakElseIfs = false;
0075     shouldBreakLineAfterLogical = false;
0076     shouldAddBraces = false;
0077     shouldAddOneLineBraces = false;
0078     shouldRemoveBraces = false;
0079     shouldPadMethodColon = false;
0080     shouldPadMethodPrefix = false;
0081     shouldUnPadMethodPrefix = false;
0082     shouldPadReturnType = false;
0083     shouldUnPadReturnType = false;
0084     shouldPadParamType = false;
0085     shouldUnPadParamType = false;
0086 
0087     // initialize ASFormatter member vectors
0088     formatterFileType = 9;      // reset to an invalid type
0089     headers = new vector<const string*>;
0090     nonParenHeaders = new vector<const string*>;
0091     preDefinitionHeaders = new vector<const string*>;
0092     preCommandHeaders = new vector<const string*>;
0093     operators = new vector<const string*>;
0094     assignmentOperators = new vector<const string*>;
0095     castOperators = new vector<const string*>;
0096 
0097     // initialize ASEnhancer member vectors
0098     indentableMacros = new vector<const pair<const string, const string>* >;
0099 }
0100 
0101 /**
0102  * Destructor of ASFormatter
0103  */
0104 ASFormatter::~ASFormatter()
0105 {
0106     // delete ASFormatter stack vectors
0107     deleteContainer(preBraceHeaderStack);
0108     deleteContainer(braceTypeStack);
0109     deleteContainer(parenStack);
0110     deleteContainer(structStack);
0111     deleteContainer(questionMarkStack);
0112 
0113     // delete ASFormatter member vectors
0114     formatterFileType = 9;      // reset to an invalid type
0115     delete headers;
0116     delete nonParenHeaders;
0117     delete preDefinitionHeaders;
0118     delete preCommandHeaders;
0119     delete operators;
0120     delete assignmentOperators;
0121     delete castOperators;
0122 
0123     // delete ASEnhancer member vectors
0124     delete indentableMacros;
0125 
0126     // must be done when the ASFormatter object is deleted (not ASBeautifier)
0127     // delete ASBeautifier member vectors
0128     ASBeautifier::deleteBeautifierVectors();
0129 
0130     delete enhancer;
0131 }
0132 
0133 /**
0134  * initialize the ASFormatter.
0135  *
0136  * init() should be called every time a ASFormatter object is to start
0137  * formatting a NEW source file.
0138  * init() receives a pointer to a ASSourceIterator object that will be
0139  * used to iterate through the source code.
0140  *
0141  * @param si        a pointer to the ASSourceIterator or ASStreamIterator object.
0142  */
0143 void ASFormatter::init(ASSourceIterator* si)
0144 {
0145     buildLanguageVectors();
0146     fixOptionVariableConflicts();
0147     ASBeautifier::init(si);
0148     sourceIterator = si;
0149 
0150     enhancer->init(getFileType(),
0151                    getIndentLength(),
0152                    getTabLength(),
0153                    getIndentString() == "\t",
0154                    getForceTabIndentation(),
0155                    getNamespaceIndent(),
0156                    getCaseIndent(),
0157                    shouldIndentPreprocBlock,
0158                    getPreprocDefineIndent(),
0159                    getEmptyLineFill(),
0160                    indentableMacros);
0161 
0162     initContainer(preBraceHeaderStack, new vector<const string*>);
0163     initContainer(parenStack, new vector<int>);
0164     initContainer(structStack, new vector<bool>);
0165     initContainer(questionMarkStack, new vector<bool>);
0166     parenStack->emplace_back(0);               // parenStack must contain this default entry
0167     initContainer(braceTypeStack, new vector<BraceType>);
0168     braceTypeStack->emplace_back(NULL_TYPE);   // braceTypeStack must contain this default entry
0169     clearFormattedLineSplitPoints();
0170 
0171     currentHeader = nullptr;
0172     currentLine = "";
0173     readyFormattedLine = "";
0174     formattedLine = "";
0175     verbatimDelimiter = "";
0176     currentChar = ' ';
0177     previousChar = ' ';
0178     previousCommandChar = ' ';
0179     previousNonWSChar = ',';    // not a potential name or operator
0180     quoteChar = '"';
0181     preprocBlockEnd = 0;
0182     charNum = 0;
0183     checksumIn = 0;
0184     checksumOut = 0;
0185     currentLineFirstBraceNum = string::npos;
0186     formattedLineCommentNum = 0;
0187     leadingSpaces = 0;
0188     previousReadyFormattedLineLength = string::npos;
0189     preprocBraceTypeStackSize = 0;
0190     spacePadNum = 0;
0191     methodAttachCharNum = string::npos;
0192     methodAttachLineNum = 0;
0193     methodBreakCharNum = string::npos;
0194     methodBreakLineNum = 0;
0195     nextLineSpacePadNum = 0;
0196     objCColonAlign = 0;
0197     templateDepth = 0;
0198     squareBracketCount = 0;
0199     runInIndentChars = 0;
0200     tabIncrementIn = 0;
0201     previousBraceType = NULL_TYPE;
0202 
0203     isVirgin = true;
0204     isInVirginLine = true;
0205     isInLineComment = false;
0206     isInComment = false;
0207     isInCommentStartLine = false;
0208     noTrimCommentContinuation = false;
0209     isInPreprocessor = false;
0210     isInPreprocessorBeautify = false;
0211     doesLineStartComment = false;
0212     lineEndsInCommentOnly = false;
0213     lineIsCommentOnly = false;
0214     lineIsLineCommentOnly = false;
0215     lineIsEmpty = false;
0216     isImmediatelyPostCommentOnly = false;
0217     isImmediatelyPostEmptyLine = false;
0218     isInClassInitializer = false;
0219     isInQuote = false;
0220     isInVerbatimQuote = false;
0221     haveLineContinuationChar = false;
0222     isInQuoteContinuation = false;
0223     isHeaderInMultiStatementLine = false;
0224     isSpecialChar = false;
0225     isNonParenHeader = false;
0226     foundNamespaceHeader = false;
0227     foundClassHeader = false;
0228     foundStructHeader = false;
0229     foundInterfaceHeader = false;
0230     foundPreDefinitionHeader = false;
0231     foundPreCommandHeader = false;
0232     foundPreCommandMacro = false;
0233     foundTrailingReturnType = false;
0234     foundCastOperator = false;
0235     foundQuestionMark = false;
0236     isInLineBreak = false;
0237     endOfAsmReached = false;
0238     endOfCodeReached = false;
0239     isFormattingModeOff = false;
0240     isInEnum = false;
0241     isInExecSQL = false;
0242     isInAsm = false;
0243     isInAsmOneLine = false;
0244     isInAsmBlock = false;
0245     isLineReady = false;
0246     elseHeaderFollowsComments = false;
0247     caseHeaderFollowsComments = false;
0248     isPreviousBraceBlockRelated = false;
0249     isInPotentialCalculation = false;
0250     needHeaderOpeningBrace = false;
0251     shouldBreakLineAtNextChar = false;
0252     shouldKeepLineUnbroken = false;
0253     shouldReparseCurrentChar = false;
0254     passedSemicolon = false;
0255     passedColon = false;
0256     isImmediatelyPostNonInStmt = false;
0257     isCharImmediatelyPostNonInStmt = false;
0258     isInTemplate = false;
0259     isImmediatelyPostComment = false;
0260     isImmediatelyPostLineComment = false;
0261     isImmediatelyPostEmptyBlock = false;
0262     isImmediatelyPostObjCMethodPrefix = false;
0263     isImmediatelyPostPreprocessor = false;
0264     isImmediatelyPostReturn = false;
0265     isImmediatelyPostThrow = false;
0266     isImmediatelyPostNewDelete = false;
0267     isImmediatelyPostOperator = false;
0268     isImmediatelyPostTemplate = false;
0269     isImmediatelyPostPointerOrReference = false;
0270     isCharImmediatelyPostReturn = false;
0271     isCharImmediatelyPostThrow = false;
0272     isCharImmediatelyPostNewDelete = false;
0273     isCharImmediatelyPostOperator = false;
0274     isCharImmediatelyPostComment = false;
0275     isPreviousCharPostComment = false;
0276     isCharImmediatelyPostLineComment = false;
0277     isCharImmediatelyPostOpenBlock = false;
0278     isCharImmediatelyPostCloseBlock = false;
0279     isCharImmediatelyPostTemplate = false;
0280     isCharImmediatelyPostPointerOrReference = false;
0281     isInObjCInterface = false;
0282     isInObjCMethodDefinition = false;
0283     isInObjCReturnType = false;
0284     isInObjCParam = false;
0285     isInObjCSelector = false;
0286     breakCurrentOneLineBlock = false;
0287     shouldRemoveNextClosingBrace = false;
0288     isInBraceRunIn = false;
0289     returnTypeChecked = false;
0290     currentLineBeginsWithBrace = false;
0291     isPrependPostBlockEmptyLineRequested = false;
0292     isAppendPostBlockEmptyLineRequested = false;
0293     isIndentableProprocessor = false;
0294     isIndentableProprocessorBlock = false;
0295     prependEmptyLine = false;
0296     appendOpeningBrace = false;
0297     foundClosingHeader = false;
0298     isImmediatelyPostHeader = false;
0299     isInHeader = false;
0300     isInCase = false;
0301     isFirstPreprocConditional = false;
0302     processedFirstConditional = false;
0303     isJavaStaticConstructor = false;
0304 }
0305 
0306 /**
0307  * build vectors for each programing language
0308  * depending on the file extension.
0309  */
0310 void ASFormatter::buildLanguageVectors()
0311 {
0312     if (getFileType() == formatterFileType)  // don't build unless necessary
0313         return;
0314 
0315     formatterFileType = getFileType();
0316 
0317     headers->clear();
0318     nonParenHeaders->clear();
0319     preDefinitionHeaders->clear();
0320     preCommandHeaders->clear();
0321     operators->clear();
0322     assignmentOperators->clear();
0323     castOperators->clear();
0324     indentableMacros->clear();  // ASEnhancer
0325 
0326     ASResource::buildHeaders(headers, getFileType());
0327     ASResource::buildNonParenHeaders(nonParenHeaders, getFileType());
0328     ASResource::buildPreDefinitionHeaders(preDefinitionHeaders, getFileType());
0329     ASResource::buildPreCommandHeaders(preCommandHeaders, getFileType());
0330     ASResource::buildOperators(operators, getFileType());
0331     ASResource::buildAssignmentOperators(assignmentOperators);
0332     ASResource::buildCastOperators(castOperators);
0333     ASResource::buildIndentableMacros(indentableMacros);    //ASEnhancer
0334 }
0335 
0336 /**
0337  * set the variables for each predefined style.
0338  * this will override any previous settings.
0339  */
0340 void ASFormatter::fixOptionVariableConflicts()
0341 {
0342     if (formattingStyle == STYLE_ALLMAN)
0343     {
0344         setBraceFormatMode(BREAK_MODE);
0345     }
0346     else if (formattingStyle == STYLE_JAVA)
0347     {
0348         setBraceFormatMode(ATTACH_MODE);
0349     }
0350     else if (formattingStyle == STYLE_KR)
0351     {
0352         setBraceFormatMode(LINUX_MODE);
0353     }
0354     else if (formattingStyle == STYLE_STROUSTRUP)
0355     {
0356         setBraceFormatMode(LINUX_MODE);
0357         setBreakClosingHeaderBracesMode(true);
0358     }
0359     else if (formattingStyle == STYLE_WHITESMITH)
0360     {
0361         setBraceFormatMode(BREAK_MODE);
0362         setBraceIndent(true);
0363         setClassIndent(true);           // avoid hanging indent with access modifiers
0364         setSwitchIndent(true);          // avoid hanging indent with case statements
0365     }
0366     else if (formattingStyle == STYLE_VTK)
0367     {
0368         // the unindented class brace does NOT cause a hanging indent like Whitesmith
0369         setBraceFormatMode(BREAK_MODE);
0370         setBraceIndentVtk(true);        // sets both braceIndent and braceIndentVtk
0371         setSwitchIndent(true);          // avoid hanging indent with case statements
0372     }
0373     else if (formattingStyle == STYLE_RATLIFF)
0374     {
0375         // attached braces can have hanging indents with the closing brace
0376         setBraceFormatMode(ATTACH_MODE);
0377         setBraceIndent(true);
0378         setClassIndent(true);           // avoid hanging indent with access modifiers
0379         setSwitchIndent(true);          // avoid hanging indent with case statements
0380     }
0381     else if (formattingStyle == STYLE_GNU)
0382     {
0383         setBraceFormatMode(BREAK_MODE);
0384         setBlockIndent(true);
0385     }
0386     else if (formattingStyle == STYLE_LINUX)
0387     {
0388         setBraceFormatMode(LINUX_MODE);
0389         // always for Linux style
0390         setMinConditionalIndentOption(MINCOND_ONEHALF);
0391     }
0392     else if (formattingStyle == STYLE_HORSTMANN)
0393     {
0394         setBraceFormatMode(RUN_IN_MODE);
0395         setSwitchIndent(true);
0396     }
0397     else if (formattingStyle == STYLE_1TBS)
0398     {
0399         setBraceFormatMode(LINUX_MODE);
0400         setAddBracesMode(true);
0401         setRemoveBracesMode(false);
0402     }
0403     else if (formattingStyle == STYLE_GOOGLE)
0404     {
0405         setBraceFormatMode(ATTACH_MODE);
0406         setModifierIndent(true);
0407         setClassIndent(false);
0408     }
0409     else if (formattingStyle == STYLE_MOZILLA)
0410     {
0411         setBraceFormatMode(LINUX_MODE);
0412     }
0413     else if (formattingStyle == STYLE_PICO)
0414     {
0415         setBraceFormatMode(RUN_IN_MODE);
0416         setAttachClosingBraceMode(true);
0417         setSwitchIndent(true);
0418         setBreakOneLineBlocksMode(false);
0419         setBreakOneLineStatementsMode(false);
0420         // add-braces won't work for pico, but it could be fixed if necessary
0421         // both options should be set to true
0422         if (shouldAddBraces)
0423             shouldAddOneLineBraces = true;
0424     }
0425     else if (formattingStyle == STYLE_LISP)
0426     {
0427         setBraceFormatMode(ATTACH_MODE);
0428         setAttachClosingBraceMode(true);
0429         setBreakOneLineStatementsMode(false);
0430         // add-one-line-braces won't work for lisp
0431         // only shouldAddBraces should be set to true
0432         if (shouldAddOneLineBraces)
0433         {
0434             shouldAddBraces = true;
0435             shouldAddOneLineBraces = false;
0436         }
0437     }
0438     setMinConditionalIndentLength();
0439     // if not set by indent=force-tab-x set equal to indentLength
0440     if (getTabLength() == 0)
0441         setDefaultTabLength();
0442     // add-one-line-braces implies keep-one-line-blocks
0443     if (shouldAddOneLineBraces)
0444         setBreakOneLineBlocksMode(false);
0445     // don't allow add-braces and remove-braces
0446     if (shouldAddBraces || shouldAddOneLineBraces)
0447         setRemoveBracesMode(false);
0448     // don't allow break-return-type and attach-return-type
0449     if (shouldBreakReturnType)
0450         shouldAttachReturnType = false;
0451     if (shouldBreakReturnTypeDecl)
0452         shouldAttachReturnTypeDecl = false;
0453     // don't allow indent-classes and indent-modifiers
0454     if (getClassIndent())
0455         setModifierIndent(false);
0456 }
0457 
0458 /**
0459  * get the next formatted line.
0460  *
0461  * @return    formatted line.
0462  */
0463 string ASFormatter::nextLine()
0464 {
0465     const string* newHeader = nullptr;
0466     isInVirginLine = isVirgin;
0467     isCharImmediatelyPostComment = false;
0468     isPreviousCharPostComment = false;
0469     isCharImmediatelyPostLineComment = false;
0470     isCharImmediatelyPostOpenBlock = false;
0471     isCharImmediatelyPostCloseBlock = false;
0472     isCharImmediatelyPostTemplate = false;
0473 
0474     while (!isLineReady)
0475     {
0476         if (shouldReparseCurrentChar)
0477             shouldReparseCurrentChar = false;
0478         else if (!getNextChar())
0479         {
0480             breakLine();
0481             continue;
0482         }
0483         else // stuff to do when reading a new character...
0484         {
0485             // make sure that a virgin '{' at the beginning of the file will be treated as a block...
0486             if (isInVirginLine && currentChar == '{'
0487                     && currentLineBeginsWithBrace
0488                     && previousCommandChar == ' ')
0489                 previousCommandChar = '{';
0490             if (isInClassInitializer
0491                     && isBraceType(braceTypeStack->back(), COMMAND_TYPE))
0492                 isInClassInitializer = false;
0493             if (isInBraceRunIn)
0494                 isInLineBreak = false;
0495             if (!isWhiteSpace(currentChar))
0496                 isInBraceRunIn = false;
0497             isPreviousCharPostComment = isCharImmediatelyPostComment;
0498             isCharImmediatelyPostComment = false;
0499             isCharImmediatelyPostTemplate = false;
0500             isCharImmediatelyPostReturn = false;
0501             isCharImmediatelyPostThrow = false;
0502             isCharImmediatelyPostNewDelete = false;
0503             isCharImmediatelyPostOperator = false;
0504             isCharImmediatelyPostPointerOrReference = false;
0505             isCharImmediatelyPostOpenBlock = false;
0506             isCharImmediatelyPostCloseBlock = false;
0507         }
0508 
0509         if ((lineIsLineCommentOnly || lineIsCommentOnly)
0510                 && currentLine.find("*INDENT-ON*", charNum) != string::npos
0511                 && isFormattingModeOff)
0512         {
0513             isFormattingModeOff = false;
0514             breakLine();
0515             formattedLine = currentLine;
0516             charNum = (int) currentLine.length() - 1;
0517             continue;
0518         }
0519         if (isFormattingModeOff)
0520         {
0521             breakLine();
0522             formattedLine = currentLine;
0523             charNum = (int) currentLine.length() - 1;
0524             continue;
0525         }
0526         if ((lineIsLineCommentOnly || lineIsCommentOnly)
0527                 && currentLine.find("*INDENT-OFF*", charNum) != string::npos)
0528         {
0529             isFormattingModeOff = true;
0530             if (isInLineBreak)          // is true if not the first line
0531                 breakLine();
0532             formattedLine = currentLine;
0533             charNum = (int) currentLine.length() - 1;
0534             continue;
0535         }
0536 
0537         if (shouldBreakLineAtNextChar)
0538         {
0539             if (isWhiteSpace(currentChar) && !lineIsEmpty)
0540                 continue;
0541             isInLineBreak = true;
0542             shouldBreakLineAtNextChar = false;
0543         }
0544 
0545         if (isInExecSQL && !passedSemicolon)
0546         {
0547             if (currentChar == ';')
0548                 passedSemicolon = true;
0549             appendCurrentChar();
0550             continue;
0551         }
0552 
0553         if (isInLineComment)
0554         {
0555             formatLineCommentBody();
0556             continue;
0557         }
0558         else if (isInComment)
0559         {
0560             formatCommentBody();
0561             continue;
0562         }
0563 
0564         else if (isInQuote)
0565         {
0566             formatQuoteBody();
0567             continue;
0568         }
0569 
0570         // not in quote or comment or line comment
0571 
0572         if (isSequenceReached("//"))
0573         {
0574             formatLineCommentOpener();
0575             testForTimeToSplitFormattedLine();
0576             continue;
0577         }
0578         else if (isSequenceReached("/*"))
0579         {
0580             formatCommentOpener();
0581             testForTimeToSplitFormattedLine();
0582             continue;
0583         }
0584         else if (currentChar == '"'
0585                  || (currentChar == '\'' && !isDigitSeparator(currentLine, charNum)))
0586         {
0587             formatQuoteOpener();
0588             testForTimeToSplitFormattedLine();
0589             continue;
0590         }
0591         // treat these preprocessor statements as a line comment
0592         else if (currentChar == '#'
0593                  && currentLine.find_first_not_of(" \t") == (size_t) charNum)
0594         {
0595             string preproc = trim(currentLine.c_str() + charNum + 1);
0596             if (preproc.length() > 0
0597                     && isCharPotentialHeader(preproc, 0)
0598                     && (findKeyword(preproc, 0, "region")
0599                         || findKeyword(preproc, 0, "endregion")
0600                         || findKeyword(preproc, 0, "error")
0601                         || findKeyword(preproc, 0, "warning")
0602                         || findKeyword(preproc, 0, "line")))
0603             {
0604                 currentLine = rtrim(currentLine);   // trim the end only
0605                 // check for run-in
0606                 if (formattedLine.length() > 0 && formattedLine[0] == '{')
0607                 {
0608                     isInLineBreak = true;
0609                     isInBraceRunIn = false;
0610                 }
0611                 if (previousCommandChar == '}')
0612                     currentHeader = nullptr;
0613                 isInLineComment = true;
0614                 appendCurrentChar();
0615                 continue;
0616             }
0617         }
0618 
0619         if (isInPreprocessor)
0620         {
0621             appendCurrentChar();
0622             continue;
0623         }
0624 
0625         if (isInTemplate && shouldCloseTemplates)
0626         {
0627             if (previousNonWSChar == '>' && isWhiteSpace(currentChar) && peekNextChar() == '>')
0628                 continue;
0629         }
0630 
0631         if (shouldRemoveNextClosingBrace && currentChar == '}')
0632         {
0633             currentLine[charNum] = currentChar = ' ';
0634             shouldRemoveNextClosingBrace = false;
0635             assert(adjustChecksumIn(-'}'));
0636             if (isEmptyLine(currentLine))
0637                 continue;
0638         }
0639 
0640         // handle white space - needed to simplify the rest.
0641         if (isWhiteSpace(currentChar))
0642         {
0643             appendCurrentChar();
0644             continue;
0645         }
0646 
0647         /* not in MIDDLE of quote or comment or SQL or white-space of any type ... */
0648 
0649         // check if in preprocessor
0650         // ** isInPreprocessor will be automatically reset at the beginning
0651         //    of a new line in getnextChar()
0652         if (currentChar == '#'
0653                 && currentLine.find_first_not_of(" \t") == (size_t) charNum
0654                 && !isBraceType(braceTypeStack->back(), SINGLE_LINE_TYPE))
0655         {
0656             isInPreprocessor = true;
0657             // check for run-in
0658             if (formattedLine.length() > 0 && formattedLine[0] == '{')
0659             {
0660                 isInLineBreak = true;
0661                 isInBraceRunIn = false;
0662             }
0663             processPreprocessor();
0664             // if top level it is potentially indentable
0665             if (shouldIndentPreprocBlock
0666                     && (isBraceType(braceTypeStack->back(), NULL_TYPE)
0667                         || isBraceType(braceTypeStack->back(), NAMESPACE_TYPE))
0668                     && !foundClassHeader
0669                     && !isInClassInitializer
0670                     && sourceIterator->tellg() > preprocBlockEnd)
0671             {
0672                 // indent the #if preprocessor blocks
0673                 string preproc = ASBeautifier::extractPreprocessorStatement(currentLine);
0674                 if (preproc.length() >= 2 && preproc.substr(0, 2) == "if") // #if, #ifdef, #ifndef
0675                 {
0676                     if (isImmediatelyPostPreprocessor)
0677                         breakLine();
0678                     isIndentableProprocessorBlock = isIndentablePreprocessorBlock(currentLine, charNum);
0679                     isIndentableProprocessor = isIndentableProprocessorBlock;
0680                 }
0681             }
0682             if (isIndentableProprocessorBlock
0683                     && charNum < (int) currentLine.length() - 1
0684                     && isWhiteSpace(currentLine[charNum + 1]))
0685             {
0686                 size_t nextText = currentLine.find_first_not_of(" \t", charNum + 1);
0687                 if (nextText != string::npos)
0688                     currentLine.erase(charNum + 1, nextText - charNum - 1);
0689             }
0690             if (isIndentableProprocessorBlock
0691                     && sourceIterator->tellg() >= preprocBlockEnd)
0692                 isIndentableProprocessorBlock = false;
0693             //  need to fall thru here to reset the variables
0694         }
0695 
0696         /* not in preprocessor ... */
0697 
0698         if (isImmediatelyPostComment)
0699         {
0700             caseHeaderFollowsComments = false;
0701             isImmediatelyPostComment = false;
0702             isCharImmediatelyPostComment = true;
0703         }
0704 
0705         if (isImmediatelyPostLineComment)
0706         {
0707             caseHeaderFollowsComments = false;
0708             isImmediatelyPostLineComment = false;
0709             isCharImmediatelyPostLineComment = true;
0710         }
0711 
0712         if (isImmediatelyPostReturn)
0713         {
0714             isImmediatelyPostReturn = false;
0715             isCharImmediatelyPostReturn = true;
0716         }
0717 
0718         if (isImmediatelyPostThrow)
0719         {
0720             isImmediatelyPostThrow = false;
0721             isCharImmediatelyPostThrow = true;
0722         }
0723 
0724         if (isImmediatelyPostNewDelete)
0725         {
0726             isImmediatelyPostNewDelete = false;
0727             isCharImmediatelyPostNewDelete = true;
0728         }
0729 
0730         if (isImmediatelyPostOperator)
0731         {
0732             isImmediatelyPostOperator = false;
0733             isCharImmediatelyPostOperator = true;
0734         }
0735         if (isImmediatelyPostTemplate)
0736         {
0737             isImmediatelyPostTemplate = false;
0738             isCharImmediatelyPostTemplate = true;
0739         }
0740         if (isImmediatelyPostPointerOrReference)
0741         {
0742             isImmediatelyPostPointerOrReference = false;
0743             isCharImmediatelyPostPointerOrReference = true;
0744         }
0745 
0746         // reset isImmediatelyPostHeader information
0747         if (isImmediatelyPostHeader)
0748         {
0749             // should braces be added
0750             if (currentChar != '{'
0751                     && shouldAddBraces
0752                     && currentChar != '#'   // don't add to preprocessor
0753                     && (shouldBreakOneLineStatements || !isHeaderInMultiStatementLine)
0754                     && isOkToBreakBlock(braceTypeStack->back()))
0755             {
0756                 bool bracesAdded = addBracesToStatement();
0757                 if (bracesAdded && !shouldAddOneLineBraces)
0758                 {
0759                     size_t firstText = currentLine.find_first_not_of(" \t");
0760                     assert(firstText != string::npos);
0761                     if ((int) firstText == charNum || shouldBreakOneLineHeaders)
0762                         breakCurrentOneLineBlock = true;
0763                 }
0764             }
0765             // should braces be removed
0766             else if (currentChar == '{' && shouldRemoveBraces)
0767             {
0768                 bool bracesRemoved = removeBracesFromStatement();
0769                 if (bracesRemoved)
0770                 {
0771                     shouldRemoveNextClosingBrace = true;
0772                     if (isBeforeAnyLineEndComment(charNum))
0773                         spacePadNum--;
0774                     else if (shouldBreakOneLineBlocks
0775                              || (currentLineBeginsWithBrace
0776                                  && currentLine.find_first_not_of(" \t") != string::npos))
0777                         shouldBreakLineAtNextChar = true;
0778                     continue;
0779                 }
0780             }
0781 
0782             // break 'else-if' if shouldBreakElseIfs is requested
0783             if (shouldBreakElseIfs
0784                     && currentHeader == &AS_ELSE
0785                     && isOkToBreakBlock(braceTypeStack->back())
0786                     && !isBeforeAnyComment()
0787                     && (shouldBreakOneLineStatements || !isHeaderInMultiStatementLine))
0788             {
0789                 string nextText = peekNextText(currentLine.substr(charNum));
0790                 if (nextText.length() > 0
0791                         && isCharPotentialHeader(nextText, 0)
0792                         && ASBase::findHeader(nextText, 0, headers) == &AS_IF)
0793                 {
0794                     isInLineBreak = true;
0795                 }
0796             }
0797 
0798             // break a header (e.g. if, while, else) from the following statement
0799             if (shouldBreakOneLineHeaders
0800                     && peekNextChar() != ' '
0801                     && (shouldBreakOneLineStatements
0802                         || (!isHeaderInMultiStatementLine
0803                             && !isMultiStatementLine()))
0804                     && isOkToBreakBlock(braceTypeStack->back())
0805                     && !isBeforeAnyComment())
0806             {
0807                 if (currentChar == '{')
0808                 {
0809                     if (!currentLineBeginsWithBrace)
0810                     {
0811                         if (isOneLineBlockReached(currentLine, charNum) == 3)
0812                             isInLineBreak = false;
0813                         else
0814                             breakCurrentOneLineBlock = true;
0815                     }
0816                 }
0817                 else if (currentHeader == &AS_ELSE)
0818                 {
0819                     string nextText = peekNextText(currentLine.substr(charNum), true);
0820                     if (nextText.length() > 0
0821                             && ((isCharPotentialHeader(nextText, 0)
0822                                  && ASBase::findHeader(nextText, 0, headers) != &AS_IF)
0823                                 || nextText[0] == '{'))
0824                         isInLineBreak = true;
0825                 }
0826                 else
0827                 {
0828                     isInLineBreak = true;
0829                 }
0830             }
0831 
0832             isImmediatelyPostHeader = false;
0833         }
0834 
0835         if (passedSemicolon)    // need to break the formattedLine
0836         {
0837             passedSemicolon = false;
0838             if (parenStack->back() == 0 && !isCharImmediatelyPostComment && currentChar != ';') // allow ;;
0839             {
0840                 // does a one-line block have ending comments?
0841                 if (isBraceType(braceTypeStack->back(), SINGLE_LINE_TYPE))
0842                 {
0843                     size_t blockEnd = currentLine.rfind(AS_CLOSE_BRACE);
0844                     assert(blockEnd != string::npos);
0845                     // move ending comments to this formattedLine
0846                     if (isBeforeAnyLineEndComment(blockEnd))
0847                     {
0848                         size_t commentStart = currentLine.find_first_not_of(" \t", blockEnd + 1);
0849                         assert(commentStart != string::npos);
0850                         assert((currentLine.compare(commentStart, 2, "//") == 0)
0851                                || (currentLine.compare(commentStart, 2, "/*") == 0));
0852                         formattedLine.append(getIndentLength() - 1, ' ');
0853                         // append comment
0854                         int charNumSave = charNum;
0855                         charNum = commentStart;
0856                         while (charNum < (int) currentLine.length())
0857                         {
0858                             currentChar = currentLine[charNum];
0859                             if (currentChar == '\t' && shouldConvertTabs)
0860                                 convertTabToSpaces();
0861                             formattedLine.append(1, currentChar);
0862                             ++charNum;
0863                         }
0864                         size_t commentLength = currentLine.length() - commentStart;
0865                         currentLine.erase(commentStart, commentLength);
0866                         charNum = charNumSave;
0867                         currentChar = currentLine[charNum];
0868                         testForTimeToSplitFormattedLine();
0869                     }
0870                 }
0871                 isInExecSQL = false;
0872                 shouldReparseCurrentChar = true;
0873                 if (formattedLine.find_first_not_of(" \t") != string::npos)
0874                     isInLineBreak = true;
0875                 if (needHeaderOpeningBrace)
0876                 {
0877                     isCharImmediatelyPostCloseBlock = true;
0878                     needHeaderOpeningBrace = false;
0879                 }
0880                 continue;
0881             }
0882         }
0883 
0884         if (passedColon)
0885         {
0886             passedColon = false;
0887             if (parenStack->back() == 0
0888                     && !isBeforeAnyComment()
0889                     && (formattedLine.find_first_not_of(" \t") != string::npos))
0890             {
0891                 shouldReparseCurrentChar = true;
0892                 isInLineBreak = true;
0893                 continue;
0894             }
0895         }
0896 
0897         // Check if in template declaration, e.g. foo<bar> or foo<bar,fig>
0898         if (!isInTemplate && currentChar == '<')
0899         {
0900             checkIfTemplateOpener();
0901         }
0902 
0903         // Check for break return type
0904         if ((size_t) charNum >= methodBreakCharNum && methodBreakLineNum == 0)
0905         {
0906             if ((size_t) charNum == methodBreakCharNum)
0907                 isInLineBreak = true;
0908             methodBreakCharNum = string::npos;
0909             methodBreakLineNum = 0;
0910         }
0911         // Check for attach return type
0912         if ((size_t) charNum >= methodAttachCharNum && methodAttachLineNum == 0)
0913         {
0914             if ((size_t) charNum == methodAttachCharNum)
0915             {
0916                 int pa = pointerAlignment;
0917                 int ra = referenceAlignment;
0918                 int itemAlignment = (previousNonWSChar == '*' || previousNonWSChar == '^')
0919                                     ? pa : ((ra == REF_SAME_AS_PTR) ? pa : ra);
0920                 isInLineBreak = false;
0921                 if (previousNonWSChar == '*' || previousNonWSChar == '&' || previousNonWSChar == '^')
0922                 {
0923                     if (itemAlignment == REF_ALIGN_TYPE)
0924                     {
0925                         if (formattedLine.length() > 0
0926                                 && !isWhiteSpace(formattedLine[formattedLine.length() - 1]))
0927                             formattedLine.append(1, ' ');
0928                     }
0929                     else if (itemAlignment == REF_ALIGN_MIDDLE)
0930                     {
0931                         if (formattedLine.length() > 0
0932                                 && !isWhiteSpace(formattedLine[formattedLine.length() - 1]))
0933                             formattedLine.append(1, ' ');
0934                     }
0935                     else if (itemAlignment == REF_ALIGN_NAME)
0936                     {
0937                         if (formattedLine.length() > 0
0938                                 && isWhiteSpace(formattedLine[formattedLine.length() - 1]))
0939                             formattedLine.erase(formattedLine.length() - 1);
0940                     }
0941                     else
0942                     {
0943                         if (formattedLine.length() > 1
0944                                 && !isWhiteSpace(formattedLine[formattedLine.length() - 2]))
0945                             formattedLine.append(1, ' ');
0946                     }
0947                 }
0948                 else
0949                     formattedLine.append(1, ' ');
0950             }
0951             methodAttachCharNum = string::npos;
0952             methodAttachLineNum = 0;
0953         }
0954 
0955         // handle parens
0956         if (currentChar == '(' || currentChar == '[' || (isInTemplate && currentChar == '<'))
0957         {
0958             questionMarkStack->push_back(foundQuestionMark);
0959             foundQuestionMark = false;
0960             parenStack->back()++;
0961             if (currentChar == '[')
0962             {
0963                 ++squareBracketCount;
0964                 if (getAlignMethodColon() && squareBracketCount == 1 && isCStyle())
0965                     objCColonAlign = findObjCColonAlignment();
0966             }
0967         }
0968         else if (currentChar == ')' || currentChar == ']' || (isInTemplate && currentChar == '>'))
0969         {
0970             foundPreCommandHeader = false;
0971             parenStack->back()--;
0972             // this can happen in preprocessor directives
0973             if (parenStack->back() < 0)
0974                 parenStack->back() = 0;
0975             if (!questionMarkStack->empty())
0976             {
0977                 foundQuestionMark = questionMarkStack->back();
0978                 questionMarkStack->pop_back();
0979             }
0980             if (isInTemplate && currentChar == '>')
0981             {
0982                 templateDepth--;
0983                 if (templateDepth == 0)
0984                 {
0985                     isInTemplate = false;
0986                     isImmediatelyPostTemplate = true;
0987                 }
0988             }
0989 
0990             // check if this parenthesis closes a header, e.g. if (...), while (...)
0991             if (isInHeader && parenStack->back() == 0)
0992             {
0993                 isInHeader = false;
0994                 isImmediatelyPostHeader = true;
0995                 foundQuestionMark = false;
0996             }
0997             if (currentChar == ']')
0998             {
0999                 --squareBracketCount;
1000                 if (squareBracketCount <= 0)
1001                 {
1002                     squareBracketCount = 0;
1003                     objCColonAlign = 0;
1004                 }
1005             }
1006             if (currentChar == ')')
1007             {
1008                 foundCastOperator = false;
1009                 if (parenStack->back() == 0)
1010                     endOfAsmReached = true;
1011             }
1012         }
1013 
1014         // handle braces
1015         if (currentChar == '{' || currentChar == '}')
1016         {
1017             // if appendOpeningBrace this was already done for the original brace
1018             if (currentChar == '{' && !appendOpeningBrace)
1019             {
1020                 BraceType newBraceType = getBraceType();
1021                 breakCurrentOneLineBlock = false;
1022                 foundNamespaceHeader = false;
1023                 foundClassHeader = false;
1024                 foundStructHeader = false;
1025                 foundInterfaceHeader = false;
1026                 foundPreDefinitionHeader = false;
1027                 foundPreCommandHeader = false;
1028                 foundPreCommandMacro = false;
1029                 foundTrailingReturnType = false;
1030                 isInPotentialCalculation = false;
1031                 isInObjCMethodDefinition = false;
1032                 isImmediatelyPostObjCMethodPrefix = false;
1033                 isInObjCInterface = false;
1034                 isInEnum = false;
1035                 isJavaStaticConstructor = false;
1036                 isCharImmediatelyPostNonInStmt = false;
1037                 needHeaderOpeningBrace = false;
1038                 shouldKeepLineUnbroken = false;
1039                 returnTypeChecked = false;
1040                 objCColonAlign = 0;
1041                 //assert(methodBreakCharNum == string::npos);   // comment out
1042                 //assert(methodBreakLineNum == 0);              // comment out
1043                 methodBreakCharNum = string::npos;
1044                 methodBreakLineNum = 0;
1045                 methodAttachCharNum = string::npos;
1046                 methodAttachLineNum = 0;
1047 
1048                 isPreviousBraceBlockRelated = !isBraceType(newBraceType, ARRAY_TYPE);
1049                 braceTypeStack->emplace_back(newBraceType);
1050                 preBraceHeaderStack->emplace_back(currentHeader);
1051                 currentHeader = nullptr;
1052                 structStack->push_back(isInIndentableStruct);
1053                 if (isBraceType(newBraceType, STRUCT_TYPE) && isCStyle())
1054                     isInIndentableStruct = isStructAccessModified(currentLine, charNum);
1055                 else
1056                     isInIndentableStruct = false;
1057             }
1058 
1059             // this must be done before the braceTypeStack is popped
1060             BraceType braceType = braceTypeStack->back();
1061             bool isOpeningArrayBrace = (isBraceType(braceType, ARRAY_TYPE)
1062                                         && braceTypeStack->size() >= 2
1063                                         && !isBraceType((*braceTypeStack)[braceTypeStack->size() - 2], ARRAY_TYPE)
1064                                        );
1065 
1066             if (currentChar == '}')
1067             {
1068                 // if a request has been made to append a post block empty line,
1069                 // but the block exists immediately before a closing brace,
1070                 // then there is no need for the post block empty line.
1071                 isAppendPostBlockEmptyLineRequested = false;
1072                 if (isInAsm)
1073                     endOfAsmReached = true;
1074                 isInAsmOneLine = isInQuote = false;
1075                 shouldKeepLineUnbroken = false;
1076                 squareBracketCount = 0;
1077 
1078                 if (braceTypeStack->size() > 1)
1079                 {
1080                     previousBraceType = braceTypeStack->back();
1081                     braceTypeStack->pop_back();
1082                     isPreviousBraceBlockRelated = !isBraceType(braceType, ARRAY_TYPE);
1083                 }
1084                 else
1085                 {
1086                     previousBraceType = NULL_TYPE;
1087                     isPreviousBraceBlockRelated = false;
1088                 }
1089 
1090                 if (!preBraceHeaderStack->empty())
1091                 {
1092                     currentHeader = preBraceHeaderStack->back();
1093                     preBraceHeaderStack->pop_back();
1094                 }
1095                 else
1096                     currentHeader = nullptr;
1097 
1098                 if (!structStack->empty())
1099                 {
1100                     isInIndentableStruct = structStack->back();
1101                     structStack->pop_back();
1102                 }
1103                 else
1104                     isInIndentableStruct = false;
1105 
1106                 if (isNonInStatementArray
1107                         && (!isBraceType(braceTypeStack->back(), ARRAY_TYPE)    // check previous brace
1108                             || peekNextChar() == ';'))                          // check for "};" added V2.01
1109                     isImmediatelyPostNonInStmt = true;
1110 
1111                 if (!shouldBreakOneLineStatements
1112                         && ASBeautifier::getNextWord(currentLine, charNum) == AS_ELSE)
1113                 {
1114                     // handle special case of "else" at the end of line
1115                     size_t nextText = currentLine.find_first_not_of(" \t", charNum + 1);
1116                     if (ASBeautifier::peekNextChar(currentLine, nextText + 3) == ' ')
1117                         shouldBreakLineAtNextChar = true;
1118                 }
1119             }
1120 
1121             // format braces
1122             appendOpeningBrace = false;
1123             if (isBraceType(braceType, ARRAY_TYPE))
1124             {
1125                 formatArrayBraces(braceType, isOpeningArrayBrace);
1126             }
1127             else
1128             {
1129                 if (currentChar == '{')
1130                     formatOpeningBrace(braceType);
1131                 else
1132                     formatClosingBrace(braceType);
1133             }
1134             continue;
1135         }
1136 
1137         if ((((previousCommandChar == '{' && isPreviousBraceBlockRelated)
1138                 || ((previousCommandChar == '}'
1139                      && !isImmediatelyPostEmptyBlock
1140                      && isPreviousBraceBlockRelated
1141                      && !isPreviousCharPostComment       // Fixes wrongly appended newlines after '}' immediately after comments
1142                      && peekNextChar() != ' '
1143                      && !isBraceType(previousBraceType, DEFINITION_TYPE))
1144                     && !isBraceType(braceTypeStack->back(), DEFINITION_TYPE)))
1145                 && isOkToBreakBlock(braceTypeStack->back()))
1146                 // check for array
1147                 || (previousCommandChar == '{'          // added 9/30/2010
1148                     && isBraceType(braceTypeStack->back(), ARRAY_TYPE)
1149                     && !isBraceType(braceTypeStack->back(), SINGLE_LINE_TYPE)
1150                     && isNonInStatementArray)
1151                 // check for pico one line braces
1152                 || (formattingStyle == STYLE_PICO
1153                     && (previousCommandChar == '{' && isPreviousBraceBlockRelated)
1154                     && isBraceType(braceTypeStack->back(), COMMAND_TYPE)
1155                     && isBraceType(braceTypeStack->back(), SINGLE_LINE_TYPE)
1156                     && braceFormatMode == RUN_IN_MODE)
1157            )
1158         {
1159             isCharImmediatelyPostOpenBlock = (previousCommandChar == '{');
1160             isCharImmediatelyPostCloseBlock = (previousCommandChar == '}');
1161 
1162             if (isCharImmediatelyPostOpenBlock
1163                     && !isCharImmediatelyPostComment
1164                     && !isCharImmediatelyPostLineComment)
1165             {
1166                 previousCommandChar = ' ';
1167 
1168                 if (braceFormatMode == NONE_MODE)
1169                 {
1170                     if (isBraceType(braceTypeStack->back(), SINGLE_LINE_TYPE)
1171                             && (isBraceType(braceTypeStack->back(), BREAK_BLOCK_TYPE)
1172                                 || shouldBreakOneLineBlocks))
1173                         isInLineBreak = true;
1174                     else if (currentLineBeginsWithBrace)
1175                         formatRunIn();
1176                     else
1177                         breakLine();
1178                 }
1179                 else if (braceFormatMode == RUN_IN_MODE
1180                          && currentChar != '#')
1181                     formatRunIn();
1182                 else
1183                     isInLineBreak = true;
1184             }
1185             else if (isCharImmediatelyPostCloseBlock
1186                      && shouldBreakOneLineStatements
1187                      && !isCharImmediatelyPostComment
1188                      && ((isLegalNameChar(currentChar) && currentChar != '.')
1189                          || currentChar == '+'
1190                          || currentChar == '-'
1191                          || currentChar == '*'
1192                          || currentChar == '&'
1193                          || currentChar == '('))
1194             {
1195                 previousCommandChar = ' ';
1196                 isInLineBreak = true;
1197             }
1198         }
1199 
1200         // reset block handling flags
1201         isImmediatelyPostEmptyBlock = false;
1202 
1203         // Objective-C method prefix with no return type
1204         if (isImmediatelyPostObjCMethodPrefix && currentChar != '(')
1205         {
1206             if (shouldPadMethodPrefix || shouldUnPadMethodPrefix)
1207                 padObjCMethodPrefix();
1208             isImmediatelyPostObjCMethodPrefix = false;
1209         }
1210 
1211         // look for headers
1212         bool isPotentialHeader = isCharPotentialHeader(currentLine, charNum);
1213 
1214         if (isPotentialHeader && !isInTemplate && squareBracketCount == 0)
1215         {
1216             isNonParenHeader = false;
1217             foundClosingHeader = false;
1218 
1219             newHeader = findHeader(headers);
1220 
1221             // java can have a 'default' not in a switch
1222             if (newHeader == &AS_DEFAULT
1223                     && ASBeautifier::peekNextChar(
1224                         currentLine, charNum + (*newHeader).length() - 1) != ':')
1225                 newHeader = nullptr;
1226             // Qt headers may be variables in C++
1227             if (isCStyle()
1228                     && (newHeader == &AS_FOREVER || newHeader == &AS_FOREACH))
1229             {
1230                 if (currentLine.find_first_of("=;", charNum) != string::npos)
1231                     newHeader = nullptr;
1232             }
1233             if (isJavaStyle()
1234                     && (newHeader == &AS_SYNCHRONIZED))
1235             {
1236                 // want synchronized statements not synchronized methods
1237                 if (!isBraceType(braceTypeStack->back(), COMMAND_TYPE))
1238                     newHeader = nullptr;
1239             }
1240             else if (newHeader == &AS_USING
1241                      && ASBeautifier::peekNextChar(
1242                          currentLine, charNum + (*newHeader).length() - 1) != '(')
1243                 newHeader = nullptr;
1244 
1245             if (newHeader != nullptr)
1246             {
1247                 foundClosingHeader = isClosingHeader(newHeader);
1248 
1249                 if (!foundClosingHeader)
1250                 {
1251                     // these are closing headers
1252                     if ((newHeader == &AS_WHILE && currentHeader == &AS_DO)
1253                             || (newHeader == &_AS_FINALLY && currentHeader == &_AS_TRY)
1254                             || (newHeader == &_AS_EXCEPT && currentHeader == &_AS_TRY))
1255                         foundClosingHeader = true;
1256                     // don't append empty block for these related headers
1257                     else if (isSharpStyle()
1258                              && previousNonWSChar == '}'
1259                              && ((newHeader == &AS_SET && currentHeader == &AS_GET)
1260                                  || (newHeader == &AS_REMOVE && currentHeader == &AS_ADD))
1261                              && isOkToBreakBlock(braceTypeStack->back()))
1262                         isAppendPostBlockEmptyLineRequested = false;
1263                 }
1264 
1265                 // TODO: this can be removed in a future release
1266                 // version 3.0 - break erroneous attached header from previous versions
1267                 if (isSharpStyle()
1268                         && ((newHeader == &AS_SET && currentHeader == &AS_GET)
1269                             || (newHeader == &AS_REMOVE && currentHeader == &AS_ADD))
1270                         && !isBraceType(braceTypeStack->back(), SINGLE_LINE_TYPE)
1271                         && currentLine[currentLine.find_first_not_of(" \t")] == '}')
1272                     isInLineBreak = true;
1273                 // END TODO
1274 
1275                 const string* previousHeader = currentHeader;
1276                 currentHeader = newHeader;
1277                 needHeaderOpeningBrace = true;
1278 
1279                 // is the previous statement on the same line?
1280                 if ((previousNonWSChar == ';' || previousNonWSChar == ':')
1281                         && !isInLineBreak
1282                         && isOkToBreakBlock(braceTypeStack->back()))
1283                 {
1284                     // if breaking lines, break the line at the header
1285                     // except for multiple 'case' statements on a line
1286                     if (maxCodeLength != string::npos
1287                             && previousHeader != &AS_CASE)
1288                         isInLineBreak = true;
1289                     else
1290                         isHeaderInMultiStatementLine = true;
1291                 }
1292 
1293                 if (foundClosingHeader && previousNonWSChar == '}')
1294                 {
1295                     if (isOkToBreakBlock(braceTypeStack->back()))
1296                         isLineBreakBeforeClosingHeader();
1297 
1298                     // get the adjustment for a comment following the closing header
1299                     if (isInLineBreak)
1300                         nextLineSpacePadNum = getNextLineCommentAdjustment();
1301                     else
1302                         spacePadNum = getCurrentLineCommentAdjustment();
1303                 }
1304 
1305                 // check if the found header is non-paren header
1306                 isNonParenHeader = findHeader(nonParenHeaders) != nullptr;
1307 
1308                 if (isNonParenHeader
1309                         && (currentHeader == &AS_CATCH
1310                             || currentHeader == &AS_CASE))
1311                 {
1312                     int startChar = charNum + currentHeader->length() - 1;
1313                     if (ASBeautifier::peekNextChar(currentLine, startChar) == '(')
1314                         isNonParenHeader = false;
1315                 }
1316 
1317                 // join 'else if' statements
1318                 if (currentHeader == &AS_IF
1319                         && previousHeader == &AS_ELSE
1320                         && isInLineBreak
1321                         && !shouldBreakElseIfs
1322                         && !isCharImmediatelyPostLineComment
1323                         && !isImmediatelyPostPreprocessor)
1324                 {
1325                     // 'else' must be last thing on the line
1326                     size_t start = formattedLine.length() >= 6 ? formattedLine.length() - 6 : 0;
1327                     if (formattedLine.find(AS_ELSE, start) != string::npos)
1328                     {
1329                         appendSpacePad();
1330                         isInLineBreak = false;
1331                     }
1332                 }
1333 
1334                 appendSequence(*currentHeader);
1335                 goForward(currentHeader->length() - 1);
1336                 // if a paren-header is found add a space after it, if needed
1337                 // this checks currentLine, appendSpacePad() checks formattedLine
1338                 // in 'case' and C# 'catch' can be either a paren or non-paren header
1339                 if (shouldPadHeader
1340                         && !isNonParenHeader
1341                         && charNum < (int) currentLine.length() - 1 && !isWhiteSpace(currentLine[charNum + 1]))
1342                     appendSpacePad();
1343 
1344                 // Signal that a header has been reached
1345                 // *** But treat a closing while() (as in do...while)
1346                 //     as if it were NOT a header since a closing while()
1347                 //     should never have a block after it!
1348                 if (currentHeader != &AS_CASE && currentHeader != &AS_DEFAULT
1349                         && !(foundClosingHeader && currentHeader == &AS_WHILE))
1350                 {
1351                     isInHeader = true;
1352 
1353                     // in C# 'catch' and 'delegate' can be a paren or non-paren header
1354                     if (isNonParenHeader && !isSharpStyleWithParen(currentHeader))
1355                     {
1356                         isImmediatelyPostHeader = true;
1357                         isInHeader = false;
1358                     }
1359                 }
1360 
1361                 if (shouldBreakBlocks
1362                         && isOkToBreakBlock(braceTypeStack->back())
1363                         && !isHeaderInMultiStatementLine)
1364                 {
1365                     if (previousHeader == nullptr
1366                             && !foundClosingHeader
1367                             && !isCharImmediatelyPostOpenBlock
1368                             && !isImmediatelyPostCommentOnly)
1369                     {
1370                         isPrependPostBlockEmptyLineRequested = true;
1371                     }
1372 
1373                     if (isClosingHeader(currentHeader)
1374                             || foundClosingHeader)
1375                     {
1376                         isPrependPostBlockEmptyLineRequested = false;
1377                     }
1378 
1379                     if (shouldBreakClosingHeaderBlocks
1380                             && isCharImmediatelyPostCloseBlock
1381                             && !isImmediatelyPostCommentOnly
1382                             && !(currentHeader == &AS_WHILE         // do-while
1383                                  && foundClosingHeader))
1384                     {
1385                         isPrependPostBlockEmptyLineRequested = true;
1386                     }
1387                 }
1388 
1389                 if (currentHeader == &AS_CASE
1390                         || currentHeader == &AS_DEFAULT)
1391                     isInCase = true;
1392 
1393                 continue;
1394             }
1395             else if ((newHeader = findHeader(preDefinitionHeaders)) != nullptr
1396                      && parenStack->back() == 0
1397                      && !isInEnum)      // not C++11 enum class
1398             {
1399                 if (newHeader == &AS_NAMESPACE || newHeader == &AS_MODULE)
1400                     foundNamespaceHeader = true;
1401                 if (newHeader == &AS_CLASS)
1402                     foundClassHeader = true;
1403                 if (newHeader == &AS_STRUCT)
1404                     foundStructHeader = true;
1405                 if (newHeader == &AS_INTERFACE && !foundNamespaceHeader && !foundClassHeader)
1406                     foundInterfaceHeader = true;
1407                 foundPreDefinitionHeader = true;
1408                 appendSequence(*newHeader);
1409                 goForward(newHeader->length() - 1);
1410 
1411                 continue;
1412             }
1413             else if ((newHeader = findHeader(preCommandHeaders)) != nullptr)
1414             {
1415                 // must be after function arguments
1416                 if (previousNonWSChar == ')')
1417                     foundPreCommandHeader = true;
1418             }
1419             else if ((newHeader = findHeader(castOperators)) != nullptr)
1420             {
1421                 foundCastOperator = true;
1422                 appendSequence(*newHeader);
1423                 goForward(newHeader->length() - 1);
1424                 continue;
1425             }
1426         }   // (isPotentialHeader && !isInTemplate)
1427 
1428         if (isInLineBreak)          // OK to break line here
1429         {
1430             breakLine();
1431             if (isInVirginLine)     // adjust for the first line
1432             {
1433                 lineCommentNoBeautify = lineCommentNoIndent;
1434                 lineCommentNoIndent = false;
1435                 if (isImmediatelyPostPreprocessor)
1436                 {
1437                     isInIndentablePreproc = isIndentableProprocessor;
1438                     isIndentableProprocessor = false;
1439                 }
1440             }
1441         }
1442 
1443         if (previousNonWSChar == '}' || currentChar == ';')
1444         {
1445             if (currentChar == ';')
1446             {
1447                 squareBracketCount = 0;
1448                 //assert(methodBreakCharNum == string::npos);   // comment out
1449                 //assert(methodBreakLineNum == 0);              // comment out
1450                 methodBreakCharNum = string::npos;
1451                 methodBreakLineNum = 0;
1452                 methodAttachCharNum = string::npos;
1453                 methodAttachLineNum = 0;
1454 
1455                 if (((shouldBreakOneLineStatements
1456                         || isBraceType(braceTypeStack->back(), SINGLE_LINE_TYPE))
1457                         && isOkToBreakBlock(braceTypeStack->back()))
1458                         && !(attachClosingBraceMode && peekNextChar() == '}'))
1459                 {
1460                     passedSemicolon = true;
1461                 }
1462                 else if (!shouldBreakOneLineStatements
1463                          && ASBeautifier::getNextWord(currentLine, charNum) == AS_ELSE)
1464                 {
1465                     // handle special case of "else" at the end of line
1466                     size_t nextText = currentLine.find_first_not_of(" \t", charNum + 1);
1467                     if (ASBeautifier::peekNextChar(currentLine, nextText + 3) == ' ')
1468                         passedSemicolon = true;
1469                 }
1470 
1471                 if (shouldBreakBlocks
1472                         && currentHeader != nullptr
1473                         && currentHeader != &AS_CASE
1474                         && currentHeader != &AS_DEFAULT
1475                         && !isHeaderInMultiStatementLine
1476                         && parenStack->back() == 0)
1477                 {
1478                     isAppendPostBlockEmptyLineRequested = true;
1479                 }
1480             }
1481             if (currentChar != ';'
1482                     || (needHeaderOpeningBrace && parenStack->back() == 0))
1483                 currentHeader = nullptr;
1484 
1485             resetEndOfStatement();
1486         }
1487 
1488         if (currentChar == ':'
1489                 && previousChar != ':'         // not part of '::'
1490                 && peekNextChar() != ':')      // not part of '::'
1491         {
1492             if (isInCase)
1493             {
1494                 isInCase = false;
1495                 if (shouldBreakOneLineStatements)
1496                     passedColon = true;
1497             }
1498             else if (isCStyle()                     // for C/C++ only
1499                      && isOkToBreakBlock(braceTypeStack->back())
1500                      && shouldBreakOneLineStatements
1501                      && !foundQuestionMark          // not in a ?: sequence
1502                      && !foundPreDefinitionHeader   // not in a definition block
1503                      && previousCommandChar != ')'  // not after closing paren of a method header
1504                      && !foundPreCommandHeader      // not after a 'noexcept'
1505                      && squareBracketCount == 0     // not in objC method call
1506                      && !isInObjCMethodDefinition   // not objC '-' or '+' method
1507                      && !isInObjCInterface          // not objC @interface
1508                      && !isInObjCSelector           // not objC @selector
1509                      && !isDigit(peekNextChar())    // not a bit field
1510                      && !isInEnum                   // not an enum with a base type
1511                      && !isInAsm                    // not in extended assembler
1512                      && !isInAsmOneLine             // not in extended assembler
1513                      && !isInAsmBlock)              // not in extended assembler
1514             {
1515                 passedColon = true;
1516             }
1517 
1518             if (isCStyle()
1519                     && (squareBracketCount > 0 || isInObjCMethodDefinition || isInObjCSelector)
1520                     && !foundQuestionMark)          // not in a ?: sequence
1521             {
1522                 isImmediatelyPostObjCMethodPrefix = false;
1523                 isInObjCReturnType = false;
1524                 isInObjCParam = true;
1525                 if (shouldPadMethodColon)
1526                     padObjCMethodColon();
1527             }
1528 
1529             if (isInObjCInterface)
1530             {
1531                 appendSpacePad();
1532                 if ((int) currentLine.length() > charNum + 1
1533                         && !isWhiteSpace(currentLine[charNum + 1]))
1534                     currentLine.insert(charNum + 1, " ");
1535             }
1536 
1537             if (isClassInitializer())
1538                 isInClassInitializer = true;
1539         }
1540 
1541         if (currentChar == '?')
1542             foundQuestionMark = true;
1543 
1544         if (isPotentialHeader && !isInTemplate)
1545         {
1546             if (findKeyword(currentLine, charNum, AS_NEW)
1547                     || findKeyword(currentLine, charNum, AS_DELETE))
1548             {
1549                 isInPotentialCalculation = false;
1550                 isImmediatelyPostNewDelete = true;
1551             }
1552 
1553             if (findKeyword(currentLine, charNum, AS_RETURN))
1554             {
1555                 isInPotentialCalculation = true;
1556                 isImmediatelyPostReturn = true;     // return is the same as an = sign
1557             }
1558 
1559             if (findKeyword(currentLine, charNum, AS_OPERATOR))
1560                 isImmediatelyPostOperator = true;
1561 
1562             if (findKeyword(currentLine, charNum, AS_ENUM))
1563             {
1564                 size_t firstNum = currentLine.find_first_of("(){},/");
1565                 if (firstNum == string::npos
1566                         || currentLine[firstNum] == '{'
1567                         || currentLine[firstNum] == '/')
1568                     isInEnum = true;
1569             }
1570 
1571             if (isCStyle()
1572                     && findKeyword(currentLine, charNum, AS_THROW)
1573                     && previousCommandChar != ')'
1574                     && !foundPreCommandHeader)      // 'const' throw()
1575                 isImmediatelyPostThrow = true;
1576 
1577             if (isCStyle() && findKeyword(currentLine, charNum, AS_EXTERN) && isExternC())
1578                 isInExternC = true;
1579 
1580             if (isCStyle() && findKeyword(currentLine, charNum, AS_AUTO)
1581                     && (isBraceType(braceTypeStack->back(), NULL_TYPE)
1582                         || isBraceType(braceTypeStack->back(), DEFINITION_TYPE)))
1583                 foundTrailingReturnType = true;
1584 
1585             // check for break/attach return type
1586             if (shouldBreakReturnType || shouldBreakReturnTypeDecl
1587                     || shouldAttachReturnType || shouldAttachReturnTypeDecl)
1588             {
1589                 if ((isBraceType(braceTypeStack->back(), NULL_TYPE)
1590                         || isBraceType(braceTypeStack->back(), DEFINITION_TYPE))
1591                         && !returnTypeChecked
1592                         && !foundNamespaceHeader
1593                         && !foundClassHeader
1594                         && !isInObjCMethodDefinition
1595                         // bypass objective-C and java @ character
1596                         && charNum == (int) currentLine.find_first_not_of(" \t")
1597                         && !(isCStyle() && isCharPotentialHeader(currentLine, charNum)
1598                              && (findKeyword(currentLine, charNum, AS_PUBLIC)
1599                                  || findKeyword(currentLine, charNum, AS_PRIVATE)
1600                                  || findKeyword(currentLine, charNum, AS_PROTECTED))))
1601                 {
1602                     findReturnTypeSplitPoint(currentLine);
1603                     returnTypeChecked = true;
1604                 }
1605             }
1606 
1607             // Objective-C NSException macros are preCommandHeaders
1608             if (isCStyle() && findKeyword(currentLine, charNum, AS_NS_DURING))
1609                 foundPreCommandMacro = true;
1610             if (isCStyle() && findKeyword(currentLine, charNum, AS_NS_HANDLER))
1611                 foundPreCommandMacro = true;
1612 
1613             if (isCStyle() && isExecSQL(currentLine, charNum))
1614                 isInExecSQL = true;
1615 
1616             if (isCStyle())
1617             {
1618                 if (findKeyword(currentLine, charNum, AS_ASM)
1619                         || findKeyword(currentLine, charNum, AS__ASM__))
1620                 {
1621                     isInAsm = true;
1622                 }
1623                 else if (findKeyword(currentLine, charNum, AS_MS_ASM)       // microsoft specific
1624                          || findKeyword(currentLine, charNum, AS_MS__ASM))
1625                 {
1626                     int index = 4;
1627                     if (peekNextChar() == '_')  // check for __asm
1628                         index = 5;
1629 
1630                     char peekedChar = ASBase::peekNextChar(currentLine, charNum + index);
1631                     if (peekedChar == '{' || peekedChar == ' ')
1632                         isInAsmBlock = true;
1633                     else
1634                         isInAsmOneLine = true;
1635                 }
1636             }
1637 
1638             if (isJavaStyle()
1639                     && (findKeyword(currentLine, charNum, AS_STATIC)
1640                         && isNextCharOpeningBrace(charNum + 6)))
1641                 isJavaStaticConstructor = true;
1642 
1643             if (isSharpStyle()
1644                     && (findKeyword(currentLine, charNum, AS_DELEGATE)
1645                         || findKeyword(currentLine, charNum, AS_UNCHECKED)))
1646                 isSharpDelegate = true;
1647 
1648             // append the entire name
1649             string name = getCurrentWord(currentLine, charNum);
1650             // must pad the 'and' and 'or' operators if required
1651             if (name == "and" || name == "or")
1652             {
1653                 if (shouldPadOperators && previousNonWSChar != ':')
1654                 {
1655                     appendSpacePad();
1656                     appendOperator(name);
1657                     goForward(name.length() - 1);
1658                     if (!isBeforeAnyComment()
1659                             && !(currentLine.compare(charNum + 1, 1, AS_SEMICOLON) == 0)
1660                             && !(currentLine.compare(charNum + 1, 2, AS_SCOPE_RESOLUTION) == 0))
1661                         appendSpaceAfter();
1662                 }
1663                 else
1664                 {
1665                     appendOperator(name);
1666                     goForward(name.length() - 1);
1667                 }
1668             }
1669             else
1670             {
1671                 appendSequence(name);
1672                 goForward(name.length() - 1);
1673             }
1674 
1675             continue;
1676 
1677         }   // (isPotentialHeader &&  !isInTemplate)
1678 
1679         // determine if this is an Objective-C statement
1680 
1681         if (currentChar == '@'
1682                 && isCStyle()
1683                 && (int) currentLine.length() > charNum + 1
1684                 && !isWhiteSpace(currentLine[charNum + 1])
1685                 && isCharPotentialHeader(currentLine, charNum + 1)
1686                 && findKeyword(currentLine, charNum + 1, AS_INTERFACE)
1687                 && isBraceType(braceTypeStack->back(), NULL_TYPE))
1688         {
1689             isInObjCInterface = true;
1690             string name = '@' + AS_INTERFACE;
1691             appendSequence(name);
1692             goForward(name.length() - 1);
1693             continue;
1694         }
1695         else if (currentChar == '@'
1696                  && isCStyle()
1697                  && (int) currentLine.length() > charNum + 1
1698                  && !isWhiteSpace(currentLine[charNum + 1])
1699                  && isCharPotentialHeader(currentLine, charNum + 1)
1700                  && findKeyword(currentLine, charNum + 1, AS_SELECTOR))
1701         {
1702             isInObjCSelector = true;
1703             string name = '@' + AS_SELECTOR;
1704             appendSequence(name);
1705             goForward(name.length() - 1);
1706             continue;
1707         }
1708         else if ((currentChar == '-' || currentChar == '+')
1709                  && isCStyle()
1710                  && (int) currentLine.find_first_not_of(" \t") == charNum
1711                  && !isInPotentialCalculation
1712                  && !isInObjCMethodDefinition
1713                  && (isBraceType(braceTypeStack->back(), NULL_TYPE)
1714                      || (isBraceType(braceTypeStack->back(), EXTERN_TYPE))))
1715         {
1716             isInObjCMethodDefinition = true;
1717             isImmediatelyPostObjCMethodPrefix = true;
1718             isInObjCParam = false;
1719             isInObjCInterface = false;
1720             if (getAlignMethodColon())
1721                 objCColonAlign = findObjCColonAlignment();
1722             appendCurrentChar();
1723             continue;
1724         }
1725 
1726         // determine if this is a potential calculation
1727 
1728         bool isPotentialOperator = isCharPotentialOperator(currentChar);
1729         newHeader = nullptr;
1730 
1731         if (isPotentialOperator)
1732         {
1733             newHeader = findOperator(operators);
1734 
1735             // check for Java ? wildcard
1736             if (newHeader != nullptr
1737                     && newHeader == &AS_GCC_MIN_ASSIGN
1738                     && isJavaStyle()
1739                     && isInTemplate)
1740                 newHeader = nullptr;
1741 
1742             if (newHeader != nullptr)
1743             {
1744                 if (newHeader == &AS_LAMBDA)
1745                     foundPreCommandHeader = true;
1746 
1747                 // correct mistake of two >> closing a template
1748                 if (isInTemplate && (newHeader == &AS_GR_GR || newHeader == &AS_GR_GR_GR))
1749                     newHeader = &AS_GR;
1750 
1751                 if (!isInPotentialCalculation)
1752                 {
1753                     // must determine if newHeader is an assignment operator
1754                     // do NOT use findOperator - the length must be exact!!!
1755                     if (find(begin(*assignmentOperators), end(*assignmentOperators), newHeader)
1756                             != end(*assignmentOperators))
1757                     {
1758                         foundPreCommandHeader = false;
1759                         char peekedChar = peekNextChar();
1760                         isInPotentialCalculation = !(newHeader == &AS_EQUAL && peekedChar == '*')
1761                                                    && !(newHeader == &AS_EQUAL && peekedChar == '&')
1762                                                    && !isCharImmediatelyPostOperator;
1763                     }
1764                 }
1765             }
1766         }
1767 
1768         // process pointers and references
1769         // check newHeader to eliminate things like '&&' sequence
1770         if (newHeader != nullptr && !isJavaStyle()
1771                 && (newHeader == &AS_MULT
1772                     || newHeader == &AS_BIT_AND
1773                     || newHeader == &AS_BIT_XOR
1774                     || newHeader == &AS_AND)
1775                 && isPointerOrReference())
1776         {
1777             if (!isDereferenceOrAddressOf() && !isOperatorPaddingDisabled())
1778                 formatPointerOrReference();
1779             else
1780             {
1781                 appendOperator(*newHeader);
1782                 goForward(newHeader->length() - 1);
1783             }
1784             isImmediatelyPostPointerOrReference = true;
1785             continue;
1786         }
1787 
1788         if (shouldPadOperators && newHeader != nullptr && !isOperatorPaddingDisabled())
1789         {
1790             padOperators(newHeader);
1791             continue;
1792         }
1793 
1794         // remove spaces before commas
1795         if (currentChar == ',')
1796         {
1797             const size_t len = formattedLine.length();
1798             size_t lastText = formattedLine.find_last_not_of(' ');
1799             if (lastText != string::npos && lastText < len - 1)
1800             {
1801                 formattedLine.resize(lastText + 1);
1802                 int size_diff = len - (lastText + 1);
1803                 spacePadNum -= size_diff;
1804             }
1805         }
1806 
1807         // pad commas and semi-colons
1808         if (currentChar == ';'
1809                 || (currentChar == ',' && (shouldPadOperators || shouldPadCommas)))
1810         {
1811             char nextChar = ' ';
1812             if (charNum + 1 < (int) currentLine.length())
1813                 nextChar = currentLine[charNum + 1];
1814             if (!isWhiteSpace(nextChar)
1815                     && nextChar != '}'
1816                     && nextChar != ')'
1817                     && nextChar != ']'
1818                     && nextChar != '>'
1819                     && nextChar != ';'
1820                     && !isBeforeAnyComment()
1821                     /* && !(isBraceType(braceTypeStack->back(), ARRAY_TYPE)) */
1822                )
1823             {
1824                 appendCurrentChar();
1825                 appendSpaceAfter();
1826                 continue;
1827             }
1828         }
1829 
1830         // pad parens
1831         if (currentChar == '(' || currentChar == ')')
1832         {
1833             if (currentChar == '(')
1834             {
1835                 if (shouldPadHeader
1836                         && (isCharImmediatelyPostReturn
1837                             || isCharImmediatelyPostThrow
1838                             || isCharImmediatelyPostNewDelete))
1839                     appendSpacePad();
1840             }
1841 
1842             if (shouldPadParensOutside || shouldPadParensInside || shouldUnPadParens || shouldPadFirstParen)
1843                 padParens();
1844             else
1845                 appendCurrentChar();
1846 
1847             if (isInObjCMethodDefinition)
1848             {
1849                 if (currentChar == '(' && isImmediatelyPostObjCMethodPrefix)
1850                 {
1851                     if (shouldPadMethodPrefix || shouldUnPadMethodPrefix)
1852                         padObjCMethodPrefix();
1853                     isImmediatelyPostObjCMethodPrefix = false;
1854                     isInObjCReturnType = true;
1855                 }
1856                 else if (currentChar == ')' && isInObjCReturnType)
1857                 {
1858                     if (shouldPadReturnType || shouldUnPadReturnType)
1859                         padObjCReturnType();
1860                     isInObjCReturnType = false;
1861                 }
1862                 else if (isInObjCParam
1863                          && (shouldPadParamType || shouldUnPadParamType))
1864                     padObjCParamType();
1865             }
1866             continue;
1867         }
1868 
1869         // bypass the entire operator
1870         if (newHeader != nullptr)
1871         {
1872             appendOperator(*newHeader);
1873             goForward(newHeader->length() - 1);
1874             continue;
1875         }
1876 
1877         appendCurrentChar();
1878 
1879     }   // end of while loop  *  end of while loop  *  end of while loop  *  end of while loop
1880 
1881     // return a beautified (i.e. correctly indented) line.
1882 
1883     string beautifiedLine;
1884     size_t readyFormattedLineLength = trim(readyFormattedLine).length();
1885     bool isInNamespace = isBraceType(braceTypeStack->back(), NAMESPACE_TYPE);
1886 
1887     if (prependEmptyLine        // prepend a blank line before this formatted line
1888             && readyFormattedLineLength > 0
1889             && previousReadyFormattedLineLength > 0)
1890     {
1891         isLineReady = true;     // signal a waiting readyFormattedLine
1892         beautifiedLine = beautify("");
1893         previousReadyFormattedLineLength = 0;
1894         // call the enhancer for new empty lines
1895         enhancer->enhance(beautifiedLine, isInNamespace, isInPreprocessorBeautify, isInBeautifySQL);
1896     }
1897     else        // format the current formatted line
1898     {
1899         isLineReady = false;
1900         runInIndentContinuation = runInIndentChars;
1901         beautifiedLine = beautify(readyFormattedLine);
1902         previousReadyFormattedLineLength = readyFormattedLineLength;
1903         // the enhancer is not called for no-indent line comments
1904         if (!lineCommentNoBeautify && !isFormattingModeOff)
1905             enhancer->enhance(beautifiedLine, isInNamespace, isInPreprocessorBeautify, isInBeautifySQL);
1906         runInIndentChars = 0;
1907         lineCommentNoBeautify = lineCommentNoIndent;
1908         lineCommentNoIndent = false;
1909         isInIndentablePreproc = isIndentableProprocessor;
1910         isIndentableProprocessor = false;
1911         isElseHeaderIndent = elseHeaderFollowsComments;
1912         isCaseHeaderCommentIndent = caseHeaderFollowsComments;
1913         objCColonAlignSubsequent = objCColonAlign;
1914         if (isCharImmediatelyPostNonInStmt)
1915         {
1916             isNonInStatementArray = false;
1917             isCharImmediatelyPostNonInStmt = false;
1918         }
1919         isInPreprocessorBeautify = isInPreprocessor;    // used by ASEnhancer
1920         isInBeautifySQL = isInExecSQL;                  // used by ASEnhancer
1921     }
1922 
1923     prependEmptyLine = false;
1924     assert(computeChecksumOut(beautifiedLine));
1925     return beautifiedLine;
1926 }
1927 
1928 /**
1929  * check if there are any indented lines ready to be read by nextLine()
1930  *
1931  * @return    are there any indented lines ready?
1932  */
1933 bool ASFormatter::hasMoreLines() const
1934 {
1935     return !endOfCodeReached;
1936 }
1937 
1938 /**
1939  * comparison function for BraceType enum
1940  */
1941 bool ASFormatter::isBraceType(BraceType a, BraceType b) const
1942 {
1943     if (a == NULL_TYPE || b == NULL_TYPE)
1944         return (a == b);
1945     return ((a & b) == b);
1946 }
1947 
1948 /**
1949  * set the formatting style.
1950  *
1951  * @param style         the formatting style.
1952  */
1953 void ASFormatter::setFormattingStyle(FormatStyle style)
1954 {
1955     formattingStyle = style;
1956 }
1957 
1958 /**
1959  * set the add braces mode.
1960  * options:
1961  *    true     braces added to headers for single line statements.
1962  *    false    braces NOT added to headers for single line statements.
1963  *
1964  * @param state         the add braces state.
1965  */
1966 void ASFormatter::setAddBracesMode(bool state)
1967 {
1968     shouldAddBraces = state;
1969 }
1970 
1971 /**
1972  * set the add one line braces mode.
1973  * options:
1974  *    true     one line braces added to headers for single line statements.
1975  *    false    one line braces NOT added to headers for single line statements.
1976  *
1977  * @param state         the add one line braces state.
1978  */
1979 void ASFormatter::setAddOneLineBracesMode(bool state)
1980 {
1981     shouldAddBraces = state;
1982     shouldAddOneLineBraces = state;
1983 }
1984 
1985 /**
1986  * set the remove braces mode.
1987  * options:
1988  *    true     braces removed from headers for single line statements.
1989  *    false    braces NOT removed from headers for single line statements.
1990  *
1991  * @param state         the remove braces state.
1992  */
1993 void ASFormatter::setRemoveBracesMode(bool state)
1994 {
1995     shouldRemoveBraces = state;
1996 }
1997 
1998 // retained for compatibility with release 2.06
1999 // "Brackets" have been changed to "Braces" in 3.0
2000 // it is referenced only by the old "bracket" options
2001 void ASFormatter::setAddBracketsMode(bool state)
2002 {
2003     setAddBracesMode(state);
2004 }
2005 
2006 // retained for compatibility with release 2.06
2007 // "Brackets" have been changed to "Braces" in 3.0
2008 // it is referenced only by the old "bracket" options
2009 void ASFormatter::setAddOneLineBracketsMode(bool state)
2010 {
2011     setAddOneLineBracesMode(state);
2012 }
2013 
2014 // retained for compatibility with release 2.06
2015 // "Brackets" have been changed to "Braces" in 3.0
2016 // it is referenced only by the old "bracket" options
2017 void ASFormatter::setRemoveBracketsMode(bool state)
2018 {
2019     setRemoveBracesMode(state);
2020 }
2021 
2022 // retained for compatibility with release 2.06
2023 // "Brackets" have been changed to "Braces" in 3.0
2024 // it is referenced only by the old "bracket" options
2025 void ASFormatter::setBreakClosingHeaderBracketsMode(bool state)
2026 {
2027     setBreakClosingHeaderBracesMode(state);
2028 }
2029 
2030 /**
2031  * set the brace formatting mode.
2032  * options:
2033  *
2034  * @param mode         the brace formatting mode.
2035  */
2036 void ASFormatter::setBraceFormatMode(BraceMode mode)
2037 {
2038     braceFormatMode = mode;
2039 }
2040 
2041 /**
2042  * set 'break after' mode for maximum code length
2043  *
2044  * @param state         the 'break after' mode.
2045  */
2046 void ASFormatter::setBreakAfterMode(bool state)
2047 {
2048     shouldBreakLineAfterLogical = state;
2049 }
2050 
2051 /**
2052  * set closing header brace breaking mode
2053  * options:
2054  *    true     braces just before closing headers (e.g. 'else', 'catch')
2055  *             will be broken, even if standard braces are attached.
2056  *    false    closing header braces will be treated as standard braces.
2057  *
2058  * @param state         the closing header brace breaking mode.
2059  */
2060 void ASFormatter::setBreakClosingHeaderBracesMode(bool state)
2061 {
2062     shouldBreakClosingHeaderBraces = state;
2063 }
2064 
2065 /**
2066  * set 'else if()' breaking mode
2067  * options:
2068  *    true     'else' headers will be broken from their succeeding 'if' headers.
2069  *    false    'else' headers will be attached to their succeeding 'if' headers.
2070  *
2071  * @param state         the 'else if()' breaking mode.
2072  */
2073 void ASFormatter::setBreakElseIfsMode(bool state)
2074 {
2075     shouldBreakElseIfs = state;
2076 }
2077 
2078 /**
2079 * set comma padding mode.
2080 * options:
2081 *    true     statement commas and semicolons will be padded with spaces around them.
2082 *    false    statement commas and semicolons will not be padded.
2083 *
2084 * @param state         the padding mode.
2085 */
2086 void ASFormatter::setCommaPaddingMode(bool state)
2087 {
2088     shouldPadCommas = state;
2089 }
2090 
2091 /**
2092  * set maximum code length
2093  *
2094  * @param max         the maximum code length.
2095  */
2096 void ASFormatter::setMaxCodeLength(int max)
2097 {
2098     maxCodeLength = max;
2099 }
2100 
2101 /**
2102  * set operator padding mode.
2103  * options:
2104  *    true     statement operators will be padded with spaces around them.
2105  *    false    statement operators will not be padded.
2106  *
2107  * @param state         the padding mode.
2108  */
2109 void ASFormatter::setOperatorPaddingMode(bool state)
2110 {
2111     shouldPadOperators = state;
2112 }
2113 
2114 /**
2115  * set parenthesis outside padding mode.
2116  * options:
2117  *    true     statement parentheses will be padded with spaces around them.
2118  *    false    statement parentheses will not be padded.
2119  *
2120  * @param state         the padding mode.
2121  */
2122 void ASFormatter::setParensOutsidePaddingMode(bool state)
2123 {
2124     shouldPadParensOutside = state;
2125 }
2126 
2127 /**
2128  * set parenthesis inside padding mode.
2129  * options:
2130  *    true     statement parenthesis will be padded with spaces around them.
2131  *    false    statement parenthesis will not be padded.
2132  *
2133  * @param state         the padding mode.
2134  */
2135 void ASFormatter::setParensInsidePaddingMode(bool state)
2136 {
2137     shouldPadParensInside = state;
2138 }
2139 
2140 /**
2141  * set padding mode before one or more open parentheses.
2142  * options:
2143  *    true     first open parenthesis will be padded with a space before.
2144  *    false    first open parenthesis will not be padded.
2145  *
2146  * @param state         the padding mode.
2147  */
2148 void ASFormatter::setParensFirstPaddingMode(bool state)
2149 {
2150     shouldPadFirstParen = state;
2151 }
2152 
2153 /**
2154  * set header padding mode.
2155  * options:
2156  *    true     headers will be padded with spaces around them.
2157  *    false    headers will not be padded.
2158  *
2159  * @param state         the padding mode.
2160  */
2161 void ASFormatter::setParensHeaderPaddingMode(bool state)
2162 {
2163     shouldPadHeader = state;
2164 }
2165 
2166 /**
2167  * set parenthesis unpadding mode.
2168  * options:
2169  *    true     statement parenthesis will be unpadded with spaces removed around them.
2170  *    false    statement parenthesis will not be unpadded.
2171  *
2172  * @param state         the padding mode.
2173  */
2174 void ASFormatter::setParensUnPaddingMode(bool state)
2175 {
2176     shouldUnPadParens = state;
2177 }
2178 
2179 /**
2180 * set the state of the preprocessor indentation option.
2181 * If true, #ifdef blocks at level 0 will be indented.
2182 *
2183 * @param   state             state of option.
2184 */
2185 void ASFormatter::setPreprocBlockIndent(bool state)
2186 {
2187     shouldIndentPreprocBlock = state;
2188 }
2189 
2190 /**
2191  * Set strip comment prefix mode.
2192  * options:
2193  *    true     strip leading '*' in a comment.
2194  *    false    leading '*' in a comment will be left unchanged.
2195  *
2196  * @param state         the strip comment prefix mode.
2197  */
2198 void ASFormatter::setStripCommentPrefix(bool state)
2199 {
2200     shouldStripCommentPrefix = state;
2201 }
2202 
2203 /**
2204  * set objective-c '-' or '+' class prefix padding mode.
2205  * options:
2206  *    true     class prefix will be padded a spaces after them.
2207  *    false    class prefix will be left unchanged.
2208  *
2209  * @param state         the padding mode.
2210  */
2211 void ASFormatter::setMethodPrefixPaddingMode(bool state)
2212 {
2213     shouldPadMethodPrefix = state;
2214 }
2215 
2216 /**
2217  * set objective-c '-' or '+' class prefix unpadding mode.
2218  * options:
2219  *    true     class prefix will be unpadded with spaces after them removed.
2220  *    false    class prefix will left unchanged.
2221  *
2222  * @param state         the unpadding mode.
2223  */
2224 void ASFormatter::setMethodPrefixUnPaddingMode(bool state)
2225 {
2226     shouldUnPadMethodPrefix = state;
2227 }
2228 
2229 // set objective-c '-' or '+' return type padding mode.
2230 void ASFormatter::setReturnTypePaddingMode(bool state)
2231 {
2232     shouldPadReturnType = state;
2233 }
2234 
2235 // set objective-c '-' or '+' return type unpadding mode.
2236 void ASFormatter::setReturnTypeUnPaddingMode(bool state)
2237 {
2238     shouldUnPadReturnType = state;
2239 }
2240 
2241 // set objective-c method parameter type padding mode.
2242 void ASFormatter::setParamTypePaddingMode(bool state)
2243 {
2244     shouldPadParamType = state;
2245 }
2246 
2247 // set objective-c method parameter type unpadding mode.
2248 void ASFormatter::setParamTypeUnPaddingMode(bool state)
2249 {
2250     shouldUnPadParamType = state;
2251 }
2252 
2253 /**
2254  * set objective-c method colon padding mode.
2255  *
2256  * @param mode         objective-c colon padding mode.
2257  */
2258 void ASFormatter::setObjCColonPaddingMode(ObjCColonPad mode)
2259 {
2260     shouldPadMethodColon = true;
2261     objCColonPadMode = mode;
2262 }
2263 
2264 /**
2265  * set option to attach closing braces
2266  *
2267  * @param state        true = attach, false = don't attach.
2268  */
2269 void ASFormatter::setAttachClosingBraceMode(bool state)
2270 {
2271     attachClosingBraceMode = state;
2272 }
2273 
2274 /**
2275  * set option to attach class braces
2276  *
2277  * @param state        true = attach, false = use style default.
2278  */
2279 void ASFormatter::setAttachClass(bool state)
2280 {
2281     shouldAttachClass = state;
2282 }
2283 
2284 /**
2285  * set option to attach extern "C" braces
2286  *
2287  * @param state        true = attach, false = use style default.
2288  */
2289 void ASFormatter::setAttachExternC(bool state)
2290 {
2291     shouldAttachExternC = state;
2292 }
2293 
2294 /**
2295  * set option to attach namespace braces
2296  *
2297  * @param state        true = attach, false = use style default.
2298  */
2299 void ASFormatter::setAttachNamespace(bool state)
2300 {
2301     shouldAttachNamespace = state;
2302 }
2303 
2304 /**
2305  * set option to attach inline braces
2306  *
2307  * @param state        true = attach, false = use style default.
2308  */
2309 void ASFormatter::setAttachInline(bool state)
2310 {
2311     shouldAttachInline = state;
2312 }
2313 
2314 void ASFormatter::setAttachClosingWhile(bool state)
2315 {
2316     shouldAttachClosingWhile = state;
2317 }
2318 
2319 /**
2320  * set option to break/not break one-line blocks
2321  *
2322  * @param state        true = break, false = don't break.
2323  */
2324 void ASFormatter::setBreakOneLineBlocksMode(bool state)
2325 {
2326     shouldBreakOneLineBlocks = state;
2327 }
2328 
2329 /**
2330 * set one line headers breaking mode
2331 */
2332 void ASFormatter::setBreakOneLineHeadersMode(bool state)
2333 {
2334     shouldBreakOneLineHeaders = state;
2335 }
2336 
2337 /**
2338 * set option to break/not break lines consisting of multiple statements.
2339 *
2340 * @param state        true = break, false = don't break.
2341 */
2342 void ASFormatter::setBreakOneLineStatementsMode(bool state)
2343 {
2344     shouldBreakOneLineStatements = state;
2345 }
2346 
2347 void ASFormatter::setCloseTemplatesMode(bool state)
2348 {
2349     shouldCloseTemplates = state;
2350 }
2351 
2352 /**
2353  * set option to convert tabs to spaces.
2354  *
2355  * @param state        true = convert, false = don't convert.
2356  */
2357 void ASFormatter::setTabSpaceConversionMode(bool state)
2358 {
2359     shouldConvertTabs = state;
2360 }
2361 
2362 /**
2363  * set option to indent comments in column 1.
2364  *
2365  * @param state        true = indent, false = don't indent.
2366  */
2367 void ASFormatter::setIndentCol1CommentsMode(bool state)
2368 {
2369     shouldIndentCol1Comments = state;
2370 }
2371 
2372 /**
2373  * set option to force all line ends to a particular style.
2374  *
2375  * @param fmt           format enum value
2376  */
2377 void ASFormatter::setLineEndFormat(LineEndFormat fmt)
2378 {
2379     lineEnd = fmt;
2380 }
2381 
2382 /**
2383  * set option to break unrelated blocks of code with empty lines.
2384  *
2385  * @param state        true = convert, false = don't convert.
2386  */
2387 void ASFormatter::setBreakBlocksMode(bool state)
2388 {
2389     shouldBreakBlocks = state;
2390 }
2391 
2392 /**
2393  * set option to break closing header blocks of code (such as 'else', 'catch', ...) with empty lines.
2394  *
2395  * @param state        true = convert, false = don't convert.
2396  */
2397 void ASFormatter::setBreakClosingHeaderBlocksMode(bool state)
2398 {
2399     shouldBreakClosingHeaderBlocks = state;
2400 }
2401 
2402 /**
2403  * set option to delete empty lines.
2404  *
2405  * @param state        true = delete, false = don't delete.
2406  */
2407 void ASFormatter::setDeleteEmptyLinesMode(bool state)
2408 {
2409     shouldDeleteEmptyLines = state;
2410 }
2411 
2412 void ASFormatter::setBreakReturnType(bool state)
2413 {
2414     shouldBreakReturnType = state;
2415 }
2416 
2417 void ASFormatter::setBreakReturnTypeDecl(bool state)
2418 {
2419     shouldBreakReturnTypeDecl = state;
2420 }
2421 
2422 void ASFormatter::setAttachReturnType(bool state)
2423 {
2424     shouldAttachReturnType = state;
2425 }
2426 
2427 void ASFormatter::setAttachReturnTypeDecl(bool state)
2428 {
2429     shouldAttachReturnTypeDecl = state;
2430 }
2431 
2432 /**
2433  * set the pointer alignment.
2434  *
2435  * @param alignment    the pointer alignment.
2436  */
2437 void ASFormatter::setPointerAlignment(PointerAlign alignment)
2438 {
2439     pointerAlignment = alignment;
2440 }
2441 
2442 void ASFormatter::setReferenceAlignment(ReferenceAlign alignment)
2443 {
2444     referenceAlignment = alignment;
2445 }
2446 
2447 /**
2448  * jump over several characters.
2449  *
2450  * @param i       the number of characters to jump over.
2451  */
2452 void ASFormatter::goForward(int i)
2453 {
2454     while (--i >= 0)
2455         getNextChar();
2456 }
2457 
2458 /**
2459  * peek at the next unread character.
2460  *
2461  * @return     the next unread character.
2462  */
2463 char ASFormatter::peekNextChar() const
2464 {
2465     char ch = ' ';
2466     size_t peekNum = currentLine.find_first_not_of(" \t", charNum + 1);
2467 
2468     if (peekNum == string::npos)
2469         return ch;
2470 
2471     ch = currentLine[peekNum];
2472 
2473     return ch;
2474 }
2475 
2476 /**
2477  * check if current placement is before a comment
2478  *
2479  * @return     is before a comment.
2480  */
2481 bool ASFormatter::isBeforeComment() const
2482 {
2483     bool foundComment = false;
2484     size_t peekNum = currentLine.find_first_not_of(" \t", charNum + 1);
2485 
2486     if (peekNum == string::npos)
2487         return foundComment;
2488 
2489     foundComment = (currentLine.compare(peekNum, 2, "/*") == 0);
2490 
2491     return foundComment;
2492 }
2493 
2494 /**
2495  * check if current placement is before a comment or line-comment
2496  *
2497  * @return     is before a comment or line-comment.
2498  */
2499 bool ASFormatter::isBeforeAnyComment() const
2500 {
2501     bool foundComment = false;
2502     size_t peekNum = currentLine.find_first_not_of(" \t", charNum + 1);
2503 
2504     if (peekNum == string::npos)
2505         return foundComment;
2506 
2507     foundComment = (currentLine.compare(peekNum, 2, "/*") == 0
2508                     || currentLine.compare(peekNum, 2, "//") == 0);
2509 
2510     return foundComment;
2511 }
2512 
2513 /**
2514  * check if current placement is before a comment or line-comment
2515  * if a block comment it must be at the end of the line
2516  *
2517  * @return     is before a comment or line-comment.
2518  */
2519 bool ASFormatter::isBeforeAnyLineEndComment(int startPos) const
2520 {
2521     bool foundLineEndComment = false;
2522     size_t peekNum = currentLine.find_first_not_of(" \t", startPos + 1);
2523 
2524     if (peekNum != string::npos)
2525     {
2526         if (currentLine.compare(peekNum, 2, "//") == 0)
2527             foundLineEndComment = true;
2528         else if (currentLine.compare(peekNum, 2, "/*") == 0)
2529         {
2530             // comment must be closed on this line with nothing after it
2531             size_t endNum = currentLine.find("*/", peekNum + 2);
2532             if (endNum != string::npos)
2533             {
2534                 size_t nextChar = currentLine.find_first_not_of(" \t", endNum + 2);
2535                 if (nextChar == string::npos)
2536                     foundLineEndComment = true;
2537             }
2538         }
2539     }
2540     return foundLineEndComment;
2541 }
2542 
2543 /**
2544  * check if current placement is before a comment followed by a line-comment
2545  *
2546  * @return     is before a multiple line-end comment.
2547  */
2548 bool ASFormatter::isBeforeMultipleLineEndComments(int startPos) const
2549 {
2550     bool foundMultipleLineEndComment = false;
2551     size_t peekNum = currentLine.find_first_not_of(" \t", startPos + 1);
2552 
2553     if (peekNum != string::npos)
2554     {
2555         if (currentLine.compare(peekNum, 2, "/*") == 0)
2556         {
2557             // comment must be closed on this line with nothing after it
2558             size_t endNum = currentLine.find("*/", peekNum + 2);
2559             if (endNum != string::npos)
2560             {
2561                 size_t nextChar = currentLine.find_first_not_of(" \t", endNum + 2);
2562                 if (nextChar != string::npos
2563                         && currentLine.compare(nextChar, 2, "//") == 0)
2564                     foundMultipleLineEndComment = true;
2565             }
2566         }
2567     }
2568     return foundMultipleLineEndComment;
2569 }
2570 
2571 /**
2572  * get the next character, increasing the current placement in the process.
2573  * the new character is inserted into the variable currentChar.
2574  *
2575  * @return   whether succeeded to receive the new character.
2576  */
2577 bool ASFormatter::getNextChar()
2578 {
2579     isInLineBreak = false;
2580     previousChar = currentChar;
2581 
2582     if (!isWhiteSpace(currentChar))
2583     {
2584         previousNonWSChar = currentChar;
2585         if (!isInComment && !isInLineComment && !isInQuote
2586                 && !isImmediatelyPostComment
2587                 && !isImmediatelyPostLineComment
2588                 && !isInPreprocessor
2589                 && !isSequenceReached("/*")
2590                 && !isSequenceReached("//"))
2591             previousCommandChar = currentChar;
2592     }
2593 
2594     if (charNum + 1 < (int) currentLine.length()
2595             && (!isWhiteSpace(peekNextChar()) || isInComment || isInLineComment))
2596     {
2597         currentChar = currentLine[++charNum];
2598 
2599         if (currentChar == '\t' && shouldConvertTabs)
2600             convertTabToSpaces();
2601 
2602         return true;
2603     }
2604 
2605     // end of line has been reached
2606     return getNextLine();
2607 }
2608 
2609 /**
2610  * get the next line of input, increasing the current placement in the process.
2611  *
2612  * @param emptyLineWasDeleted         an empty line was deleted.
2613  * @return   whether succeeded in reading the next line.
2614  */
2615 bool ASFormatter::getNextLine(bool emptyLineWasDeleted /*false*/)
2616 {
2617     if (!sourceIterator->hasMoreLines())
2618     {
2619         endOfCodeReached = true;
2620         return false;
2621     }
2622     if (appendOpeningBrace)
2623         currentLine = "{";      // append brace that was removed from the previous line
2624     else
2625     {
2626         currentLine = sourceIterator->nextLine(emptyLineWasDeleted);
2627         assert(computeChecksumIn(currentLine));
2628     }
2629     // reset variables for new line
2630     inLineNumber++;
2631     if (endOfAsmReached)
2632         endOfAsmReached = isInAsmBlock = isInAsm = false;
2633     shouldKeepLineUnbroken = false;
2634     isInCommentStartLine = false;
2635     isInCase = false;
2636     isInAsmOneLine = false;
2637     isHeaderInMultiStatementLine = false;
2638     isInQuoteContinuation = isInVerbatimQuote || haveLineContinuationChar;
2639     haveLineContinuationChar = false;
2640     isImmediatelyPostEmptyLine = lineIsEmpty;
2641     previousChar = ' ';
2642 
2643     if (currentLine.length() == 0)
2644         currentLine = string(" ");        // a null is inserted if this is not done
2645 
2646     if (methodBreakLineNum > 0)
2647         --methodBreakLineNum;
2648     if (methodAttachLineNum > 0)
2649         --methodAttachLineNum;
2650 
2651     // unless reading in the first line of the file, break a new line.
2652     if (!isVirgin)
2653         isInLineBreak = true;
2654     else
2655         isVirgin = false;
2656 
2657     if (isImmediatelyPostNonInStmt)
2658     {
2659         isCharImmediatelyPostNonInStmt = true;
2660         isImmediatelyPostNonInStmt = false;
2661     }
2662 
2663     // check if is in preprocessor before line trimming
2664     // a blank line after a \ will remove the flag
2665     isImmediatelyPostPreprocessor = isInPreprocessor;
2666     if (!isInComment
2667             && (previousNonWSChar != '\\'
2668                 || isEmptyLine(currentLine)))
2669         isInPreprocessor = false;
2670 
2671     if (passedSemicolon)
2672         isInExecSQL = false;
2673     initNewLine();
2674 
2675     currentChar = currentLine[charNum];
2676     if (isInBraceRunIn && previousNonWSChar == '{' && !isInComment)
2677         isInLineBreak = false;
2678     isInBraceRunIn = false;
2679 
2680     if (currentChar == '\t' && shouldConvertTabs)
2681         convertTabToSpaces();
2682 
2683     // check for an empty line inside a command brace.
2684     // if yes then read the next line (calls getNextLine recursively).
2685     // must be after initNewLine.
2686     if (shouldDeleteEmptyLines
2687             && lineIsEmpty
2688             && isBraceType((*braceTypeStack)[braceTypeStack->size() - 1], COMMAND_TYPE))
2689     {
2690         if (!shouldBreakBlocks || previousNonWSChar == '{' || !commentAndHeaderFollows())
2691         {
2692             isInPreprocessor = isImmediatelyPostPreprocessor;       // restore
2693             lineIsEmpty = false;
2694             return getNextLine(true);
2695         }
2696     }
2697     return true;
2698 }
2699 
2700 /**
2701  * jump over the leading white space in the current line,
2702  * IF the line does not begin a comment or is in a preprocessor definition.
2703  */
2704 void ASFormatter::initNewLine()
2705 {
2706     size_t len = currentLine.length();
2707     size_t tabSize = getTabLength();
2708     charNum = 0;
2709 
2710     // don't trim these
2711     if (isInQuoteContinuation
2712             || (isInPreprocessor && !getPreprocDefineIndent()))
2713         return;
2714 
2715     // SQL continuation lines must be adjusted so the leading spaces
2716     // is equivalent to the opening EXEC SQL
2717     if (isInExecSQL)
2718     {
2719         // replace leading tabs with spaces
2720         // so that continuation indent will be spaces
2721         size_t tabCount_ = 0;
2722         size_t i;
2723         for (i = 0; i < currentLine.length(); i++)
2724         {
2725             if (!isWhiteSpace(currentLine[i]))      // stop at first text
2726                 break;
2727             if (currentLine[i] == '\t')
2728             {
2729                 size_t numSpaces = tabSize - ((tabCount_ + i) % tabSize);
2730                 currentLine.replace(i, 1, numSpaces, ' ');
2731                 tabCount_++;
2732                 i += tabSize - 1;
2733             }
2734         }
2735         // this will correct the format if EXEC SQL is not a hanging indent
2736         trimContinuationLine();
2737         return;
2738     }
2739 
2740     // comment continuation lines must be adjusted so the leading spaces
2741     // is equivalent to the opening comment
2742     if (isInComment)
2743     {
2744         if (noTrimCommentContinuation)
2745             leadingSpaces = tabIncrementIn = 0;
2746         trimContinuationLine();
2747         return;
2748     }
2749 
2750     // compute leading spaces
2751     isImmediatelyPostCommentOnly = lineIsLineCommentOnly || lineEndsInCommentOnly;
2752     lineIsCommentOnly = false;
2753     lineIsLineCommentOnly = false;
2754     lineEndsInCommentOnly = false;
2755     doesLineStartComment = false;
2756     currentLineBeginsWithBrace = false;
2757     lineIsEmpty = false;
2758     currentLineFirstBraceNum = string::npos;
2759     tabIncrementIn = 0;
2760 
2761     // bypass whitespace at the start of a line
2762     // preprocessor tabs are replaced later in the program
2763     for (charNum = 0; isWhiteSpace(currentLine[charNum]) && charNum + 1 < (int) len; charNum++)
2764     {
2765         if (currentLine[charNum] == '\t' && !isInPreprocessor)
2766             tabIncrementIn += tabSize - 1 - ((tabIncrementIn + charNum) % tabSize);
2767     }
2768     leadingSpaces = charNum + tabIncrementIn;
2769 
2770     if (isSequenceReached("/*"))
2771     {
2772         doesLineStartComment = true;
2773         if ((int) currentLine.length() > charNum + 2
2774                 && currentLine.find("*/", charNum + 2) != string::npos)
2775             lineIsCommentOnly = true;
2776     }
2777     else if (isSequenceReached("//"))
2778     {
2779         lineIsLineCommentOnly = true;
2780     }
2781     else if (isSequenceReached("{"))
2782     {
2783         currentLineBeginsWithBrace = true;
2784         currentLineFirstBraceNum = charNum;
2785         size_t firstText = currentLine.find_first_not_of(" \t", charNum + 1);
2786         if (firstText != string::npos)
2787         {
2788             if (currentLine.compare(firstText, 2, "//") == 0)
2789                 lineIsLineCommentOnly = true;
2790             else if (currentLine.compare(firstText, 2, "/*") == 0
2791                      || isExecSQL(currentLine, firstText))
2792             {
2793                 // get the extra adjustment
2794                 size_t j;
2795                 for (j = charNum + 1; j < firstText && isWhiteSpace(currentLine[j]); j++)
2796                 {
2797                     if (currentLine[j] == '\t')
2798                         tabIncrementIn += tabSize - 1 - ((tabIncrementIn + j) % tabSize);
2799                 }
2800                 leadingSpaces = j + tabIncrementIn;
2801                 if (currentLine.compare(firstText, 2, "/*") == 0)
2802                     doesLineStartComment = true;
2803             }
2804         }
2805     }
2806     else if (isWhiteSpace(currentLine[charNum]) && !(charNum + 1 < (int) currentLine.length()))
2807     {
2808         lineIsEmpty = true;
2809     }
2810 
2811     // do not trim indented preprocessor define (except for comment continuation lines)
2812     if (isInPreprocessor)
2813     {
2814         if (!doesLineStartComment)
2815             leadingSpaces = 0;
2816         charNum = 0;
2817     }
2818 }
2819 
2820 /**
2821  * Append a character to the current formatted line.
2822  * The formattedLine split points are updated.
2823  *
2824  * @param ch               the character to append.
2825  * @param canBreakLine     if true, a registered line-break
2826  */
2827 void ASFormatter::appendChar(char ch, bool canBreakLine)
2828 {
2829     if (canBreakLine && isInLineBreak)
2830         breakLine();
2831 
2832     formattedLine.append(1, ch);
2833     isImmediatelyPostCommentOnly = false;
2834     if (maxCodeLength != string::npos)
2835     {
2836         // These compares reduce the frequency of function calls.
2837         if (isOkToSplitFormattedLine())
2838             updateFormattedLineSplitPoints(ch);
2839         if (formattedLine.length() > maxCodeLength)
2840             testForTimeToSplitFormattedLine();
2841     }
2842 }
2843 
2844 /**
2845  * Append a string sequence to the current formatted line.
2846  * The formattedLine split points are NOT updated.
2847  * But the formattedLine is checked for time to split.
2848  *
2849  * @param sequence         the sequence to append.
2850  * @param canBreakLine     if true, a registered line-break
2851  */
2852 void ASFormatter::appendSequence(const string& sequence, bool canBreakLine)
2853 {
2854     if (canBreakLine && isInLineBreak)
2855         breakLine();
2856     formattedLine.append(sequence);
2857     if (formattedLine.length() > maxCodeLength)
2858         testForTimeToSplitFormattedLine();
2859 }
2860 
2861 /**
2862  * Append an operator sequence to the current formatted line.
2863  * The formattedLine split points are updated.
2864  *
2865  * @param sequence         the sequence to append.
2866  * @param canBreakLine     if true, a registered line-break
2867  */
2868 void ASFormatter::appendOperator(const string& sequence, bool canBreakLine)
2869 {
2870     if (canBreakLine && isInLineBreak)
2871         breakLine();
2872     formattedLine.append(sequence);
2873     if (maxCodeLength != string::npos)
2874     {
2875         // These compares reduce the frequency of function calls.
2876         if (isOkToSplitFormattedLine())
2877             updateFormattedLineSplitPointsOperator(sequence);
2878         if (formattedLine.length() > maxCodeLength)
2879             testForTimeToSplitFormattedLine();
2880     }
2881 }
2882 
2883 /**
2884  * append a space to the current formattedline, UNLESS the
2885  * last character is already a white-space character.
2886  */
2887 void ASFormatter::appendSpacePad()
2888 {
2889     int len = formattedLine.length();
2890     if (len > 0 && !isWhiteSpace(formattedLine[len - 1]))
2891     {
2892         formattedLine.append(1, ' ');
2893         spacePadNum++;
2894         if (maxCodeLength != string::npos)
2895         {
2896             // These compares reduce the frequency of function calls.
2897             if (isOkToSplitFormattedLine())
2898                 updateFormattedLineSplitPoints(' ');
2899             if (formattedLine.length() > maxCodeLength)
2900                 testForTimeToSplitFormattedLine();
2901         }
2902     }
2903 }
2904 
2905 /**
2906  * append a space to the current formattedline, UNLESS the
2907  * next character is already a white-space character.
2908  */
2909 void ASFormatter::appendSpaceAfter()
2910 {
2911     int len = currentLine.length();
2912     if (charNum + 1 < len && !isWhiteSpace(currentLine[charNum + 1]))
2913     {
2914         formattedLine.append(1, ' ');
2915         spacePadNum++;
2916         if (maxCodeLength != string::npos)
2917         {
2918             // These compares reduce the frequency of function calls.
2919             if (isOkToSplitFormattedLine())
2920                 updateFormattedLineSplitPoints(' ');
2921             if (formattedLine.length() > maxCodeLength)
2922                 testForTimeToSplitFormattedLine();
2923         }
2924     }
2925 }
2926 
2927 /**
2928  * register a line break for the formatted line.
2929  */
2930 void ASFormatter::breakLine(bool isSplitLine /*false*/)
2931 {
2932     isLineReady = true;
2933     isInLineBreak = false;
2934     spacePadNum = nextLineSpacePadNum;
2935     nextLineSpacePadNum = 0;
2936     readyFormattedLine = formattedLine;
2937     formattedLine.erase();
2938     // queue an empty line prepend request if one exists
2939     prependEmptyLine = isPrependPostBlockEmptyLineRequested;
2940 
2941     if (!isSplitLine)
2942     {
2943         formattedLineCommentNum = string::npos;
2944         clearFormattedLineSplitPoints();
2945 
2946         if (isAppendPostBlockEmptyLineRequested)
2947         {
2948             isAppendPostBlockEmptyLineRequested = false;
2949             isPrependPostBlockEmptyLineRequested = true;
2950         }
2951         else
2952             isPrependPostBlockEmptyLineRequested = false;
2953     }
2954 }
2955 
2956 /**
2957  * check if the currently reached open-brace (i.e. '{')
2958  * opens a:
2959  * - a definition type block (such as a class or namespace),
2960  * - a command block (such as a method block)
2961  * - a static array
2962  * this method takes for granted that the current character
2963  * is an opening brace.
2964  *
2965  * @return    the type of the opened block.
2966  */
2967 BraceType ASFormatter::getBraceType()
2968 {
2969     assert(currentChar == '{');
2970 
2971     BraceType returnVal = NULL_TYPE;
2972 
2973     if ((previousNonWSChar == '='
2974             || isBraceType(braceTypeStack->back(), ARRAY_TYPE))
2975             && previousCommandChar != ')'
2976             && !isNonParenHeader)
2977         returnVal = ARRAY_TYPE;
2978     else if (foundPreDefinitionHeader && previousCommandChar != ')')
2979     {
2980         returnVal = DEFINITION_TYPE;
2981         if (foundNamespaceHeader)
2982             returnVal = (BraceType)(returnVal | NAMESPACE_TYPE);
2983         else if (foundClassHeader)
2984             returnVal = (BraceType)(returnVal | CLASS_TYPE);
2985         else if (foundStructHeader)
2986             returnVal = (BraceType)(returnVal | STRUCT_TYPE);
2987         else if (foundInterfaceHeader)
2988             returnVal = (BraceType)(returnVal | INTERFACE_TYPE);
2989     }
2990     else if (isInEnum)
2991     {
2992         returnVal = (BraceType)(ARRAY_TYPE | ENUM_TYPE);
2993     }
2994     else
2995     {
2996         bool isCommandType = (foundPreCommandHeader
2997                               || foundPreCommandMacro
2998                               || (currentHeader != nullptr && isNonParenHeader)
2999                               || (previousCommandChar == ')')
3000                               || (previousCommandChar == ':' && !foundQuestionMark)
3001                               || (previousCommandChar == ';')
3002                               || ((previousCommandChar == '{' || previousCommandChar == '}')
3003                                   && isPreviousBraceBlockRelated)
3004                               || (isInClassInitializer
3005                                   && ((!isLegalNameChar(previousNonWSChar) && previousNonWSChar != '(')
3006                                       || foundPreCommandHeader))
3007                               || foundTrailingReturnType
3008                               || isInObjCMethodDefinition
3009                               || isInObjCInterface
3010                               || isJavaStaticConstructor
3011                               || isSharpDelegate);
3012 
3013         // C# methods containing 'get', 'set', 'add', and 'remove' do NOT end with parens
3014         if (!isCommandType && isSharpStyle() && isNextWordSharpNonParenHeader(charNum + 1))
3015         {
3016             isCommandType = true;
3017             isSharpAccessor = true;
3018         }
3019 
3020         if (isInExternC)
3021             returnVal = (isCommandType ? COMMAND_TYPE : EXTERN_TYPE);
3022         else
3023             returnVal = (isCommandType ? COMMAND_TYPE : ARRAY_TYPE);
3024     }
3025 
3026     int foundOneLineBlock = isOneLineBlockReached(currentLine, charNum);
3027 
3028     if (foundOneLineBlock == 2 && returnVal == COMMAND_TYPE)
3029         returnVal = ARRAY_TYPE;
3030 
3031     if (foundOneLineBlock > 0)
3032     {
3033         returnVal = (BraceType) (returnVal | SINGLE_LINE_TYPE);
3034         if (breakCurrentOneLineBlock)
3035             returnVal = (BraceType) (returnVal | BREAK_BLOCK_TYPE);
3036         if (foundOneLineBlock == 3)
3037             returnVal = (BraceType)(returnVal | EMPTY_BLOCK_TYPE);
3038     }
3039 
3040     if (isBraceType(returnVal, ARRAY_TYPE))
3041     {
3042         if (isNonInStatementArrayBrace())
3043         {
3044             returnVal = (BraceType)(returnVal | ARRAY_NIS_TYPE);
3045             isNonInStatementArray = true;
3046             isImmediatelyPostNonInStmt = false;     // in case of "},{"
3047             nonInStatementBrace = formattedLine.length() - 1;
3048         }
3049         if (isUniformInitializerBrace())
3050             returnVal = (BraceType)(returnVal | INIT_TYPE);
3051     }
3052 
3053     return returnVal;
3054 }
3055 
3056 bool ASFormatter::isNumericVariable(string word) const
3057 {
3058     if (word == "bool"
3059             || word == "int"
3060             || word == "void"
3061             || word == "char"
3062             || word == "long"
3063             || word == "short"
3064             || word == "double"
3065             || word == "float"
3066             || (word.length() >= 4     // check end of word for _t
3067                 && word.compare(word.length() - 2, 2, "_t") == 0)
3068 // removed release 3.1
3069 //          || word == "Int32"
3070 //          || word == "UInt32"
3071 //          || word == "Int64"
3072 //          || word == "UInt64"
3073             || word == "BOOL"
3074             || word == "DWORD"
3075             || word == "HWND"
3076             || word == "INT"
3077             || word == "LPSTR"
3078             || word == "VOID"
3079             || word == "LPVOID"
3080             || word == "wxFontEncoding"
3081        )
3082         return true;
3083     return false;
3084 }
3085 
3086 /**
3087 * check if a colon is a class initializer separator
3088 *
3089 * @return        whether it is a class initializer separator
3090 */
3091 bool ASFormatter::isClassInitializer() const
3092 {
3093     assert(currentChar == ':');
3094     assert(previousChar != ':' && peekNextChar() != ':');   // not part of '::'
3095 
3096     // this should be similar to ASBeautifier::parseCurrentLine()
3097     bool foundClassInitializer = false;
3098 
3099     if (foundQuestionMark)
3100     {
3101         // do nothing special
3102     }
3103     else if (parenStack->back() > 0)
3104     {
3105         // found a 'for' loop or an objective-C statement
3106         // so do nothing special
3107     }
3108     else if (isInEnum)
3109     {
3110         // found an enum with a base-type
3111     }
3112     else if (isCStyle()
3113              && !isInCase
3114              && (previousCommandChar == ')' || foundPreCommandHeader))
3115     {
3116         // found a 'class' c'tor initializer
3117         foundClassInitializer = true;
3118     }
3119     return foundClassInitializer;
3120 }
3121 
3122 /**
3123  * check if a line is empty
3124  *
3125  * @return        whether line is empty
3126  */
3127 bool ASFormatter::isEmptyLine(const string& line) const
3128 {
3129     return line.find_first_not_of(" \t") == string::npos;
3130 }
3131 
3132 /**
3133  * Check if the following text is "C" as in extern "C".
3134  *
3135  * @return        whether the statement is extern "C"
3136  */
3137 bool ASFormatter::isExternC() const
3138 {
3139     // charNum should be at 'extern'
3140     assert(!isWhiteSpace(currentLine[charNum]));
3141     size_t startQuote = currentLine.find_first_of(" \t\"", charNum);
3142     if (startQuote == string::npos)
3143         return false;
3144     startQuote = currentLine.find_first_not_of(" \t", startQuote);
3145     if (startQuote == string::npos)
3146         return false;
3147     if (currentLine.compare(startQuote, 3, "\"C\"") != 0)
3148         return false;
3149     return true;
3150 }
3151 
3152 /**
3153  * Check if the currently reached '*', '&' or '^' character is
3154  * a pointer-or-reference symbol, or another operator.
3155  * A pointer dereference (*) or an "address of" character (&)
3156  * counts as a pointer or reference because it is not an
3157  * arithmetic operator.
3158  *
3159  * @return        whether current character is a reference-or-pointer
3160  */
3161 bool ASFormatter::isPointerOrReference() const
3162 {
3163     assert(currentChar == '*' || currentChar == '&' || currentChar == '^');
3164 
3165     if (isJavaStyle())
3166         return false;
3167 
3168     if (isCharImmediatelyPostOperator)
3169         return false;
3170 
3171     // get the last legal word (may be a number)
3172     string lastWord = getPreviousWord(currentLine, charNum);
3173     if (lastWord.empty())
3174         lastWord = " ";
3175 
3176     // check for preceding or following numeric values
3177     string nextText = peekNextText(currentLine.substr(charNum + 1));
3178     if (nextText.length() == 0)
3179         nextText = " ";
3180     if (isDigit(lastWord[0])
3181             || isDigit(nextText[0])
3182             || nextText[0] == '!'
3183             || nextText[0] == '~')
3184         return false;
3185 
3186     // check for multiply then a dereference (a * *b)
3187     char nextChar = peekNextChar();
3188     if (currentChar == '*'
3189             && nextChar == '*'
3190             && !isPointerToPointer(currentLine, charNum))
3191         return false;
3192 
3193     if ((foundCastOperator && nextChar == '>')
3194             || isPointerOrReferenceVariable(lastWord))
3195         return true;
3196 
3197     if (isInClassInitializer
3198             && previousNonWSChar != '('
3199             && previousNonWSChar != '{'
3200             && previousCommandChar != ','
3201             && nextChar != ')'
3202             && nextChar != '}')
3203         return false;
3204 
3205     //check for rvalue reference
3206     if (currentChar == '&' && nextChar == '&')
3207     {
3208         if (lastWord == AS_AUTO)
3209             return true;
3210         if (previousNonWSChar == '>')
3211             return true;
3212         string followingText;
3213         if ((int) currentLine.length() > charNum + 2)
3214             followingText = peekNextText(currentLine.substr(charNum + 2));
3215         if (followingText.length() > 0 && followingText[0] == ')')
3216             return true;
3217         if (currentHeader != nullptr || isInPotentialCalculation)
3218             return false;
3219         if (parenStack->back() > 0 && isBraceType(braceTypeStack->back(), COMMAND_TYPE))
3220             return false;
3221         return true;
3222     }
3223     if (nextChar == '*'
3224             || previousNonWSChar == '='
3225             || previousNonWSChar == '('
3226             || previousNonWSChar == '['
3227             || isCharImmediatelyPostReturn
3228             || isInTemplate
3229             || isCharImmediatelyPostTemplate
3230             || currentHeader == &AS_CATCH
3231             || currentHeader == &AS_FOREACH
3232             || currentHeader == &AS_QFOREACH)
3233         return true;
3234 
3235     if (isBraceType(braceTypeStack->back(), ARRAY_TYPE)
3236             && isLegalNameChar(lastWord[0])
3237             && isLegalNameChar(nextChar)
3238             && previousNonWSChar != ')')
3239     {
3240         if (isArrayOperator())
3241             return false;
3242     }
3243 
3244     // checks on operators in parens
3245     if (parenStack->back() > 0
3246             && isLegalNameChar(lastWord[0])
3247             && isLegalNameChar(nextChar))
3248     {
3249         // if followed by an assignment it is a pointer or reference
3250         // if followed by semicolon it is a pointer or reference in range-based for
3251         const string* followingOperator = getFollowingOperator();
3252         if (followingOperator != nullptr
3253                 && followingOperator != &AS_MULT
3254                 && followingOperator != &AS_BIT_AND)
3255         {
3256             if (followingOperator == &AS_ASSIGN || followingOperator == &AS_COLON)
3257                 return true;
3258             return false;
3259         }
3260 
3261         if (isBraceType(braceTypeStack->back(), COMMAND_TYPE)
3262                 || squareBracketCount > 0)
3263             return false;
3264         return true;
3265     }
3266 
3267     // checks on operators in parens with following '('
3268     if (parenStack->back() > 0
3269             && nextChar == '('
3270             && previousNonWSChar != ','
3271             && previousNonWSChar != '('
3272             && previousNonWSChar != '!'
3273             && previousNonWSChar != '&'
3274             && previousNonWSChar != '*'
3275             && previousNonWSChar != '|')
3276         return false;
3277 
3278     if (nextChar == '-'
3279             || nextChar == '+')
3280     {
3281         size_t nextNum = currentLine.find_first_not_of(" \t", charNum + 1);
3282         if (nextNum != string::npos)
3283         {
3284             if (currentLine.compare(nextNum, 2, "++") != 0
3285                     && currentLine.compare(nextNum, 2, "--") != 0)
3286                 return false;
3287         }
3288     }
3289 
3290     bool isPR = (!isInPotentialCalculation
3291                  || (!isLegalNameChar(previousNonWSChar)
3292                      && !(previousNonWSChar == ')' && nextChar == '(')
3293                      && !(previousNonWSChar == ')' && currentChar == '*' && !isImmediatelyPostCast())
3294                      && previousNonWSChar != ']')
3295                  || (!isWhiteSpace(nextChar)
3296                      && nextChar != '-'
3297                      && nextChar != '('
3298                      && nextChar != '['
3299                      && !isLegalNameChar(nextChar))
3300                 );
3301 
3302     return isPR;
3303 }
3304 
3305 /**
3306  * Check if the currently reached  '*' or '&' character is
3307  * a dereferenced pointer or "address of" symbol.
3308  * NOTE: this MUST be a pointer or reference as determined by
3309  * the function isPointerOrReference().
3310  *
3311  * @return        whether current character is a dereference or address of
3312  */
3313 bool ASFormatter::isDereferenceOrAddressOf() const
3314 {
3315     assert(currentChar == '*' || currentChar == '&' || currentChar == '^');
3316 
3317     if (isCharImmediatelyPostTemplate)
3318         return false;
3319 
3320     if (previousNonWSChar == '='
3321             || previousNonWSChar == ','
3322             || previousNonWSChar == '.'
3323             || previousNonWSChar == '{'
3324             || previousNonWSChar == '>'
3325             || previousNonWSChar == '<'
3326             || previousNonWSChar == '?'
3327             || isCharImmediatelyPostLineComment
3328             || isCharImmediatelyPostComment
3329             || isCharImmediatelyPostReturn)
3330         return true;
3331 
3332     char nextChar = peekNextChar();
3333     if (currentChar == '*' && nextChar == '*')
3334     {
3335         if (previousNonWSChar == '(')
3336             return true;
3337         if ((int) currentLine.length() < charNum + 2)
3338             return true;
3339         return false;
3340     }
3341     if (currentChar == '&' && nextChar == '&')
3342     {
3343         if (previousNonWSChar == '(' || isInTemplate)
3344             return true;
3345         if ((int) currentLine.length() < charNum + 2)
3346             return true;
3347         return false;
3348     }
3349 
3350     // check first char on the line
3351     if (charNum == (int) currentLine.find_first_not_of(" \t")
3352             && (isBraceType(braceTypeStack->back(), COMMAND_TYPE)
3353                 || parenStack->back() != 0))
3354         return true;
3355 
3356     string nextText = peekNextText(currentLine.substr(charNum + 1));
3357     if (nextText.length() > 0)
3358     {
3359         if (nextText[0] == ')' || nextText[0] == '>'
3360                 || nextText[0] == ',' || nextText[0] == '=')
3361             return false;
3362         if (nextText[0] == ';')
3363             return true;
3364     }
3365 
3366     // check for reference to a pointer *&
3367     if ((currentChar == '*' && nextChar == '&')
3368             || (previousNonWSChar == '*' && currentChar == '&'))
3369         return false;
3370 
3371     if (!isBraceType(braceTypeStack->back(), COMMAND_TYPE)
3372             && parenStack->back() == 0)
3373         return false;
3374 
3375     string lastWord = getPreviousWord(currentLine, charNum);
3376     if (lastWord == "else" || lastWord == "delete")
3377         return true;
3378 
3379     if (isPointerOrReferenceVariable(lastWord))
3380         return false;
3381 
3382     bool isDA = (!(isLegalNameChar(previousNonWSChar) || previousNonWSChar == '>')
3383                  || (nextText.length() > 0 && !isLegalNameChar(nextText[0]) && nextText[0] != '/')
3384                  || (ispunct((unsigned char)previousNonWSChar) && previousNonWSChar != '.')
3385                  || isCharImmediatelyPostReturn);
3386 
3387     return isDA;
3388 }
3389 
3390 /**
3391  * Check if the currently reached  '*' or '&' character is
3392  * centered with one space on each side.
3393  * Only spaces are checked, not tabs.
3394  * If true then a space will be deleted on the output.
3395  *
3396  * @return        whether current character is centered.
3397  */
3398 bool ASFormatter::isPointerOrReferenceCentered() const
3399 {
3400     assert(currentChar == '*' || currentChar == '&' || currentChar == '^');
3401 
3402     int prNum = charNum;
3403     int lineLength = (int) currentLine.length();
3404 
3405     // check for end of line
3406     if (peekNextChar() == ' ')
3407         return false;
3408 
3409     // check space before
3410     if (prNum < 1
3411             || currentLine[prNum - 1] != ' ')
3412         return false;
3413 
3414     // check no space before that
3415     if (prNum < 2
3416             || currentLine[prNum - 2] == ' ')
3417         return false;
3418 
3419     // check for ** or &&
3420     if (prNum + 1 < lineLength
3421             && (currentLine[prNum + 1] == '*' || currentLine[prNum + 1] == '&'))
3422         prNum++;
3423 
3424     // check space after
3425     if (prNum + 1 <= lineLength
3426             && currentLine[prNum + 1] != ' ')
3427         return false;
3428 
3429     // check no space after that
3430     if (prNum + 2 < lineLength
3431             && currentLine[prNum + 2] == ' ')
3432         return false;
3433 
3434     return true;
3435 }
3436 
3437 /**
3438  * Check if a word is a pointer or reference variable type.
3439  *
3440  * @return        whether word is a pointer or reference variable.
3441  */
3442 bool ASFormatter::isPointerOrReferenceVariable(const string& word) const
3443 {
3444     return (word == "char"
3445             || word == "int"
3446             || word == "void"
3447             || (word.length() >= 6     // check end of word for _t
3448                 && word.compare(word.length() - 2, 2, "_t") == 0)
3449             || word == "INT"
3450             || word == "VOID");
3451 }
3452 
3453 /**
3454  * Check if * * is a pointer to a pointer or a multiply then a dereference.
3455  *
3456  * @return        true if a pointer *.
3457  */
3458 bool ASFormatter::isPointerToPointer(const string& line, int currPos) const
3459 {
3460     assert(line[currPos] == '*' && peekNextChar() == '*');
3461     if ((int) line.length() > currPos + 1 && line[currPos + 1] == '*')
3462         return true;
3463     size_t nextText = line.find_first_not_of(" \t", currPos + 1);
3464     if (nextText == string::npos || line[nextText] != '*')
3465         return false;
3466     size_t nextText2 = line.find_first_not_of(" \t", nextText + 1);
3467     if (nextText == string::npos)
3468         return false;
3469     if (line[nextText2] == ')' || line[nextText2] == '*')
3470         return true;
3471     return false;
3472 }
3473 
3474 /**
3475  * check if the currently reached '+' or '-' character is a unary operator
3476  * this method takes for granted that the current character
3477  * is a '+' or '-'.
3478  *
3479  * @return        whether the current '+' or '-' is a unary operator.
3480  */
3481 bool ASFormatter::isUnaryOperator() const
3482 {
3483     assert(currentChar == '+' || currentChar == '-');
3484 
3485     // does a digit follow a c-style cast
3486     if (previousCommandChar == ')')
3487     {
3488         if (!isdigit(peekNextChar()))
3489             return false;
3490         size_t end = currentLine.rfind(')', charNum);
3491         if (end == string::npos)
3492             return false;
3493         size_t lastChar = currentLine.find_last_not_of(" \t", end - 1);
3494         if (lastChar == string::npos)
3495             return false;
3496         if (currentLine[lastChar] == '*')
3497             end = lastChar;
3498         string prevWord = getPreviousWord(currentLine, end);
3499         if (prevWord.empty())
3500             return false;
3501         if (!isNumericVariable(prevWord))
3502             return false;
3503         return true;
3504     }
3505 
3506     return ((isCharImmediatelyPostReturn || !isLegalNameChar(previousCommandChar))
3507             && previousCommandChar != '.'
3508             && previousCommandChar != '\"'
3509             && previousCommandChar != '\''
3510             && previousCommandChar != ']');
3511 }
3512 
3513 /**
3514  * check if the currently reached comment is in a 'switch' statement
3515  *
3516  * @return        whether the current '+' or '-' is in an exponent.
3517  */
3518 bool ASFormatter::isInSwitchStatement() const
3519 {
3520     assert(isInLineComment || isInComment);
3521     if (!preBraceHeaderStack->empty())
3522         for (size_t i = 1; i < preBraceHeaderStack->size(); i++)
3523             if (preBraceHeaderStack->at(i) == &AS_SWITCH)
3524                 return true;
3525     return false;
3526 }
3527 
3528 /**
3529  * check if the currently reached '+' or '-' character is
3530  * part of an exponent, i.e. 0.2E-5.
3531  *
3532  * @return        whether the current '+' or '-' is in an exponent.
3533  */
3534 bool ASFormatter::isInExponent() const
3535 {
3536     assert(currentChar == '+' || currentChar == '-');
3537 
3538     if (charNum >= 2)
3539     {
3540         char prevPrevFormattedChar = currentLine[charNum - 2];
3541         char prevFormattedChar = currentLine[charNum - 1];
3542         return ((prevFormattedChar == 'e' || prevFormattedChar == 'E')
3543                 && (prevPrevFormattedChar == '.' || isDigit(prevPrevFormattedChar)));
3544     }
3545     return false;
3546 }
3547 
3548 /**
3549  * check if an array brace should NOT have an in-statement indent
3550  *
3551  * @return        the array is non in-statement
3552  */
3553 bool ASFormatter::isNonInStatementArrayBrace() const
3554 {
3555     bool returnVal = false;
3556     char nextChar = peekNextChar();
3557     // if this opening brace begins the line there will be no inStatement indent
3558     if (currentLineBeginsWithBrace
3559             && (size_t) charNum == currentLineFirstBraceNum
3560             && nextChar != '}')
3561         returnVal = true;
3562     // if an opening brace ends the line there will be no inStatement indent
3563     if (isWhiteSpace(nextChar)
3564             || isBeforeAnyLineEndComment(charNum)
3565             || nextChar == '{')
3566         returnVal = true;
3567 
3568     // Java "new Type [] {...}" IS an inStatement indent
3569     if (isJavaStyle() && previousNonWSChar == ']')
3570         returnVal = false;
3571 
3572     return returnVal;
3573 }
3574 
3575 /**
3576  * check if a one-line block has been reached,
3577  * i.e. if the currently reached '{' character is closed
3578  * with a complimentary '}' elsewhere on the current line,
3579  *.
3580  * @return     0 = one-line block has not been reached.
3581  *             1 = one-line block has been reached.
3582  *             2 = one-line block has been reached and is followed by a comma.
3583  *             3 = one-line block has been reached and is an empty block.
3584  */
3585 int ASFormatter::isOneLineBlockReached(const string& line, int startChar) const
3586 {
3587     assert(line[startChar] == '{');
3588 
3589     bool isInComment_ = false;
3590     bool isInQuote_ = false;
3591     bool hasText = false;
3592     int braceCount = 0;
3593     int lineLength = line.length();
3594     char quoteChar_ = ' ';
3595     char ch = ' ';
3596     char prevCh = ' ';
3597 
3598     for (int i = startChar; i < lineLength; ++i)
3599     {
3600         ch = line[i];
3601 
3602         if (isInComment_)
3603         {
3604             if (line.compare(i, 2, "*/") == 0)
3605             {
3606                 isInComment_ = false;
3607                 ++i;
3608             }
3609             continue;
3610         }
3611 
3612         if (isInQuote_)
3613         {
3614             if (ch == '\\')
3615                 ++i;
3616             else if (ch == quoteChar_)
3617                 isInQuote_ = false;
3618             continue;
3619         }
3620 
3621         if (ch == '"'
3622                 || (ch == '\'' && !isDigitSeparator(line, i)))
3623         {
3624             isInQuote_ = true;
3625             quoteChar_ = ch;
3626             continue;
3627         }
3628 
3629         if (line.compare(i, 2, "//") == 0)
3630             break;
3631 
3632         if (line.compare(i, 2, "/*") == 0)
3633         {
3634             isInComment_ = true;
3635             ++i;
3636             continue;
3637         }
3638 
3639         if (ch == '{')
3640         {
3641             ++braceCount;
3642             continue;
3643         }
3644         if (ch == '}')
3645         {
3646             --braceCount;
3647             if (braceCount == 0)
3648             {
3649                 // is this an array?
3650                 if (parenStack->back() == 0 && prevCh != '}')
3651                 {
3652                     size_t peekNum = line.find_first_not_of(" \t", i + 1);
3653                     if (peekNum != string::npos && line[peekNum] == ',')
3654                         return 2;
3655                 }
3656                 if (!hasText)
3657                     return 3;   // is an empty block
3658                 return 1;
3659             }
3660         }
3661         if (ch == ';')
3662             continue;
3663         if (!isWhiteSpace(ch))
3664         {
3665             hasText = true;
3666             prevCh = ch;
3667         }
3668     }
3669 
3670     return 0;
3671 }
3672 
3673 /**
3674  * peek at the next word to determine if it is a C# non-paren header.
3675  * will look ahead in the input file if necessary.
3676  *
3677  * @param  startChar      position on currentLine to start the search
3678  * @return                true if the next word is get or set.
3679  */
3680 bool ASFormatter::isNextWordSharpNonParenHeader(int startChar) const
3681 {
3682     // look ahead to find the next non-comment text
3683     string nextText = peekNextText(currentLine.substr(startChar));
3684     if (nextText.length() == 0)
3685         return false;
3686     if (nextText[0] == '[')
3687         return true;
3688     if (!isCharPotentialHeader(nextText, 0))
3689         return false;
3690     if (findKeyword(nextText, 0, AS_GET) || findKeyword(nextText, 0, AS_SET)
3691             || findKeyword(nextText, 0, AS_ADD) || findKeyword(nextText, 0, AS_REMOVE))
3692         return true;
3693     return false;
3694 }
3695 
3696 /**
3697  * peek at the next char to determine if it is an opening brace.
3698  * will look ahead in the input file if necessary.
3699  * this determines a java static constructor.
3700  *
3701  * @param startChar     position on currentLine to start the search
3702  * @return              true if the next word is an opening brace.
3703  */
3704 bool ASFormatter::isNextCharOpeningBrace(int startChar) const
3705 {
3706     bool retVal = false;
3707     string nextText = peekNextText(currentLine.substr(startChar));
3708     if (nextText.length() > 0
3709             && nextText.compare(0, 1, "{") == 0)
3710         retVal = true;
3711     return retVal;
3712 }
3713 
3714 /**
3715 * Check if operator and, pointer, and reference padding is disabled.
3716 * Disabling is done thru a NOPAD tag in an ending comment.
3717 *
3718 * @return              true if the formatting on this line is disabled.
3719 */
3720 bool ASFormatter::isOperatorPaddingDisabled() const
3721 {
3722     size_t commentStart = currentLine.find("//", charNum);
3723     if (commentStart == string::npos)
3724     {
3725         commentStart = currentLine.find("/*", charNum);
3726         // comment must end on this line
3727         if (commentStart != string::npos)
3728         {
3729             size_t commentEnd = currentLine.find("*/", commentStart + 2);
3730             if (commentEnd == string::npos)
3731                 commentStart = string::npos;
3732         }
3733     }
3734     if (commentStart == string::npos)
3735         return false;
3736     size_t noPadStart = currentLine.find("*NOPAD*", commentStart);
3737     if (noPadStart == string::npos)
3738         return false;
3739     return true;
3740 }
3741 
3742 /**
3743 * Determine if an opening array-type brace should have a leading space pad.
3744 * This is to identify C++11 uniform initializers.
3745 */
3746 bool ASFormatter::isUniformInitializerBrace() const
3747 {
3748     if (isCStyle() && !isInEnum && !isImmediatelyPostPreprocessor)
3749     {
3750         if (isInClassInitializer
3751                 || isLegalNameChar(previousNonWSChar)
3752                 || previousNonWSChar == '(')
3753             return true;
3754     }
3755     return false;
3756 }
3757 
3758 /**
3759 * Determine if there is a following statement on the current line.
3760 */
3761 bool ASFormatter::isMultiStatementLine() const
3762 {
3763     assert((isImmediatelyPostHeader || foundClosingHeader));
3764     bool isInComment_ = false;
3765     bool isInQuote_ = false;
3766     int  semiCount_ = 0;
3767     int  parenCount_ = 0;
3768     int  braceCount_ = 0;
3769 
3770     for (size_t i = 0; i < currentLine.length(); i++)
3771     {
3772         if (isInComment_)
3773         {
3774             if (currentLine.compare(i, 2, "*/") == 0)
3775             {
3776                 isInComment_ = false;
3777                 continue;
3778             }
3779         }
3780         if (currentLine.compare(i, 2, "/*") == 0)
3781         {
3782             isInComment_ = true;
3783             continue;
3784         }
3785         if (currentLine.compare(i, 2, "//") == 0)
3786             return false;
3787         if (isInQuote_)
3788         {
3789             if (currentLine[i] == '"' || currentLine[i] == '\'')
3790                 isInQuote_ = false;
3791             continue;
3792         }
3793         if (currentLine[i] == '"' || currentLine[i] == '\'')
3794         {
3795             isInQuote_ = true;
3796             continue;
3797         }
3798         if (currentLine[i] == '(')
3799         {
3800             ++parenCount_;
3801             continue;
3802         }
3803         if (currentLine[i] == ')')
3804         {
3805             --parenCount_;
3806             continue;
3807         }
3808         if (parenCount_ > 0)
3809             continue;
3810         if (currentLine[i] == '{')
3811         {
3812             ++braceCount_;
3813         }
3814         if (currentLine[i] == '}')
3815         {
3816             --braceCount_;
3817         }
3818         if (braceCount_ > 0)
3819             continue;
3820         if (currentLine[i] == ';')
3821         {
3822             ++semiCount_;
3823             if (semiCount_ > 1)
3824                 return true;
3825             continue;
3826         }
3827     }
3828     return false;
3829 }
3830 
3831 /**
3832  * get the next non-whitespace substring on following lines, bypassing all comments.
3833  *
3834  * @param   firstLine   the first line to check
3835  * @return  the next non-whitespace substring.
3836  */
3837 string ASFormatter::peekNextText(const string& firstLine,
3838                                  bool endOnEmptyLine /*false*/,
3839                                  shared_ptr<ASPeekStream> streamArg /*nullptr*/) const
3840 {
3841     assert(sourceIterator->getPeekStart() == 0 || streamArg != nullptr);    // Borland may need != 0
3842     bool isFirstLine = true;
3843     string nextLine_ = firstLine;
3844     size_t firstChar = string::npos;
3845     shared_ptr<ASPeekStream> stream = streamArg;
3846     if (stream == nullptr)                  // Borland may need == 0
3847         stream = make_shared<ASPeekStream>(sourceIterator);
3848 
3849     // find the first non-blank text, bypassing all comments.
3850     bool isInComment_ = false;
3851     while (stream->hasMoreLines() || isFirstLine)
3852     {
3853         if (isFirstLine)
3854             isFirstLine = false;
3855         else
3856             nextLine_ = stream->peekNextLine();
3857 
3858         firstChar = nextLine_.find_first_not_of(" \t");
3859         if (firstChar == string::npos)
3860         {
3861             if (endOnEmptyLine && !isInComment_)
3862                 break;
3863             continue;
3864         }
3865 
3866         if (nextLine_.compare(firstChar, 2, "/*") == 0)
3867         {
3868             firstChar += 2;
3869             isInComment_ = true;
3870         }
3871 
3872         if (isInComment_)
3873         {
3874             firstChar = nextLine_.find("*/", firstChar);
3875             if (firstChar == string::npos)
3876                 continue;
3877             firstChar += 2;
3878             isInComment_ = false;
3879             firstChar = nextLine_.find_first_not_of(" \t", firstChar);
3880             if (firstChar == string::npos)
3881                 continue;
3882         }
3883 
3884         if (nextLine_.compare(firstChar, 2, "//") == 0)
3885             continue;
3886 
3887         // found the next text
3888         break;
3889     }
3890 
3891     if (firstChar == string::npos)
3892         nextLine_ = "";
3893     else
3894         nextLine_ = nextLine_.substr(firstChar);
3895     return nextLine_;
3896 }
3897 
3898 /**
3899  * adjust comment position because of adding or deleting spaces
3900  * the spaces are added or deleted to formattedLine
3901  * spacePadNum contains the adjustment
3902  */
3903 void ASFormatter::adjustComments()
3904 {
3905     assert(spacePadNum != 0);
3906     assert(isSequenceReached("//") || isSequenceReached("/*"));
3907 
3908     // block comment must be closed on this line with nothing after it
3909     if (isSequenceReached("/*"))
3910     {
3911         size_t endNum = currentLine.find("*/", charNum + 2);
3912         if (endNum == string::npos)
3913             return;
3914         // following line comments may be a tag from AStyleWx //[[)>
3915         size_t nextNum = currentLine.find_first_not_of(" \t", endNum + 2);
3916         if (nextNum != string::npos
3917                 && currentLine.compare(nextNum, 2, "//") != 0)
3918             return;
3919     }
3920 
3921     size_t len = formattedLine.length();
3922     // don't adjust a tab
3923     if (formattedLine[len - 1] == '\t')
3924         return;
3925     // if spaces were removed, need to add spaces before the comment
3926     if (spacePadNum < 0)
3927     {
3928         int adjust = -spacePadNum;          // make the number positive
3929         formattedLine.append(adjust, ' ');
3930     }
3931     // if spaces were added, need to delete extra spaces before the comment
3932     // if cannot be done put the comment one space after the last text
3933     else if (spacePadNum > 0)
3934     {
3935         int adjust = spacePadNum;
3936         size_t lastText = formattedLine.find_last_not_of(' ');
3937         if (lastText != string::npos
3938                 && lastText < len - adjust - 1)
3939             formattedLine.resize(len - adjust);
3940         else if (len > lastText + 2)
3941             formattedLine.resize(lastText + 2);
3942         else if (len < lastText + 2)
3943             formattedLine.append(len - lastText, ' ');
3944     }
3945 }
3946 
3947 /**
3948  * append the current brace inside the end of line comments
3949  * currentChar contains the brace, it will be appended to formattedLine
3950  * formattedLineCommentNum is the comment location on formattedLine
3951  */
3952 void ASFormatter::appendCharInsideComments()
3953 {
3954     if (formattedLineCommentNum == string::npos     // does the comment start on the previous line?
3955             || formattedLineCommentNum == 0)
3956     {
3957         appendCurrentChar();                        // don't attach
3958         return;
3959     }
3960     assert(formattedLine.compare(formattedLineCommentNum, 2, "//") == 0
3961            || formattedLine.compare(formattedLineCommentNum, 2, "/*") == 0);
3962 
3963     // find the previous non space char
3964     size_t end = formattedLineCommentNum;
3965     size_t beg = formattedLine.find_last_not_of(" \t", end - 1);
3966     if (beg == string::npos)
3967     {
3968         appendCurrentChar();                // don't attach
3969         return;
3970     }
3971     beg++;
3972 
3973     // insert the brace
3974     if (end - beg < 3)                      // is there room to insert?
3975         formattedLine.insert(beg, 3 - end + beg, ' ');
3976     if (formattedLine[beg] == '\t')         // don't pad with a tab
3977         formattedLine.insert(beg, 1, ' ');
3978     formattedLine[beg + 1] = currentChar;
3979     testForTimeToSplitFormattedLine();
3980 
3981     if (isBeforeComment())
3982         breakLine();
3983     else if (isCharImmediatelyPostLineComment)
3984         shouldBreakLineAtNextChar = true;
3985 }
3986 
3987 /**
3988  * add or remove space padding to operators
3989  * the operators and necessary padding will be appended to formattedLine
3990  * the calling function should have a continue statement after calling this method
3991  *
3992  * @param newOperator     the operator to be padded
3993  */
3994 void ASFormatter::padOperators(const string* newOperator)
3995 {
3996     assert(shouldPadOperators);
3997     assert(newOperator != nullptr);
3998 
3999     char nextNonWSChar = ASBase::peekNextChar(currentLine, charNum);
4000     bool shouldPad = (newOperator != &AS_SCOPE_RESOLUTION
4001                       && newOperator != &AS_PLUS_PLUS
4002                       && newOperator != &AS_MINUS_MINUS
4003                       && newOperator != &AS_NOT
4004                       && newOperator != &AS_BIT_NOT
4005                       && newOperator != &AS_ARROW
4006                       && !(newOperator == &AS_COLON && !foundQuestionMark           // objC methods
4007                            && (isInObjCMethodDefinition || isInObjCInterface
4008                                || isInObjCSelector || squareBracketCount != 0))
4009                       && !(newOperator == &AS_MINUS && isInExponent())
4010                       && !(newOperator == &AS_PLUS && isInExponent())
4011                       && !((newOperator == &AS_PLUS || newOperator == &AS_MINUS)    // check for unary plus or minus
4012                            && (previousNonWSChar == '('
4013                                || previousNonWSChar == '['
4014                                || previousNonWSChar == '='
4015                                || previousNonWSChar == ','
4016                                || previousNonWSChar == ':'
4017                                || previousNonWSChar == '{'))
4018 //?                   // commented out in release 2.05.1 - doesn't seem to do anything???
4019 //x                   && !((newOperator == &AS_MULT || newOperator == &AS_BIT_AND || newOperator == &AS_AND)
4020 //x                        && isPointerOrReference())
4021                       && !(newOperator == &AS_MULT
4022                            && (previousNonWSChar == '.'
4023                                || previousNonWSChar == '>'))    // check for ->
4024                       && !(newOperator == &AS_MULT && peekNextChar() == '>')
4025                       && !((isInTemplate || isImmediatelyPostTemplate)
4026                            && (newOperator == &AS_LS || newOperator == &AS_GR))
4027                       && !(newOperator == &AS_GCC_MIN_ASSIGN
4028                            && ASBase::peekNextChar(currentLine, charNum + 1) == '>')
4029                       && !(newOperator == &AS_GR && previousNonWSChar == '?')
4030                       && !(newOperator == &AS_QUESTION          // check for Java wildcard
4031                            && isJavaStyle()
4032                            && (previousNonWSChar == '<'
4033                                || nextNonWSChar == '>'
4034                                || nextNonWSChar == '.'))
4035                       && !(newOperator == &AS_QUESTION          // check for C# null conditional operator
4036                            && isSharpStyle()
4037                            && (nextNonWSChar == '.'
4038                                || nextNonWSChar == '['))
4039                       && !isCharImmediatelyPostOperator
4040                       && !isInCase
4041                       && !isInAsm
4042                       && !isInAsmOneLine
4043                       && !isInAsmBlock
4044                      );
4045 
4046     // pad before operator
4047     if (shouldPad
4048             && !(newOperator == &AS_COLON
4049                  && (!foundQuestionMark && !isInEnum) && currentHeader != &AS_FOR)
4050             && !(newOperator == &AS_QUESTION && isSharpStyle() // check for C# nullable type (e.g. int?)
4051                  && currentLine.find(':', charNum + 1) == string::npos)
4052        )
4053         appendSpacePad();
4054     appendOperator(*newOperator);
4055     goForward(newOperator->length() - 1);
4056 
4057     currentChar = (*newOperator)[newOperator->length() - 1];
4058     // pad after operator
4059     // but do not pad after a '-' that is a unary-minus.
4060     if (shouldPad
4061             && !isBeforeAnyComment()
4062             && !(newOperator == &AS_PLUS && isUnaryOperator())
4063             && !(newOperator == &AS_MINUS && isUnaryOperator())
4064             && !(currentLine.compare(charNum + 1, 1, AS_SEMICOLON) == 0)
4065             && !(currentLine.compare(charNum + 1, 2, AS_SCOPE_RESOLUTION) == 0)
4066             && !(peekNextChar() == ',')
4067             && !(newOperator == &AS_QUESTION && isSharpStyle() // check for C# nullable type (e.g. int?)
4068                  && peekNextChar() == '[')
4069        )
4070         appendSpaceAfter();
4071 }
4072 
4073 /**
4074  * format pointer or reference
4075  * currentChar contains the pointer or reference
4076  * the symbol and necessary padding will be appended to formattedLine
4077  * the calling function should have a continue statement after calling this method
4078  *
4079  * NOTE: Do NOT use appendCurrentChar() in this method. The line should not be
4080  *       broken once the calculation starts.
4081  */
4082 void ASFormatter::formatPointerOrReference()
4083 {
4084     assert(currentChar == '*' || currentChar == '&' || currentChar == '^');
4085     assert(!isJavaStyle());
4086 
4087     int pa = pointerAlignment;
4088     int ra = referenceAlignment;
4089     int itemAlignment = (currentChar == '*' || currentChar == '^')
4090                         ? pa : ((ra == REF_SAME_AS_PTR) ? pa : ra);
4091 
4092     // check for ** and &&
4093     int ptrLength = 1;
4094     char peekedChar = peekNextChar();
4095     if ((currentChar == '*' && peekedChar == '*')
4096             || (currentChar == '&' && peekedChar == '&'))
4097     {
4098         ptrLength = 2;
4099         size_t nextChar = currentLine.find_first_not_of(" \t", charNum + 2);
4100         if (nextChar == string::npos)
4101             peekedChar = ' ';
4102         else
4103             peekedChar = currentLine[nextChar];
4104     }
4105     // check for cast
4106     if (peekedChar == ')' || peekedChar == '>' || peekedChar == ',')
4107     {
4108         formatPointerOrReferenceCast();
4109         return;
4110     }
4111 
4112     // check for a padded space and remove it
4113     if (charNum > 0
4114             && !isWhiteSpace(currentLine[charNum - 1])
4115             && formattedLine.length() > 0
4116             && isWhiteSpace(formattedLine[formattedLine.length() - 1]))
4117     {
4118         formattedLine.erase(formattedLine.length() - 1);
4119         spacePadNum--;
4120     }
4121 
4122     if (itemAlignment == PTR_ALIGN_TYPE)
4123     {
4124         formatPointerOrReferenceToType();
4125     }
4126     else if (itemAlignment == PTR_ALIGN_MIDDLE)
4127     {
4128         formatPointerOrReferenceToMiddle();
4129     }
4130     else if (itemAlignment == PTR_ALIGN_NAME)
4131     {
4132         formatPointerOrReferenceToName();
4133     }
4134     else    // pointerAlignment == PTR_ALIGN_NONE
4135     {
4136         formattedLine.append(currentLine.substr(charNum, ptrLength));
4137         if (ptrLength > 1)
4138             goForward(ptrLength - 1);
4139     }
4140 }
4141 
4142 /**
4143  * format pointer or reference with align to type
4144  */
4145 void ASFormatter::formatPointerOrReferenceToType()
4146 {
4147     assert(currentChar == '*' || currentChar == '&' || currentChar == '^');
4148     assert(!isJavaStyle());
4149 
4150     // do this before bumping charNum
4151     bool isOldPRCentered = isPointerOrReferenceCentered();
4152     string sequenceToInsert(1, currentChar);
4153     // get the sequence
4154     if (currentChar == peekNextChar())
4155     {
4156         for (size_t i = charNum + 1; currentLine.length() > i; i++)
4157         {
4158             if (currentLine[i] == sequenceToInsert[0])
4159             {
4160                 sequenceToInsert.append(1, currentLine[i]);
4161                 goForward(1);
4162                 continue;
4163             }
4164             break;
4165         }
4166     }
4167     // append the seqence
4168     string charSave;
4169     size_t prevCh = formattedLine.find_last_not_of(" \t");
4170     if (prevCh < formattedLine.length())
4171     {
4172         charSave = formattedLine.substr(prevCh + 1);
4173         formattedLine.resize(prevCh + 1);
4174     }
4175     formattedLine.append(sequenceToInsert);
4176     if (peekNextChar() != ')')
4177         formattedLine.append(charSave);
4178     else
4179         spacePadNum -= charSave.length();
4180     // if no space after then add one
4181     if (charNum < (int) currentLine.length() - 1
4182             && !isWhiteSpace(currentLine[charNum + 1])
4183             && currentLine[charNum + 1] != ')')
4184         appendSpacePad();
4185     // if old pointer or reference is centered, remove a space
4186     if (isOldPRCentered
4187             && isWhiteSpace(formattedLine[formattedLine.length() - 1]))
4188     {
4189         formattedLine.erase(formattedLine.length() - 1, 1);
4190         spacePadNum--;
4191     }
4192     // update the formattedLine split point
4193     if (maxCodeLength != string::npos && formattedLine.length() > 0)
4194     {
4195         size_t index = formattedLine.length() - 1;
4196         if (isWhiteSpace(formattedLine[index]))
4197         {
4198             updateFormattedLineSplitPointsPointerOrReference(index);
4199             testForTimeToSplitFormattedLine();
4200         }
4201     }
4202 }
4203 
4204 /**
4205  * format pointer or reference with align in the middle
4206  */
4207 void ASFormatter::formatPointerOrReferenceToMiddle()
4208 {
4209     assert(currentChar == '*' || currentChar == '&' || currentChar == '^');
4210     assert(!isJavaStyle());
4211 
4212     // compute current whitespace before
4213     size_t wsBefore = currentLine.find_last_not_of(" \t", charNum - 1);
4214     if (wsBefore == string::npos)
4215         wsBefore = 0;
4216     else
4217         wsBefore = charNum - wsBefore - 1;
4218     string sequenceToInsert(1, currentChar);
4219     if (currentChar == peekNextChar())
4220     {
4221         for (size_t i = charNum + 1; currentLine.length() > i; i++)
4222         {
4223             if (currentLine[i] == sequenceToInsert[0])
4224             {
4225                 sequenceToInsert.append(1, currentLine[i]);
4226                 goForward(1);
4227                 continue;
4228             }
4229             break;
4230         }
4231     }
4232     // if reference to a pointer check for conflicting alignment
4233     else if (currentChar == '*' && peekNextChar() == '&'
4234              && (referenceAlignment == REF_ALIGN_TYPE
4235                  || referenceAlignment == REF_ALIGN_MIDDLE
4236                  || referenceAlignment == REF_SAME_AS_PTR))
4237     {
4238         sequenceToInsert = "*&";
4239         goForward(1);
4240         for (size_t i = charNum; i < currentLine.length() - 1 && isWhiteSpace(currentLine[i]); i++)
4241             goForward(1);
4242     }
4243     // if a comment follows don't align, just space pad
4244     if (isBeforeAnyComment())
4245     {
4246         appendSpacePad();
4247         formattedLine.append(sequenceToInsert);
4248         appendSpaceAfter();
4249         return;
4250     }
4251     // do this before goForward()
4252     bool isAfterScopeResolution = previousNonWSChar == ':';
4253     size_t charNumSave = charNum;
4254     // if this is the last thing on the line
4255     if (currentLine.find_first_not_of(" \t", charNum + 1) == string::npos)
4256     {
4257         if (wsBefore == 0 && !isAfterScopeResolution)
4258             formattedLine.append(1, ' ');
4259         formattedLine.append(sequenceToInsert);
4260         return;
4261     }
4262     // goForward() to convert tabs to spaces, if necessary,
4263     // and move following characters to preceding characters
4264     // this may not work every time with tab characters
4265     for (size_t i = charNum + 1; i < currentLine.length() && isWhiteSpace(currentLine[i]); i++)
4266     {
4267         goForward(1);
4268         if (formattedLine.length() > 0)
4269             formattedLine.append(1, currentLine[i]);
4270         else
4271             spacePadNum--;
4272     }
4273     // find space padding after
4274     size_t wsAfter = currentLine.find_first_not_of(" \t", charNumSave + 1);
4275     if (wsAfter == string::npos || isBeforeAnyComment())
4276         wsAfter = 0;
4277     else
4278         wsAfter = wsAfter - charNumSave - 1;
4279     // don't pad before scope resolution operator, but pad after
4280     if (isAfterScopeResolution)
4281     {
4282         size_t lastText = formattedLine.find_last_not_of(" \t");
4283         formattedLine.insert(lastText + 1, sequenceToInsert);
4284         appendSpacePad();
4285     }
4286     else if (formattedLine.length() > 0)
4287     {
4288         // whitespace should be at least 2 chars to center
4289         if (wsBefore + wsAfter < 2)
4290         {
4291             size_t charsToAppend = (2 - (wsBefore + wsAfter));
4292             formattedLine.append(charsToAppend, ' ');
4293             spacePadNum += charsToAppend;
4294             if (wsBefore == 0)
4295                 wsBefore++;
4296             if (wsAfter == 0)
4297                 wsAfter++;
4298         }
4299         // insert the pointer or reference char
4300         size_t padAfter = (wsBefore + wsAfter) / 2;
4301         size_t index = formattedLine.length() - padAfter;
4302         if (index < formattedLine.length())
4303             formattedLine.insert(index, sequenceToInsert);
4304         else
4305             formattedLine.append(sequenceToInsert);
4306     }
4307     else    // formattedLine.length() == 0
4308     {
4309         formattedLine.append(sequenceToInsert);
4310         if (wsAfter == 0)
4311             wsAfter++;
4312         formattedLine.append(wsAfter, ' ');
4313         spacePadNum += wsAfter;
4314     }
4315     // update the formattedLine split point after the pointer
4316     if (maxCodeLength != string::npos && formattedLine.length() > 0)
4317     {
4318         size_t index = formattedLine.find_last_not_of(" \t");
4319         if (index != string::npos && (index < formattedLine.length() - 1))
4320         {
4321             index++;
4322             updateFormattedLineSplitPointsPointerOrReference(index);
4323             testForTimeToSplitFormattedLine();
4324         }
4325     }
4326 }
4327 
4328 /**
4329  * format pointer or reference with align to name
4330  */
4331 void ASFormatter::formatPointerOrReferenceToName()
4332 {
4333     assert(currentChar == '*' || currentChar == '&' || currentChar == '^');
4334     assert(!isJavaStyle());
4335 
4336     // do this before bumping charNum
4337     bool isOldPRCentered = isPointerOrReferenceCentered();
4338 
4339     size_t startNum = formattedLine.find_last_not_of(" \t");
4340     if (startNum == string::npos)
4341         startNum = 0;
4342     string sequenceToInsert(1, currentChar);
4343     if (currentChar == peekNextChar())
4344     {
4345         for (size_t i = charNum + 1; currentLine.length() > i; i++)
4346         {
4347             if (currentLine[i] == sequenceToInsert[0])
4348             {
4349                 sequenceToInsert.append(1, currentLine[i]);
4350                 goForward(1);
4351                 continue;
4352             }
4353             break;
4354         }
4355     }
4356     // if reference to a pointer align both to name
4357     else if (currentChar == '*' && peekNextChar() == '&')
4358     {
4359         sequenceToInsert = "*&";
4360         goForward(1);
4361         for (size_t i = charNum; i < currentLine.length() - 1 && isWhiteSpace(currentLine[i]); i++)
4362             goForward(1);
4363     }
4364     char peekedChar = peekNextChar();
4365     bool isAfterScopeResolution = previousNonWSChar == ':';     // check for ::
4366     // if this is not the last thing on the line
4367     if ((isLegalNameChar(peekedChar) || peekedChar == '(' || peekedChar == '[' || peekedChar == '=')
4368             && (int) currentLine.find_first_not_of(" \t", charNum + 1) > charNum)
4369     {
4370         // goForward() to convert tabs to spaces, if necessary,
4371         // and move following characters to preceding characters
4372         // this may not work every time with tab characters
4373         for (size_t i = charNum + 1; i < currentLine.length() && isWhiteSpace(currentLine[i]); i++)
4374         {
4375             // if a padded paren follows don't move
4376             if (shouldPadParensOutside && peekedChar == '(' && !isOldPRCentered)
4377             {
4378                 // empty parens don't count
4379                 size_t start = currentLine.find_first_not_of("( \t", i);
4380                 if (start != string::npos && currentLine[start] != ')')
4381                     break;
4382             }
4383             goForward(1);
4384             if (formattedLine.length() > 0)
4385                 formattedLine.append(1, currentLine[charNum]);
4386             else
4387                 spacePadNum--;
4388         }
4389     }
4390     // don't pad before scope resolution operator
4391     if (isAfterScopeResolution)
4392     {
4393         size_t lastText = formattedLine.find_last_not_of(" \t");
4394         if (lastText != string::npos && lastText + 1 < formattedLine.length())
4395             formattedLine.erase(lastText + 1);
4396     }
4397     // if no space before * then add one
4398     else if (formattedLine.length() > 0
4399              && (formattedLine.length() <= startNum + 1
4400                  || !isWhiteSpace(formattedLine[startNum + 1])))
4401     {
4402         formattedLine.insert(startNum + 1, 1, ' ');
4403         spacePadNum++;
4404     }
4405     appendSequence(sequenceToInsert, false);
4406     // if old pointer or reference is centered, remove a space
4407     if (isOldPRCentered
4408             && formattedLine.length() > startNum + 1
4409             && isWhiteSpace(formattedLine[startNum + 1])
4410             && peekedChar != '*'        // check for '* *'
4411             && !isBeforeAnyComment())
4412     {
4413         formattedLine.erase(startNum + 1, 1);
4414         spacePadNum--;
4415     }
4416     // don't convert to *= or &=
4417     if (peekedChar == '=')
4418     {
4419         appendSpaceAfter();
4420         // if more than one space before, delete one
4421         if (formattedLine.length() > startNum
4422                 && isWhiteSpace(formattedLine[startNum + 1])
4423                 && isWhiteSpace(formattedLine[startNum + 2]))
4424         {
4425             formattedLine.erase(startNum + 1, 1);
4426             spacePadNum--;
4427         }
4428     }
4429     // update the formattedLine split point
4430     if (maxCodeLength != string::npos)
4431     {
4432         size_t index = formattedLine.find_last_of(" \t");
4433         if (index != string::npos
4434                 && index < formattedLine.length() - 1
4435                 && (formattedLine[index + 1] == '*'
4436                     || formattedLine[index + 1] == '&'
4437                     || formattedLine[index + 1] == '^'))
4438         {
4439             updateFormattedLineSplitPointsPointerOrReference(index);
4440             testForTimeToSplitFormattedLine();
4441         }
4442     }
4443 }
4444 
4445 /**
4446  * format pointer or reference cast
4447  * currentChar contains the pointer or reference
4448  * NOTE: the pointers and references in function definitions
4449  *       are processed as a cast (e.g. void foo(void*, void*))
4450  *       is processed here.
4451  */
4452 void ASFormatter::formatPointerOrReferenceCast()
4453 {
4454     assert(currentChar == '*' || currentChar == '&' || currentChar == '^');
4455     assert(!isJavaStyle());
4456 
4457     int pa = pointerAlignment;
4458     int ra = referenceAlignment;
4459     int itemAlignment = (currentChar == '*' || currentChar == '^')
4460                         ? pa : ((ra == REF_SAME_AS_PTR) ? pa : ra);
4461 
4462     string sequenceToInsert(1, currentChar);
4463     if (isSequenceReached("**") || isSequenceReached("&&"))
4464     {
4465         goForward(1);
4466         sequenceToInsert.append(1, currentLine[charNum]);
4467     }
4468     if (itemAlignment == PTR_ALIGN_NONE)
4469     {
4470         appendSequence(sequenceToInsert, false);
4471         return;
4472     }
4473     // remove preceding whitespace
4474     char prevCh = ' ';
4475     size_t prevNum = formattedLine.find_last_not_of(" \t");
4476     if (prevNum != string::npos)
4477     {
4478         prevCh = formattedLine[prevNum];
4479         if (itemAlignment == PTR_ALIGN_TYPE && currentChar == '*' && prevCh == '*')
4480         {
4481             // '* *' may be a multiply followed by a dereference
4482             if (prevNum + 2 < formattedLine.length()
4483                     && isWhiteSpace(formattedLine[prevNum + 2]))
4484             {
4485                 spacePadNum -= (formattedLine.length() - 2 - prevNum);
4486                 formattedLine.erase(prevNum + 2);
4487             }
4488         }
4489         else if (prevNum + 1 < formattedLine.length()
4490                  && isWhiteSpace(formattedLine[prevNum + 1])
4491                  && prevCh != '(')
4492         {
4493             spacePadNum -= (formattedLine.length() - 1 - prevNum);
4494             formattedLine.erase(prevNum + 1);
4495         }
4496     }
4497     bool isAfterScopeResolution = previousNonWSChar == ':';
4498     if ((itemAlignment == PTR_ALIGN_MIDDLE || itemAlignment == PTR_ALIGN_NAME)
4499             && !isAfterScopeResolution && prevCh != '(')
4500     {
4501         appendSpacePad();
4502         // in this case appendSpacePad may or may not update the split point
4503         if (maxCodeLength != string::npos && formattedLine.length() > 0)
4504             updateFormattedLineSplitPointsPointerOrReference(formattedLine.length() - 1);
4505         appendSequence(sequenceToInsert, false);
4506     }
4507     else
4508         appendSequence(sequenceToInsert, false);
4509 }
4510 
4511 /**
4512  * add or remove space padding to parens
4513  * currentChar contains the paren
4514  * the parens and necessary padding will be appended to formattedLine
4515  * the calling function should have a continue statement after calling this method
4516  */
4517 void ASFormatter::padParens()
4518 {
4519     assert(currentChar == '(' || currentChar == ')');
4520     assert(shouldPadParensOutside || shouldPadParensInside || shouldUnPadParens || shouldPadFirstParen);
4521 
4522     int spacesOutsideToDelete = 0;
4523     int spacesInsideToDelete = 0;
4524 
4525     if (currentChar == '(')
4526     {
4527         spacesOutsideToDelete = formattedLine.length() - 1;
4528         spacesInsideToDelete = 0;
4529 
4530         // compute spaces outside the opening paren to delete
4531         if (shouldUnPadParens)
4532         {
4533             char lastChar = ' ';
4534             bool prevIsParenHeader = false;
4535             size_t i = formattedLine.find_last_not_of(" \t");
4536             if (i != string::npos)
4537             {
4538                 // if last char is a brace the previous whitespace is an indent
4539                 if (formattedLine[i] == '{')
4540                     spacesOutsideToDelete = 0;
4541                 else if (isCharImmediatelyPostPointerOrReference)
4542                     spacesOutsideToDelete = 0;
4543                 else
4544                 {
4545                     spacesOutsideToDelete -= i;
4546                     lastChar = formattedLine[i];
4547                     // if previous word is a header, it will be a paren header
4548                     string prevWord = getPreviousWord(formattedLine, formattedLine.length());
4549                     const string* prevWordH = nullptr;
4550                     if (shouldPadHeader
4551                             && prevWord.length() > 0
4552                             && isCharPotentialHeader(prevWord, 0))
4553                         prevWordH = ASBase::findHeader(prevWord, 0, headers);
4554                     if (prevWordH != nullptr)
4555                         prevIsParenHeader = true;    // don't unpad
4556                     else if (prevWord == AS_RETURN)
4557                         prevIsParenHeader = true;    // don't unpad
4558                     else if ((prevWord == AS_NEW || prevWord == AS_DELETE)
4559                              && shouldPadHeader)
4560                         prevIsParenHeader = true;    // don't unpad
4561                     else if (isCStyle() && prevWord == AS_THROW && shouldPadHeader)
4562                         prevIsParenHeader = true;    // don't unpad
4563                     else if (prevWord == "and" || prevWord == "or" || prevWord == "in")
4564                         prevIsParenHeader = true;    // don't unpad
4565                     // don't unpad variables
4566                     else if (isNumericVariable(prevWord))
4567                         prevIsParenHeader = true;    // don't unpad
4568                 }
4569             }
4570             // do not unpad operators, but leave them if already padded
4571             if (shouldPadParensOutside || prevIsParenHeader)
4572                 spacesOutsideToDelete--;
4573             else if (lastChar == '|'          // check for ||
4574                      || lastChar == '&'       // check for &&
4575                      || lastChar == ','
4576                      || (lastChar == '(' && shouldPadParensInside)
4577                      || (lastChar == '>' && !foundCastOperator)
4578                      || lastChar == '<'
4579                      || lastChar == '?'
4580                      || lastChar == ':'
4581                      || lastChar == ';'
4582                      || lastChar == '='
4583                      || lastChar == '+'
4584                      || lastChar == '-'
4585                      || lastChar == '*'
4586                      || lastChar == '/'
4587                      || lastChar == '%'
4588                      || lastChar == '^'
4589                     )
4590                 spacesOutsideToDelete--;
4591 
4592             if (spacesOutsideToDelete > 0)
4593             {
4594                 formattedLine.erase(i + 1, spacesOutsideToDelete);
4595                 spacePadNum -= spacesOutsideToDelete;
4596             }
4597         }
4598 
4599         // pad open paren outside
4600         char peekedCharOutside = peekNextChar();
4601         if (shouldPadFirstParen && previousChar != '(' && peekedCharOutside != ')')
4602             appendSpacePad();
4603         else if (shouldPadParensOutside)
4604         {
4605             if (!(currentChar == '(' && peekedCharOutside == ')'))
4606                 appendSpacePad();
4607         }
4608 
4609         appendCurrentChar();
4610 
4611         // unpad open paren inside
4612         if (shouldUnPadParens)
4613         {
4614             size_t j = currentLine.find_first_not_of(" \t", charNum + 1);
4615             if (j != string::npos)
4616                 spacesInsideToDelete = j - charNum - 1;
4617             if (shouldPadParensInside)
4618                 spacesInsideToDelete--;
4619             if (spacesInsideToDelete > 0)
4620             {
4621                 currentLine.erase(charNum + 1, spacesInsideToDelete);
4622                 spacePadNum -= spacesInsideToDelete;
4623             }
4624             // convert tab to space if requested
4625             if (shouldConvertTabs
4626                     && (int) currentLine.length() > charNum + 1
4627                     && currentLine[charNum + 1] == '\t')
4628                 currentLine[charNum + 1] = ' ';
4629         }
4630 
4631         // pad open paren inside
4632         char peekedCharInside = peekNextChar();
4633         if (shouldPadParensInside)
4634             if (!(currentChar == '(' && peekedCharInside == ')'))
4635                 appendSpaceAfter();
4636     }
4637     else if (currentChar == ')')
4638     {
4639         // unpad close paren inside
4640         if (shouldUnPadParens)
4641         {
4642             spacesInsideToDelete = formattedLine.length();
4643             size_t i = formattedLine.find_last_not_of(" \t");
4644             if (i != string::npos)
4645                 spacesInsideToDelete = formattedLine.length() - 1 - i;
4646             if (shouldPadParensInside)
4647                 spacesInsideToDelete--;
4648             if (spacesInsideToDelete > 0)
4649             {
4650                 formattedLine.erase(i + 1, spacesInsideToDelete);
4651                 spacePadNum -= spacesInsideToDelete;
4652             }
4653         }
4654 
4655         // pad close paren inside
4656         if (shouldPadParensInside)
4657             if (!(previousChar == '(' && currentChar == ')'))
4658                 appendSpacePad();
4659 
4660         appendCurrentChar();
4661 
4662         // unpad close paren outside
4663         // close parens outside are left unchanged
4664         if (shouldUnPadParens)
4665         {
4666             //spacesOutsideToDelete = 0;
4667             //size_t j = currentLine.find_first_not_of(" \t", charNum + 1);
4668             //if (j != string::npos)
4669             //  spacesOutsideToDelete = j - charNum - 1;
4670             //if (shouldPadParensOutside)
4671             //  spacesOutsideToDelete--;
4672 
4673             //if (spacesOutsideToDelete > 0)
4674             //{
4675             //  currentLine.erase(charNum + 1, spacesOutsideToDelete);
4676             //  spacePadNum -= spacesOutsideToDelete;
4677             //}
4678         }
4679 
4680         // pad close paren outside
4681         char peekedCharOutside = peekNextChar();
4682         if (shouldPadParensOutside)
4683             if (peekedCharOutside != ';'
4684                     && peekedCharOutside != ','
4685                     && peekedCharOutside != '.'
4686                     && peekedCharOutside != '+'    // check for ++
4687                     && peekedCharOutside != '-'    // check for --
4688                     && peekedCharOutside != ']')
4689                 appendSpaceAfter();
4690     }
4691 }
4692 
4693 /**
4694 * add or remove space padding to objective-c method prefix (- or +)
4695 * if this is a '(' it begins a return type
4696 * these options have precedence over the padParens methods
4697 * the padParens method has already been called, this method adjusts
4698 */
4699 void ASFormatter::padObjCMethodPrefix()
4700 {
4701     assert(isInObjCMethodDefinition && isImmediatelyPostObjCMethodPrefix);
4702     assert(shouldPadMethodPrefix || shouldUnPadMethodPrefix);
4703 
4704     size_t prefix = formattedLine.find_first_of("+-");
4705     if (prefix == string::npos)
4706         return;
4707     size_t firstChar = formattedLine.find_first_not_of(" \t", prefix + 1);
4708     if (firstChar == string::npos)
4709         firstChar = formattedLine.length();
4710     int spaces = firstChar - prefix - 1;
4711 
4712     if (shouldPadMethodPrefix)
4713     {
4714         if (spaces == 0)
4715         {
4716             formattedLine.insert(prefix + 1, 1, ' ');
4717             spacePadNum += 1;
4718         }
4719         else if (spaces > 1)
4720         {
4721             formattedLine.erase(prefix + 1, spaces - 1);
4722             formattedLine[prefix + 1] = ' ';  // convert any tab to space
4723             spacePadNum -= spaces - 1;
4724         }
4725     }
4726     // this option will be ignored if used with pad-method-prefix
4727     else if (shouldUnPadMethodPrefix)
4728     {
4729         if (spaces > 0)
4730         {
4731             formattedLine.erase(prefix + 1, spaces);
4732             spacePadNum -= spaces;
4733         }
4734     }
4735 }
4736 
4737 /**
4738 * add or remove space padding to objective-c parens
4739 * these options have precedence over the padParens methods
4740 * the padParens method has already been called, this method adjusts
4741 */
4742 void ASFormatter::padObjCReturnType()
4743 {
4744     assert(currentChar == ')' && isInObjCReturnType);
4745     assert(shouldPadReturnType || shouldUnPadReturnType);
4746 
4747     size_t nextText = currentLine.find_first_not_of(" \t", charNum + 1);
4748     if (nextText == string::npos)
4749         return;
4750     int spaces = nextText - charNum - 1;
4751 
4752     if (shouldPadReturnType)
4753     {
4754         if (spaces == 0)
4755         {
4756             // this will already be padded if pad-paren is used
4757             if (formattedLine[formattedLine.length() - 1] != ' ')
4758             {
4759                 formattedLine.append(" ");
4760                 spacePadNum += 1;
4761             }
4762         }
4763         else if (spaces > 1)
4764         {
4765             // do not use goForward here
4766             currentLine.erase(charNum + 1, spaces - 1);
4767             currentLine[charNum + 1] = ' ';  // convert any tab to space
4768             spacePadNum -= spaces - 1;
4769         }
4770     }
4771     // this option will be ignored if used with pad-return-type
4772     else if (shouldUnPadReturnType)
4773     {
4774         // this will already be padded if pad-paren is used
4775         if (formattedLine[formattedLine.length() - 1] == ' ')
4776         {
4777             int lastText = formattedLine.find_last_not_of(" \t");
4778             spacePadNum -= formattedLine.length() - lastText - 1;
4779             formattedLine.resize(lastText + 1);
4780         }
4781         // do not use goForward here
4782         currentLine.erase(charNum + 1, spaces);
4783         spacePadNum -= spaces;
4784     }
4785 }
4786 
4787 /**
4788 * add or remove space padding to objective-c parens
4789 * these options have precedence over the padParens methods
4790 * the padParens method has already been called, this method adjusts
4791 */
4792 void ASFormatter::padObjCParamType()
4793 {
4794     assert((currentChar == '(' || currentChar == ')') && isInObjCMethodDefinition);
4795     assert(!isImmediatelyPostObjCMethodPrefix && !isInObjCReturnType);
4796     assert(shouldPadParamType || shouldUnPadParamType);
4797 
4798     if (currentChar == '(')
4799     {
4800         // open paren has already been attached to formattedLine by padParen
4801         size_t paramOpen = formattedLine.rfind('(');
4802         assert(paramOpen != string::npos);
4803         size_t prevText = formattedLine.find_last_not_of(" \t", paramOpen - 1);
4804         if (prevText == string::npos)
4805             return;
4806         int spaces = paramOpen - prevText - 1;
4807 
4808         if (shouldPadParamType
4809                 || objCColonPadMode == COLON_PAD_ALL
4810                 || objCColonPadMode == COLON_PAD_AFTER)
4811         {
4812             if (spaces == 0)
4813             {
4814                 formattedLine.insert(paramOpen, 1, ' ');
4815                 spacePadNum += 1;
4816             }
4817             if (spaces > 1)
4818             {
4819                 formattedLine.erase(prevText + 1, spaces - 1);
4820                 formattedLine[prevText + 1] = ' ';  // convert any tab to space
4821                 spacePadNum -= spaces - 1;
4822             }
4823         }
4824         // this option will be ignored if used with pad-param-type
4825         else if (shouldUnPadParamType
4826                  || objCColonPadMode == COLON_PAD_NONE
4827                  || objCColonPadMode == COLON_PAD_BEFORE)
4828         {
4829             if (spaces > 0)
4830             {
4831                 formattedLine.erase(prevText + 1, spaces);
4832                 spacePadNum -= spaces;
4833             }
4834         }
4835     }
4836     else if (currentChar == ')')
4837     {
4838         size_t nextText = currentLine.find_first_not_of(" \t", charNum + 1);
4839         if (nextText == string::npos)
4840             return;
4841         int spaces = nextText - charNum - 1;
4842 
4843         if (shouldPadParamType)
4844         {
4845             if (spaces == 0)
4846             {
4847                 // this will already be padded if pad-paren is used
4848                 if (formattedLine[formattedLine.length() - 1] != ' ')
4849                 {
4850                     formattedLine.append(" ");
4851                     spacePadNum += 1;
4852                 }
4853             }
4854             else if (spaces > 1)
4855             {
4856                 // do not use goForward here
4857                 currentLine.erase(charNum + 1, spaces - 1);
4858                 currentLine[charNum + 1] = ' ';  // convert any tab to space
4859                 spacePadNum -= spaces - 1;
4860             }
4861         }
4862         // this option will be ignored if used with pad-param-type
4863         else if (shouldUnPadParamType)
4864         {
4865             // this will already be padded if pad-paren is used
4866             if (formattedLine[formattedLine.length() - 1] == ' ')
4867             {
4868                 spacePadNum -= 1;
4869                 int lastText = formattedLine.find_last_not_of(" \t");
4870                 formattedLine.resize(lastText + 1);
4871             }
4872             if (spaces > 0)
4873             {
4874                 // do not use goForward here
4875                 currentLine.erase(charNum + 1, spaces);
4876                 spacePadNum -= spaces;
4877             }
4878         }
4879     }
4880 }
4881 
4882 /**
4883  * format opening brace as attached or broken
4884  * currentChar contains the brace
4885  * the braces will be appended to the current formattedLine or a new formattedLine as necessary
4886  * the calling function should have a continue statement after calling this method
4887  *
4888  * @param braceType    the type of brace to be formatted.
4889  */
4890 void ASFormatter::formatOpeningBrace(BraceType braceType)
4891 {
4892     assert(!isBraceType(braceType, ARRAY_TYPE));
4893     assert(currentChar == '{');
4894 
4895     parenStack->emplace_back(0);
4896 
4897     bool breakBrace = isCurrentBraceBroken();
4898 
4899     if (breakBrace)
4900     {
4901         if (isBeforeAnyComment() && isOkToBreakBlock(braceType) && sourceIterator->hasMoreLines())
4902         {
4903             // if comment is at line end leave the comment on this line
4904             if (isBeforeAnyLineEndComment(charNum) && !currentLineBeginsWithBrace)
4905             {
4906                 currentChar = ' ';              // remove brace from current line
4907                 if (parenStack->size() > 1)
4908                     parenStack->pop_back();
4909                 currentLine[charNum] = currentChar;
4910                 appendOpeningBrace = true;      // append brace to following line
4911             }
4912             // else put comment after the brace
4913             else if (!isBeforeMultipleLineEndComments(charNum))
4914                 breakLine();
4915         }
4916         else if (!isBraceType(braceType, SINGLE_LINE_TYPE))
4917         {
4918             formattedLine = rtrim(formattedLine);
4919             breakLine();
4920         }
4921         else if ((shouldBreakOneLineBlocks || isBraceType(braceType, BREAK_BLOCK_TYPE))
4922                  && !isBraceType(braceType, EMPTY_BLOCK_TYPE))
4923             breakLine();
4924         else if (!isInLineBreak)
4925             appendSpacePad();
4926 
4927         appendCurrentChar();
4928 
4929         // should a following comment break from the brace?
4930         // must break the line AFTER the brace
4931         if (isBeforeComment()
4932                 && formattedLine.length() > 0
4933                 && formattedLine[0] == '{'
4934                 && isOkToBreakBlock(braceType)
4935                 && (braceFormatMode == BREAK_MODE
4936                     || braceFormatMode == LINUX_MODE))
4937         {
4938             shouldBreakLineAtNextChar = true;
4939         }
4940     }
4941     else    // attach brace
4942     {
4943         // are there comments before the brace?
4944         if (isCharImmediatelyPostComment || isCharImmediatelyPostLineComment)
4945         {
4946             if (isOkToBreakBlock(braceType)
4947                     && !(isCharImmediatelyPostComment && isCharImmediatelyPostLineComment)  // don't attach if two comments on the line
4948                     && !isImmediatelyPostPreprocessor
4949 //                  && peekNextChar() != '}'        // don't attach { }     // removed release 2.03
4950                     && previousCommandChar != '{'   // don't attach { {
4951                     && previousCommandChar != '}'   // don't attach } {
4952                     && previousCommandChar != ';')  // don't attach ; {
4953             {
4954                 appendCharInsideComments();
4955             }
4956             else
4957             {
4958                 appendCurrentChar();                // don't attach
4959             }
4960         }
4961         else if (previousCommandChar == '{'
4962                  || (previousCommandChar == '}' && !isInClassInitializer)
4963                  || previousCommandChar == ';')     // '}' , ';' chars added for proper handling of '{' immediately after a '}' or ';'
4964         {
4965             appendCurrentChar();                    // don't attach
4966         }
4967         else
4968         {
4969             // if a blank line precedes this don't attach
4970             if (isEmptyLine(formattedLine))
4971                 appendCurrentChar();                // don't attach
4972             else if (isOkToBreakBlock(braceType)
4973                      && !(isImmediatelyPostPreprocessor
4974                           && currentLineBeginsWithBrace))
4975             {
4976                 if (!isBraceType(braceType, EMPTY_BLOCK_TYPE))
4977                 {
4978                     appendSpacePad();
4979                     appendCurrentChar(false);               // OK to attach
4980                     testForTimeToSplitFormattedLine();      // line length will have changed
4981                     // should a following comment attach with the brace?
4982                     // insert spaces to reposition the comment
4983                     if (isBeforeComment()
4984                             && !isBeforeMultipleLineEndComments(charNum)
4985                             && (!isBeforeAnyLineEndComment(charNum) || currentLineBeginsWithBrace))
4986                     {
4987                         shouldBreakLineAtNextChar = true;
4988                         currentLine.insert(charNum + 1, charNum + 1, ' ');
4989                     }
4990                     else if (!isBeforeAnyComment())     // added in release 2.03
4991                     {
4992                         shouldBreakLineAtNextChar = true;
4993                     }
4994                 }
4995                 else
4996                 {
4997                     if (currentLineBeginsWithBrace && (size_t) charNum == currentLineFirstBraceNum)
4998                     {
4999                         appendSpacePad();
5000                         appendCurrentChar(false);       // attach
5001                         shouldBreakLineAtNextChar = true;
5002                     }
5003                     else
5004                     {
5005                         appendSpacePad();
5006                         appendCurrentChar();        // don't attach
5007                     }
5008                 }
5009             }
5010             else
5011             {
5012                 if (!isInLineBreak)
5013                     appendSpacePad();
5014                 appendCurrentChar();                // don't attach
5015             }
5016         }
5017     }
5018 }
5019 
5020 /**
5021  * format closing brace
5022  * currentChar contains the brace
5023  * the calling function should have a continue statement after calling this method
5024  *
5025  * @param braceType    the type of the opening brace for this closing brace.
5026  */
5027 void ASFormatter::formatClosingBrace(BraceType braceType)
5028 {
5029     assert(!isBraceType(braceType, ARRAY_TYPE));
5030     assert(currentChar == '}');
5031 
5032     // parenStack must contain one entry
5033     if (parenStack->size() > 1)
5034         parenStack->pop_back();
5035 
5036     // mark state of immediately after empty block
5037     // this state will be used for locating braces that appear immediately AFTER an empty block (e.g. '{} \n}').
5038     if (previousCommandChar == '{')
5039         isImmediatelyPostEmptyBlock = true;
5040 
5041     if (attachClosingBraceMode)
5042     {
5043         // for now, namespaces and classes will be attached. Uncomment the lines below to break.
5044         if ((isEmptyLine(formattedLine)         // if a blank line precedes this
5045                 || isCharImmediatelyPostLineComment
5046                 || isCharImmediatelyPostComment
5047                 || (isImmediatelyPostPreprocessor && (int) currentLine.find_first_not_of(" \t") == charNum)
5048 //              || (isBraceType(braceType, CLASS_TYPE) && isOkToBreakBlock(braceType) && previousNonWSChar != '{')
5049 //              || (isBraceType(braceType, NAMESPACE_TYPE) && isOkToBreakBlock(braceType) && previousNonWSChar != '{')
5050             )
5051                 && (!isBraceType(braceType, SINGLE_LINE_TYPE) || isOkToBreakBlock(braceType)))
5052         {
5053             breakLine();
5054             appendCurrentChar();                // don't attach
5055         }
5056         else
5057         {
5058             if (previousNonWSChar != '{'
5059                     && (!isBraceType(braceType, SINGLE_LINE_TYPE)
5060                         || isOkToBreakBlock(braceType)))
5061                 appendSpacePad();
5062             appendCurrentChar(false);           // attach
5063         }
5064     }
5065     else if (!isBraceType(braceType, EMPTY_BLOCK_TYPE)
5066              && (isBraceType(braceType, BREAK_BLOCK_TYPE)
5067                  || isOkToBreakBlock(braceType)))
5068     {
5069         breakLine();
5070         appendCurrentChar();
5071     }
5072     else
5073     {
5074         appendCurrentChar();
5075     }
5076 
5077     // if a declaration follows a definition, space pad
5078     if (isLegalNameChar(peekNextChar()))
5079         appendSpaceAfter();
5080 
5081     if (shouldBreakBlocks
5082             && currentHeader != nullptr
5083             && !isHeaderInMultiStatementLine
5084             && parenStack->back() == 0)
5085     {
5086         if (currentHeader == &AS_CASE || currentHeader == &AS_DEFAULT)
5087         {
5088             // do not yet insert a line if "break" statement is outside the braces
5089             string nextText = peekNextText(currentLine.substr(charNum + 1));
5090             if (nextText.length() > 0
5091                     && nextText.substr(0, 5) != "break")
5092                 isAppendPostBlockEmptyLineRequested = true;
5093         }
5094         else
5095             isAppendPostBlockEmptyLineRequested = true;
5096     }
5097 }
5098 
5099 /**
5100  * format array braces as attached or broken
5101  * determine if the braces can have an inStatement indent
5102  * currentChar contains the brace
5103  * the braces will be appended to the current formattedLine or a new formattedLine as necessary
5104  * the calling function should have a continue statement after calling this method
5105  *
5106  * @param braceType            the type of brace to be formatted, must be an ARRAY_TYPE.
5107  * @param isOpeningArrayBrace  indicates if this is the opening brace for the array block.
5108  */
5109 void ASFormatter::formatArrayBraces(BraceType braceType, bool isOpeningArrayBrace)
5110 {
5111     assert(isBraceType(braceType, ARRAY_TYPE));
5112     assert(currentChar == '{' || currentChar == '}');
5113 
5114     if (currentChar == '{')
5115     {
5116         // is this the first opening brace in the array?
5117         if (isOpeningArrayBrace)
5118         {
5119             if (braceFormatMode == ATTACH_MODE
5120                     || braceFormatMode == LINUX_MODE)
5121             {
5122                 // break an enum if mozilla
5123                 if (isBraceType(braceType, ENUM_TYPE)
5124                         && formattingStyle == STYLE_MOZILLA)
5125                 {
5126                     isInLineBreak = true;
5127                     appendCurrentChar();                // don't attach
5128                 }
5129                 // don't attach to a preprocessor directive or '\' line
5130                 else if ((isImmediatelyPostPreprocessor
5131                           || (formattedLine.length() > 0
5132                               && formattedLine[formattedLine.length() - 1] == '\\'))
5133                          && currentLineBeginsWithBrace)
5134                 {
5135                     isInLineBreak = true;
5136                     appendCurrentChar();                // don't attach
5137                 }
5138                 else if (isCharImmediatelyPostComment)
5139                 {
5140                     // TODO: attach brace to line-end comment
5141                     appendCurrentChar();                // don't attach
5142                 }
5143                 else if (isCharImmediatelyPostLineComment && !isBraceType(braceType, SINGLE_LINE_TYPE))
5144                 {
5145                     appendCharInsideComments();
5146                 }
5147                 else
5148                 {
5149                     // if a blank line precedes this don't attach
5150                     if (isEmptyLine(formattedLine))
5151                         appendCurrentChar();            // don't attach
5152                     else
5153                     {
5154                         // if brace is broken or not an assignment
5155                         if (currentLineBeginsWithBrace
5156                                 && !isBraceType(braceType, SINGLE_LINE_TYPE))
5157                         {
5158                             appendSpacePad();
5159                             appendCurrentChar(false);               // OK to attach
5160                             // TODO: debug the following line
5161                             testForTimeToSplitFormattedLine();      // line length will have changed
5162 
5163                             if (currentLineBeginsWithBrace
5164                                     && currentLineFirstBraceNum == (size_t) charNum)
5165                                 shouldBreakLineAtNextChar = true;
5166                         }
5167                         else
5168                         {
5169                             if (previousNonWSChar != '(')
5170                             {
5171                                 // don't space pad C++11 uniform initialization
5172                                 if (!isBraceType(braceType, INIT_TYPE))
5173                                     appendSpacePad();
5174                             }
5175                             appendCurrentChar();
5176                         }
5177                     }
5178                 }
5179             }
5180             else if (braceFormatMode == BREAK_MODE)
5181             {
5182                 if (isWhiteSpace(peekNextChar()) && !isInVirginLine)
5183                     breakLine();
5184                 else if (isBeforeAnyComment() && sourceIterator->hasMoreLines())
5185                 {
5186                     // do not break unless comment is at line end
5187                     if (isBeforeAnyLineEndComment(charNum) && !currentLineBeginsWithBrace)
5188                     {
5189                         currentChar = ' ';            // remove brace from current line
5190                         appendOpeningBrace = true;    // append brace to following line
5191                     }
5192                 }
5193                 if (!isInLineBreak && previousNonWSChar != '(')
5194                 {
5195                     // don't space pad C++11 uniform initialization
5196                     if (!isBraceType(braceType, INIT_TYPE))
5197                         appendSpacePad();
5198                 }
5199                 appendCurrentChar();
5200 
5201                 if (currentLineBeginsWithBrace
5202                         && currentLineFirstBraceNum == (size_t) charNum
5203                         && !isBraceType(braceType, SINGLE_LINE_TYPE))
5204                     shouldBreakLineAtNextChar = true;
5205             }
5206             else if (braceFormatMode == RUN_IN_MODE)
5207             {
5208                 if (isWhiteSpace(peekNextChar()) && !isInVirginLine)
5209                     breakLine();
5210                 else if (isBeforeAnyComment() && sourceIterator->hasMoreLines())
5211                 {
5212                     // do not break unless comment is at line end
5213                     if (isBeforeAnyLineEndComment(charNum) && !currentLineBeginsWithBrace)
5214                     {
5215                         currentChar = ' ';            // remove brace from current line
5216                         appendOpeningBrace = true;    // append brace to following line
5217                     }
5218                 }
5219                 if (!isInLineBreak && previousNonWSChar != '(')
5220                 {
5221                     // don't space pad C++11 uniform initialization
5222                     if (!isBraceType(braceType, INIT_TYPE))
5223                         appendSpacePad();
5224                 }
5225                 appendCurrentChar();
5226             }
5227             else if (braceFormatMode == NONE_MODE)
5228             {
5229                 if (currentLineBeginsWithBrace
5230                         && (size_t) charNum == currentLineFirstBraceNum)
5231                 {
5232                     appendCurrentChar();                // don't attach
5233                 }
5234                 else
5235                 {
5236                     if (previousNonWSChar != '(')
5237                     {
5238                         // don't space pad C++11 uniform initialization
5239                         if (!isBraceType(braceType, INIT_TYPE))
5240                             appendSpacePad();
5241                     }
5242                     appendCurrentChar(false);           // OK to attach
5243                 }
5244             }
5245         }
5246         else         // not the first opening brace
5247         {
5248             if (braceFormatMode == RUN_IN_MODE)
5249             {
5250                 if (previousNonWSChar == '{'
5251                         && braceTypeStack->size() > 2
5252                         && !isBraceType((*braceTypeStack)[braceTypeStack->size() - 2],
5253                                         SINGLE_LINE_TYPE))
5254                     formatArrayRunIn();
5255             }
5256             else if (!isInLineBreak
5257                      && !isWhiteSpace(peekNextChar())
5258                      && previousNonWSChar == '{'
5259                      && braceTypeStack->size() > 2
5260                      && !isBraceType((*braceTypeStack)[braceTypeStack->size() - 2],
5261                                      SINGLE_LINE_TYPE))
5262                 formatArrayRunIn();
5263 
5264             appendCurrentChar();
5265         }
5266     }
5267     else if (currentChar == '}')
5268     {
5269         if (attachClosingBraceMode)
5270         {
5271             if (isEmptyLine(formattedLine)          // if a blank line precedes this
5272                     || isImmediatelyPostPreprocessor
5273                     || isCharImmediatelyPostLineComment
5274                     || isCharImmediatelyPostComment)
5275                 appendCurrentChar();                // don't attach
5276             else
5277             {
5278                 appendSpacePad();
5279                 appendCurrentChar(false);           // attach
5280             }
5281         }
5282         else
5283         {
5284             // does this close the first opening brace in the array?
5285             // must check if the block is still a single line because of anonymous statements
5286             if (!isBraceType(braceType, INIT_TYPE)
5287                     && (!isBraceType(braceType, SINGLE_LINE_TYPE)
5288                         || formattedLine.find('{') == string::npos))
5289                 breakLine();
5290             appendCurrentChar();
5291         }
5292 
5293         // if a declaration follows an enum definition, space pad
5294         char peekedChar = peekNextChar();
5295         if ((isLegalNameChar(peekedChar) && peekedChar != '.')
5296                 || peekedChar == '[')
5297             appendSpaceAfter();
5298     }
5299 }
5300 
5301 /**
5302  * determine if a run-in can be attached.
5303  * if it can insert the indents in formattedLine and reset the current line break.
5304  */
5305 void ASFormatter::formatRunIn()
5306 {
5307     assert(braceFormatMode == RUN_IN_MODE || braceFormatMode == NONE_MODE);
5308 
5309     // keep one line blocks returns true without indenting the run-in
5310     if (formattingStyle != STYLE_PICO
5311             && !isOkToBreakBlock(braceTypeStack->back()))
5312         return; // true;
5313 
5314     // make sure the line begins with a brace
5315     size_t lastText = formattedLine.find_last_not_of(" \t");
5316     if (lastText == string::npos || formattedLine[lastText] != '{')
5317         return; // false;
5318 
5319     // make sure the brace is broken
5320     if (formattedLine.find_first_not_of(" \t{") != string::npos)
5321         return; // false;
5322 
5323     if (isBraceType(braceTypeStack->back(), NAMESPACE_TYPE))
5324         return; // false;
5325 
5326     bool extraIndent = false;
5327     bool extraHalfIndent = false;
5328     isInLineBreak = true;
5329 
5330     // cannot attach a class modifier without indent-classes
5331     if (isCStyle()
5332             && isCharPotentialHeader(currentLine, charNum)
5333             && (isBraceType(braceTypeStack->back(), CLASS_TYPE)
5334                 || (isBraceType(braceTypeStack->back(), STRUCT_TYPE)
5335                     && isInIndentableStruct)))
5336     {
5337         if (findKeyword(currentLine, charNum, AS_PUBLIC)
5338                 || findKeyword(currentLine, charNum, AS_PRIVATE)
5339                 || findKeyword(currentLine, charNum, AS_PROTECTED))
5340         {
5341             if (getModifierIndent())
5342                 extraHalfIndent = true;
5343             else if (!getClassIndent())
5344                 return; // false;
5345         }
5346         else if (getClassIndent())
5347             extraIndent = true;
5348     }
5349 
5350     // cannot attach a 'case' statement without indent-switches
5351     if (!getSwitchIndent()
5352             && isCharPotentialHeader(currentLine, charNum)
5353             && (findKeyword(currentLine, charNum, AS_CASE)
5354                 || findKeyword(currentLine, charNum, AS_DEFAULT)))
5355         return; // false;
5356 
5357     // extra indent for switch statements
5358     if (getSwitchIndent()
5359             && !preBraceHeaderStack->empty()
5360             && preBraceHeaderStack->back() == &AS_SWITCH
5361             && ((isLegalNameChar(currentChar)
5362                  && !findKeyword(currentLine, charNum, AS_CASE))))
5363         extraIndent = true;
5364 
5365     isInLineBreak = false;
5366     // remove for extra whitespace
5367     if (formattedLine.length() > lastText + 1
5368             && formattedLine.find_first_not_of(" \t", lastText + 1) == string::npos)
5369         formattedLine.erase(lastText + 1);
5370 
5371     if (extraHalfIndent)
5372     {
5373         int indentLength_ = getIndentLength();
5374         runInIndentChars = indentLength_ / 2;
5375         formattedLine.append(runInIndentChars - 1, ' ');
5376     }
5377     else if (getForceTabIndentation() && getIndentLength() != getTabLength())
5378     {
5379         // insert the space indents
5380         string indent;
5381         int indentLength_ = getIndentLength();
5382         int tabLength_ = getTabLength();
5383         indent.append(indentLength_, ' ');
5384         if (extraIndent)
5385             indent.append(indentLength_, ' ');
5386         // replace spaces indents with tab indents
5387         size_t tabCount = indent.length() / tabLength_;     // truncate extra spaces
5388         indent.replace(0U, tabCount * tabLength_, tabCount, '\t');
5389         runInIndentChars = indentLength_;
5390         if (indent[0] == ' ')           // allow for brace
5391             indent.erase(0, 1);
5392         formattedLine.append(indent);
5393     }
5394     else if (getIndentString() == "\t")
5395     {
5396         appendChar('\t', false);
5397         runInIndentChars = 2;   // one for { and one for tab
5398         if (extraIndent)
5399         {
5400             appendChar('\t', false);
5401             runInIndentChars++;
5402         }
5403     }
5404     else // spaces
5405     {
5406         int indentLength_ = getIndentLength();
5407         formattedLine.append(indentLength_ - 1, ' ');
5408         runInIndentChars = indentLength_;
5409         if (extraIndent)
5410         {
5411             formattedLine.append(indentLength_, ' ');
5412             runInIndentChars += indentLength_;
5413         }
5414     }
5415     isInBraceRunIn = true;
5416 }
5417 
5418 /**
5419  * remove whitespace and add indentation for an array run-in.
5420  */
5421 void ASFormatter::formatArrayRunIn()
5422 {
5423     assert(isBraceType(braceTypeStack->back(), ARRAY_TYPE));
5424 
5425     // make sure the brace is broken
5426     if (formattedLine.find_first_not_of(" \t{") != string::npos)
5427         return;
5428 
5429     size_t lastText = formattedLine.find_last_not_of(" \t");
5430     if (lastText == string::npos || formattedLine[lastText] != '{')
5431         return;
5432 
5433     // check for extra whitespace
5434     if (formattedLine.length() > lastText + 1
5435             && formattedLine.find_first_not_of(" \t", lastText + 1) == string::npos)
5436         formattedLine.erase(lastText + 1);
5437 
5438     if (getIndentString() == "\t")
5439     {
5440         appendChar('\t', false);
5441         runInIndentChars = 2;   // one for { and one for tab
5442     }
5443     else
5444     {
5445         int indent = getIndentLength();
5446         formattedLine.append(indent - 1, ' ');
5447         runInIndentChars = indent;
5448     }
5449     isInBraceRunIn = true;
5450     isInLineBreak = false;
5451 }
5452 
5453 /**
5454  * delete a braceTypeStack vector object
5455  * BraceTypeStack did not work with the DeleteContainer template
5456  */
5457 void ASFormatter::deleteContainer(vector<BraceType>*& container)
5458 {
5459     if (container != nullptr)
5460     {
5461         container->clear();
5462         delete (container);
5463         container = nullptr;
5464     }
5465 }
5466 
5467 /**
5468  * delete a vector object
5469  * T is the type of vector
5470  * used for all vectors except braceTypeStack
5471  */
5472 template<typename T>
5473 void ASFormatter::deleteContainer(T& container)
5474 {
5475     if (container != nullptr)
5476     {
5477         container->clear();
5478         delete (container);
5479         container = nullptr;
5480     }
5481 }
5482 
5483 /**
5484  * initialize a braceType vector object
5485  * braceType did not work with the DeleteContainer template
5486  */
5487 void ASFormatter::initContainer(vector<BraceType>*& container, vector<BraceType>* value)
5488 {
5489     if (container != nullptr)
5490         deleteContainer(container);
5491     container = value;
5492 }
5493 
5494 /**
5495  * initialize a vector object
5496  * T is the type of vector
5497  * used for all vectors except braceTypeStack
5498  */
5499 template<typename T>
5500 void ASFormatter::initContainer(T& container, T value)
5501 {
5502     // since the ASFormatter object is never deleted,
5503     // the existing vectors must be deleted before creating new ones
5504     if (container != nullptr)
5505         deleteContainer(container);
5506     container = value;
5507 }
5508 
5509 /**
5510  * convert a tab to spaces.
5511  * charNum points to the current character to convert to spaces.
5512  * tabIncrementIn is the increment that must be added for tab indent characters
5513  *     to get the correct column for the current tab.
5514  * replaces the tab in currentLine with the required number of spaces.
5515  * replaces the value of currentChar.
5516  */
5517 void ASFormatter::convertTabToSpaces()
5518 {
5519     assert(currentChar == '\t');
5520 
5521     // do NOT replace if in quotes
5522     if (isInQuote || isInQuoteContinuation)
5523         return;
5524 
5525     size_t tabSize = getTabLength();
5526     size_t numSpaces = tabSize - ((tabIncrementIn + charNum) % tabSize);
5527     currentLine.replace(charNum, 1, numSpaces, ' ');
5528     currentChar = currentLine[charNum];
5529 }
5530 
5531 /**
5532 * is it ok to break this block?
5533 */
5534 bool ASFormatter::isOkToBreakBlock(BraceType braceType) const
5535 {
5536     // Actually, there should not be an ARRAY_TYPE brace here.
5537     // But this will avoid breaking a one line block when there is.
5538     // Otherwise they will be formatted differently on consecutive runs.
5539     if (isBraceType(braceType, ARRAY_TYPE)
5540             && isBraceType(braceType, SINGLE_LINE_TYPE))
5541         return false;
5542     if (isBraceType(braceType, COMMAND_TYPE)
5543             && isBraceType(braceType, EMPTY_BLOCK_TYPE))
5544         return false;
5545     if (!isBraceType(braceType, SINGLE_LINE_TYPE)
5546             || isBraceType(braceType, BREAK_BLOCK_TYPE)
5547             || shouldBreakOneLineBlocks)
5548         return true;
5549     return false;
5550 }
5551 
5552 /**
5553 * check if a sharp header is a paren or non-paren header
5554 */
5555 bool ASFormatter::isSharpStyleWithParen(const string* header) const
5556 {
5557     return (isSharpStyle() && peekNextChar() == '('
5558             && (header == &AS_CATCH
5559                 || header == &AS_DELEGATE));
5560 }
5561 
5562 /**
5563  * Check for a following header when a comment is reached.
5564  * firstLine must contain the start of the comment.
5565  * return value is a pointer to the header or nullptr.
5566  */
5567 const string* ASFormatter::checkForHeaderFollowingComment(const string& firstLine) const
5568 {
5569     assert(isInComment || isInLineComment);
5570     assert(shouldBreakElseIfs || shouldBreakBlocks || isInSwitchStatement());
5571     // look ahead to find the next non-comment text
5572     bool endOnEmptyLine = (currentHeader == nullptr);
5573     if (isInSwitchStatement())
5574         endOnEmptyLine = false;
5575     string nextText = peekNextText(firstLine, endOnEmptyLine);
5576 
5577     if (nextText.length() == 0 || !isCharPotentialHeader(nextText, 0))
5578         return nullptr;
5579 
5580     return ASBase::findHeader(nextText, 0, headers);
5581 }
5582 
5583 /**
5584  * process preprocessor statements.
5585  * charNum should be the index of the #.
5586  *
5587  * delete braceTypeStack entries added by #if if a #else is found.
5588  * prevents double entries in the braceTypeStack.
5589  */
5590 void ASFormatter::processPreprocessor()
5591 {
5592     assert(currentChar == '#');
5593 
5594     const size_t preproc = currentLine.find_first_not_of(" \t", charNum + 1);
5595 
5596     if (preproc == string::npos)
5597         return;
5598 
5599     if (currentLine.compare(preproc, 2, "if") == 0)
5600     {
5601         preprocBraceTypeStackSize = braceTypeStack->size();
5602     }
5603     else if (currentLine.compare(preproc, 4, "else") == 0)
5604     {
5605         // delete stack entries added in #if
5606         // should be replaced by #else
5607         if (preprocBraceTypeStackSize > 0)
5608         {
5609             int addedPreproc = braceTypeStack->size() - preprocBraceTypeStackSize;
5610             for (int i = 0; i < addedPreproc; i++)
5611                 braceTypeStack->pop_back();
5612         }
5613     }
5614 }
5615 
5616 /**
5617  * determine if the next line starts a comment
5618  * and a header follows the comment or comments.
5619  */
5620 bool ASFormatter::commentAndHeaderFollows()
5621 {
5622     // called ONLY IF shouldDeleteEmptyLines and shouldBreakBlocks are TRUE.
5623     assert(shouldDeleteEmptyLines && shouldBreakBlocks);
5624 
5625     // is the next line a comment
5626     auto stream = make_shared<ASPeekStream>(sourceIterator);
5627     if (!stream->hasMoreLines())
5628         return false;
5629     string nextLine_ = stream->peekNextLine();
5630     size_t firstChar = nextLine_.find_first_not_of(" \t");
5631     if (firstChar == string::npos
5632             || !(nextLine_.compare(firstChar, 2, "//") == 0
5633                  || nextLine_.compare(firstChar, 2, "/*") == 0))
5634         return false;
5635 
5636     // find the next non-comment text, and reset
5637     string nextText = peekNextText(nextLine_, false, stream);
5638     if (nextText.length() == 0 || !isCharPotentialHeader(nextText, 0))
5639         return false;
5640 
5641     const string* newHeader = ASBase::findHeader(nextText, 0, headers);
5642 
5643     if (newHeader == nullptr)
5644         return false;
5645 
5646     // if a closing header, reset break unless break is requested
5647     if (isClosingHeader(newHeader) && !shouldBreakClosingHeaderBlocks)
5648     {
5649         isAppendPostBlockEmptyLineRequested = false;
5650         return false;
5651     }
5652 
5653     return true;
5654 }
5655 
5656 /**
5657  * determine if a brace should be attached or broken
5658  * uses braces in the braceTypeStack
5659  * the last brace in the braceTypeStack is the one being formatted
5660  * returns true if the brace should be broken
5661  */
5662 bool ASFormatter::isCurrentBraceBroken() const
5663 {
5664     assert(braceTypeStack->size() > 1);
5665 
5666     bool breakBrace = false;
5667     size_t stackEnd = braceTypeStack->size() - 1;
5668 
5669     // check brace modifiers
5670     if (shouldAttachExternC
5671             && isBraceType((*braceTypeStack)[stackEnd], EXTERN_TYPE))
5672     {
5673         return false;
5674     }
5675     if (shouldAttachNamespace
5676             && isBraceType((*braceTypeStack)[stackEnd], NAMESPACE_TYPE))
5677     {
5678         return false;
5679     }
5680     if (shouldAttachClass
5681             && (isBraceType((*braceTypeStack)[stackEnd], CLASS_TYPE)
5682                 || isBraceType((*braceTypeStack)[stackEnd], INTERFACE_TYPE)))
5683     {
5684         return false;
5685     }
5686     if (shouldAttachInline
5687             && isCStyle()           // for C++ only
5688             && braceFormatMode != RUN_IN_MODE
5689             && !(currentLineBeginsWithBrace && peekNextChar() == '/')
5690             && isBraceType((*braceTypeStack)[stackEnd], COMMAND_TYPE))
5691     {
5692         size_t i;
5693         for (i = 1; i < braceTypeStack->size(); i++)
5694             if (isBraceType((*braceTypeStack)[i], CLASS_TYPE)
5695                     || isBraceType((*braceTypeStack)[i], STRUCT_TYPE))
5696                 return false;
5697     }
5698 
5699     // check braces
5700     if (isBraceType((*braceTypeStack)[stackEnd], EXTERN_TYPE))
5701     {
5702         if (currentLineBeginsWithBrace
5703                 || braceFormatMode == RUN_IN_MODE)
5704             breakBrace = true;
5705     }
5706     else if (braceFormatMode == NONE_MODE)
5707     {
5708         if (currentLineBeginsWithBrace
5709                 && currentLineFirstBraceNum == (size_t) charNum)
5710             breakBrace = true;
5711     }
5712     else if (braceFormatMode == BREAK_MODE || braceFormatMode == RUN_IN_MODE)
5713     {
5714         breakBrace = true;
5715     }
5716     else if (braceFormatMode == LINUX_MODE)
5717     {
5718         // break a namespace if NOT stroustrup or mozilla
5719         if (isBraceType((*braceTypeStack)[stackEnd], NAMESPACE_TYPE))
5720         {
5721             if (formattingStyle != STYLE_STROUSTRUP
5722                     && formattingStyle != STYLE_MOZILLA)
5723                 breakBrace = true;
5724         }
5725         // break a class or interface if NOT stroustrup
5726         else if (isBraceType((*braceTypeStack)[stackEnd], CLASS_TYPE)
5727                  || isBraceType((*braceTypeStack)[stackEnd], INTERFACE_TYPE))
5728         {
5729             if (formattingStyle != STYLE_STROUSTRUP)
5730                 breakBrace = true;
5731         }
5732         // break a struct if mozilla - an enum is processed as an array brace
5733         else if (isBraceType((*braceTypeStack)[stackEnd], STRUCT_TYPE))
5734         {
5735             if (formattingStyle == STYLE_MOZILLA)
5736                 breakBrace = true;
5737         }
5738         // break the first brace if a function
5739         else if (isBraceType((*braceTypeStack)[stackEnd], COMMAND_TYPE))
5740         {
5741             if (stackEnd == 1)
5742             {
5743                 breakBrace = true;
5744             }
5745             else if (stackEnd > 1)
5746             {
5747                 // break the first brace after these if a function
5748                 if (isBraceType((*braceTypeStack)[stackEnd - 1], NAMESPACE_TYPE)
5749                         || isBraceType((*braceTypeStack)[stackEnd - 1], CLASS_TYPE)
5750                         || isBraceType((*braceTypeStack)[stackEnd - 1], ARRAY_TYPE)
5751                         || isBraceType((*braceTypeStack)[stackEnd - 1], STRUCT_TYPE)
5752                         || isBraceType((*braceTypeStack)[stackEnd - 1], EXTERN_TYPE))
5753                 {
5754                     breakBrace = true;
5755                 }
5756             }
5757         }
5758     }
5759     return breakBrace;
5760 }
5761 
5762 /**
5763  * format comment body
5764  * the calling function should have a continue statement after calling this method
5765  */
5766 void ASFormatter::formatCommentBody()
5767 {
5768     assert(isInComment);
5769 
5770     // append the comment
5771     while (charNum < (int) currentLine.length())
5772     {
5773         currentChar = currentLine[charNum];
5774         if (isSequenceReached("*/"))
5775         {
5776             formatCommentCloser();
5777             break;
5778         }
5779         if (currentChar == '\t' && shouldConvertTabs)
5780             convertTabToSpaces();
5781         appendCurrentChar();
5782         ++charNum;
5783     }
5784     if (shouldStripCommentPrefix)
5785         stripCommentPrefix();
5786 }
5787 
5788 /**
5789  * format a comment opener
5790  * the comment opener will be appended to the current formattedLine or a new formattedLine as necessary
5791  * the calling function should have a continue statement after calling this method
5792  */
5793 void ASFormatter::formatCommentOpener()
5794 {
5795     assert(isSequenceReached("/*"));
5796 
5797     isInComment = isInCommentStartLine = true;
5798     isImmediatelyPostLineComment = false;
5799     if (previousNonWSChar == '}')
5800         resetEndOfStatement();
5801 
5802     // Check for a following header.
5803     // For speed do not check multiple comment lines more than once.
5804     // For speed do not check shouldBreakBlocks if previous line is empty, a comment, or a '{'.
5805     const string* followingHeader = nullptr;
5806     if ((doesLineStartComment
5807             && !isImmediatelyPostCommentOnly
5808             && isBraceType(braceTypeStack->back(), COMMAND_TYPE))
5809             && (shouldBreakElseIfs
5810                 || isInSwitchStatement()
5811                 || (shouldBreakBlocks
5812                     && !isImmediatelyPostEmptyLine
5813                     && previousCommandChar != '{')))
5814         followingHeader = checkForHeaderFollowingComment(currentLine.substr(charNum));
5815 
5816     if (spacePadNum != 0 && !isInLineBreak)
5817         adjustComments();
5818     formattedLineCommentNum = formattedLine.length();
5819 
5820     // must be done BEFORE appendSequence
5821     if (previousCommandChar == '{'
5822             && !isImmediatelyPostComment
5823             && !isImmediatelyPostLineComment)
5824     {
5825         if (isBraceType(braceTypeStack->back(), NAMESPACE_TYPE))
5826         {
5827             // namespace run-in is always broken.
5828             isInLineBreak = true;
5829         }
5830         else if (braceFormatMode == NONE_MODE)
5831         {
5832             // should a run-in statement be attached?
5833             if (currentLineBeginsWithBrace)
5834                 formatRunIn();
5835         }
5836         else if (braceFormatMode == ATTACH_MODE)
5837         {
5838             // if the brace was not attached?
5839             if (formattedLine.length() > 0 && formattedLine[0] == '{'
5840                     && !isBraceType(braceTypeStack->back(), SINGLE_LINE_TYPE))
5841                 isInLineBreak = true;
5842         }
5843         else if (braceFormatMode == RUN_IN_MODE)
5844         {
5845             // should a run-in statement be attached?
5846             if (formattedLine.length() > 0 && formattedLine[0] == '{')
5847                 formatRunIn();
5848         }
5849     }
5850     else if (!doesLineStartComment)
5851         noTrimCommentContinuation = true;
5852 
5853     // ASBeautifier needs to know the following statements
5854     if (shouldBreakElseIfs && followingHeader == &AS_ELSE)
5855         elseHeaderFollowsComments = true;
5856     if (followingHeader == &AS_CASE || followingHeader == &AS_DEFAULT)
5857         caseHeaderFollowsComments = true;
5858 
5859     // appendSequence will write the previous line
5860     appendSequence(AS_OPEN_COMMENT);
5861     goForward(1);
5862 
5863     // must be done AFTER appendSequence
5864 
5865     // Break before the comment if a header follows the line comment.
5866     // But not break if previous line is empty, a comment, or a '{'.
5867     if (shouldBreakBlocks
5868             && followingHeader != nullptr
5869             && !isImmediatelyPostEmptyLine
5870             && previousCommandChar != '{')
5871     {
5872         if (isClosingHeader(followingHeader))
5873         {
5874             if (!shouldBreakClosingHeaderBlocks)
5875                 isPrependPostBlockEmptyLineRequested = false;
5876         }
5877         // if an opening header, break before the comment
5878         else
5879             isPrependPostBlockEmptyLineRequested = true;
5880     }
5881 
5882     if (previousCommandChar == '}')
5883         currentHeader = nullptr;
5884 }
5885 
5886 /**
5887  * format a comment closer
5888  * the comment closer will be appended to the current formattedLine
5889  */
5890 void ASFormatter::formatCommentCloser()
5891 {
5892     assert(isSequenceReached("*/"));
5893     isInComment = false;
5894     noTrimCommentContinuation = false;
5895     isImmediatelyPostComment = true;
5896     appendSequence(AS_CLOSE_COMMENT);
5897     goForward(1);
5898     if (doesLineStartComment
5899             && (currentLine.find_first_not_of(" \t", charNum + 1) == string::npos))
5900         lineEndsInCommentOnly = true;
5901     if (peekNextChar() == '}'
5902             && previousCommandChar != ';'
5903             && !isBraceType(braceTypeStack->back(), ARRAY_TYPE)
5904             && !isInPreprocessor
5905             && isOkToBreakBlock(braceTypeStack->back()))
5906     {
5907         isInLineBreak = true;
5908         shouldBreakLineAtNextChar = true;
5909     }
5910 }
5911 
5912 /**
5913  * format a line comment body
5914  * the calling function should have a continue statement after calling this method
5915  */
5916 void ASFormatter::formatLineCommentBody()
5917 {
5918     assert(isInLineComment);
5919 
5920     // append the comment
5921     while (charNum < (int) currentLine.length())
5922 //          && !isLineReady // commented out in release 2.04, unnecessary
5923     {
5924         currentChar = currentLine[charNum];
5925         if (currentChar == '\t' && shouldConvertTabs)
5926             convertTabToSpaces();
5927         appendCurrentChar();
5928         ++charNum;
5929     }
5930 
5931     // explicitly break a line when a line comment's end is found.
5932     if (charNum == (int) currentLine.length())
5933     {
5934         isInLineBreak = true;
5935         isInLineComment = false;
5936         isImmediatelyPostLineComment = true;
5937         currentChar = 0;  //make sure it is a neutral char.
5938     }
5939 }
5940 
5941 /**
5942  * format a line comment opener
5943  * the line comment opener will be appended to the current formattedLine or a new formattedLine as necessary
5944  * the calling function should have a continue statement after calling this method
5945  */
5946 void ASFormatter::formatLineCommentOpener()
5947 {
5948     assert(isSequenceReached("//"));
5949 
5950     if ((int) currentLine.length() > charNum + 2
5951             && currentLine[charNum + 2] == '\xf2')     // check for windows line marker
5952         isAppendPostBlockEmptyLineRequested = false;
5953 
5954     isInLineComment = true;
5955     isCharImmediatelyPostComment = false;
5956     if (previousNonWSChar == '}')
5957         resetEndOfStatement();
5958 
5959     // Check for a following header.
5960     // For speed do not check multiple comment lines more than once.
5961     // For speed do not check shouldBreakBlocks if previous line is empty, a comment, or a '{'.
5962     const string* followingHeader = nullptr;
5963     if ((lineIsLineCommentOnly
5964             && !isImmediatelyPostCommentOnly
5965             && isBraceType(braceTypeStack->back(), COMMAND_TYPE))
5966             && (shouldBreakElseIfs
5967                 || isInSwitchStatement()
5968                 || (shouldBreakBlocks
5969                     && !isImmediatelyPostEmptyLine
5970                     && previousCommandChar != '{')))
5971         followingHeader = checkForHeaderFollowingComment(currentLine.substr(charNum));
5972 
5973     // do not indent if in column 1 or 2
5974     // or in a namespace before the opening brace
5975     if ((!shouldIndentCol1Comments && !lineCommentNoIndent)
5976             || foundNamespaceHeader)
5977     {
5978         if (charNum == 0)
5979             lineCommentNoIndent = true;
5980         else if (charNum == 1 && currentLine[0] == ' ')
5981             lineCommentNoIndent = true;
5982     }
5983     // move comment if spaces were added or deleted
5984     if (!lineCommentNoIndent && spacePadNum != 0 && !isInLineBreak)
5985         adjustComments();
5986     formattedLineCommentNum = formattedLine.length();
5987 
5988     // must be done BEFORE appendSequence
5989     // check for run-in statement
5990     if (previousCommandChar == '{'
5991             && !isImmediatelyPostComment
5992             && !isImmediatelyPostLineComment)
5993     {
5994         if (braceFormatMode == NONE_MODE)
5995         {
5996             if (currentLineBeginsWithBrace)
5997                 formatRunIn();
5998         }
5999         else if (braceFormatMode == RUN_IN_MODE)
6000         {
6001             if (!lineCommentNoIndent)
6002                 formatRunIn();
6003             else
6004                 isInLineBreak = true;
6005         }
6006         else if (braceFormatMode == BREAK_MODE)
6007         {
6008             if (formattedLine.length() > 0 && formattedLine[0] == '{')
6009                 isInLineBreak = true;
6010         }
6011         else
6012         {
6013             if (currentLineBeginsWithBrace)
6014                 isInLineBreak = true;
6015         }
6016     }
6017 
6018     // ASBeautifier needs to know the following statements
6019     if (shouldBreakElseIfs && followingHeader == &AS_ELSE)
6020         elseHeaderFollowsComments = true;
6021     if (followingHeader == &AS_CASE || followingHeader == &AS_DEFAULT)
6022         caseHeaderFollowsComments = true;
6023 
6024     // appendSequence will write the previous line
6025     appendSequence(AS_OPEN_LINE_COMMENT);
6026     goForward(1);
6027 
6028     // must be done AFTER appendSequence
6029 
6030     // Break before the comment if a header follows the line comment.
6031     // But do not break if previous line is empty, a comment, or a '{'.
6032     if (shouldBreakBlocks
6033             && followingHeader != nullptr
6034             && !isImmediatelyPostEmptyLine
6035             && previousCommandChar != '{')
6036     {
6037         if (isClosingHeader(followingHeader))
6038         {
6039             if (!shouldBreakClosingHeaderBlocks)
6040                 isPrependPostBlockEmptyLineRequested = false;
6041         }
6042         // if an opening header, break before the comment
6043         else
6044             isPrependPostBlockEmptyLineRequested = true;
6045     }
6046 
6047     if (previousCommandChar == '}')
6048         currentHeader = nullptr;
6049 
6050     // if tabbed input don't convert the immediately following tabs to spaces
6051     if (getIndentString() == "\t" && lineCommentNoIndent)
6052     {
6053         while (charNum + 1 < (int) currentLine.length()
6054                 && currentLine[charNum + 1] == '\t')
6055         {
6056             currentChar = currentLine[++charNum];
6057             appendCurrentChar();
6058         }
6059     }
6060 
6061     // explicitly break a line when a line comment's end is found.
6062     if (charNum + 1 == (int) currentLine.length())
6063     {
6064         isInLineBreak = true;
6065         isInLineComment = false;
6066         isImmediatelyPostLineComment = true;
6067         currentChar = 0;  //make sure it is a neutral char.
6068     }
6069 }
6070 
6071 /**
6072  * format quote body
6073  * the calling function should have a continue statement after calling this method
6074  */
6075 void ASFormatter::formatQuoteBody()
6076 {
6077     assert(isInQuote);
6078 
6079     if (isSpecialChar)
6080     {
6081         isSpecialChar = false;
6082     }
6083     else if (currentChar == '\\' && !isInVerbatimQuote)
6084     {
6085         if (peekNextChar() == ' ')              // is this '\' at end of line
6086             haveLineContinuationChar = true;
6087         else
6088             isSpecialChar = true;
6089     }
6090     else if (isInVerbatimQuote && currentChar == '"')
6091     {
6092         if (isCStyle())
6093         {
6094             string delim = ')' + verbatimDelimiter;
6095             int delimStart = charNum - delim.length();
6096             if (delimStart > 0 && currentLine.substr(delimStart, delim.length()) == delim)
6097             {
6098                 isInQuote = false;
6099                 isInVerbatimQuote = false;
6100             }
6101         }
6102         else if (isSharpStyle())
6103         {
6104             if ((int) currentLine.length() > charNum + 1
6105                     && currentLine[charNum + 1] == '"')         // check consecutive quotes
6106             {
6107                 appendSequence("\"\"");
6108                 goForward(1);
6109                 return;
6110             }
6111             isInQuote = false;
6112             isInVerbatimQuote = false;
6113         }
6114     }
6115     else if (quoteChar == currentChar)
6116     {
6117         isInQuote = false;
6118     }
6119 
6120     appendCurrentChar();
6121 
6122     // append the text to the ending quoteChar or an escape sequence
6123     // tabs in quotes are NOT changed by convert-tabs
6124     if (isInQuote && currentChar != '\\')
6125     {
6126         while (charNum + 1 < (int) currentLine.length()
6127                 && currentLine[charNum + 1] != quoteChar
6128                 && currentLine[charNum + 1] != '\\')
6129         {
6130             currentChar = currentLine[++charNum];
6131             appendCurrentChar();
6132         }
6133     }
6134     if (charNum + 1 >= (int) currentLine.length()
6135             && currentChar != '\\'
6136             && !isInVerbatimQuote)
6137         isInQuote = false;              // missing closing quote
6138 }
6139 
6140 /**
6141  * format a quote opener
6142  * the quote opener will be appended to the current formattedLine or a new formattedLine as necessary
6143  * the calling function should have a continue statement after calling this method
6144  */
6145 void ASFormatter::formatQuoteOpener()
6146 {
6147     assert(currentChar == '"'
6148            || (currentChar == '\'' && !isDigitSeparator(currentLine, charNum)));
6149 
6150     isInQuote = true;
6151     quoteChar = currentChar;
6152     if (isCStyle() && previousChar == 'R')
6153     {
6154         int parenPos = currentLine.find('(', charNum);
6155         if (parenPos != -1)
6156         {
6157             isInVerbatimQuote = true;
6158             verbatimDelimiter = currentLine.substr(charNum + 1, parenPos - charNum - 1);
6159         }
6160     }
6161     else if (isSharpStyle() && previousChar == '@')
6162         isInVerbatimQuote = true;
6163 
6164     // a quote following a brace is an array
6165     if (previousCommandChar == '{'
6166             && !isImmediatelyPostComment
6167             && !isImmediatelyPostLineComment
6168             && isNonInStatementArray
6169             && !isBraceType(braceTypeStack->back(), SINGLE_LINE_TYPE)
6170             && !isWhiteSpace(peekNextChar()))
6171     {
6172         if (braceFormatMode == NONE_MODE)
6173         {
6174             if (currentLineBeginsWithBrace)
6175                 formatRunIn();
6176         }
6177         else if (braceFormatMode == RUN_IN_MODE)
6178         {
6179             formatRunIn();
6180         }
6181         else if (braceFormatMode == BREAK_MODE)
6182         {
6183             if (formattedLine.length() > 0 && formattedLine[0] == '{')
6184                 isInLineBreak = true;
6185         }
6186         else
6187         {
6188             if (currentLineBeginsWithBrace)
6189                 isInLineBreak = true;
6190         }
6191     }
6192     previousCommandChar = ' ';
6193     appendCurrentChar();
6194 }
6195 
6196 /**
6197  * get the next line comment adjustment that results from breaking a closing brace.
6198  * the brace must be on the same line as the closing header.
6199  * i.e "} else" changed to "} <NL> else".
6200  */
6201 int ASFormatter::getNextLineCommentAdjustment()
6202 {
6203     assert(foundClosingHeader && previousNonWSChar == '}');
6204     if (charNum < 1)            // "else" is in column 1
6205         return 0;
6206     size_t lastBrace = currentLine.rfind('}', charNum - 1);
6207     if (lastBrace != string::npos)
6208         return (lastBrace - charNum);   // return a negative number
6209     return 0;
6210 }
6211 
6212 // for console build only
6213 LineEndFormat ASFormatter::getLineEndFormat() const
6214 {
6215     return lineEnd;
6216 }
6217 
6218 /**
6219  * get the current line comment adjustment that results from attaching
6220  * a closing header to a closing brace.
6221  * the brace must be on the line previous to the closing header.
6222  * the adjustment is 2 chars, one for the brace and one for the space.
6223  * i.e "} <NL> else" changed to "} else".
6224  */
6225 int ASFormatter::getCurrentLineCommentAdjustment()
6226 {
6227     assert(foundClosingHeader && previousNonWSChar == '}');
6228     if (charNum < 1)
6229         return 2;
6230     size_t lastBrace = currentLine.rfind('}', charNum - 1);
6231     if (lastBrace == string::npos)
6232         return 2;
6233     return 0;
6234 }
6235 
6236 /**
6237  * get the previous word on a line
6238  * the argument 'currPos' must point to the current position.
6239  *
6240  * @return is the previous word or an empty string if none found.
6241  */
6242 string ASFormatter::getPreviousWord(const string& line, int currPos) const
6243 {
6244     // get the last legal word (may be a number)
6245     if (currPos == 0)
6246         return string();
6247 
6248     size_t end = line.find_last_not_of(" \t", currPos - 1);
6249     if (end == string::npos || !isLegalNameChar(line[end]))
6250         return string();
6251 
6252     int start;          // start of the previous word
6253     for (start = end; start > -1; start--)
6254     {
6255         if (!isLegalNameChar(line[start]) || line[start] == '.')
6256             break;
6257     }
6258     start++;
6259 
6260     return (line.substr(start, end - start + 1));
6261 }
6262 
6263 /**
6264  * check if a line break is needed when a closing brace
6265  * is followed by a closing header.
6266  * the break depends on the braceFormatMode and other factors.
6267  */
6268 void ASFormatter::isLineBreakBeforeClosingHeader()
6269 {
6270     assert(foundClosingHeader && previousNonWSChar == '}');
6271 
6272     if (currentHeader == &AS_WHILE && shouldAttachClosingWhile)
6273     {
6274         appendClosingHeader();
6275         return;
6276     }
6277 
6278     if (braceFormatMode == BREAK_MODE
6279             || braceFormatMode == RUN_IN_MODE
6280             || attachClosingBraceMode)
6281     {
6282         isInLineBreak = true;
6283     }
6284     else if (braceFormatMode == NONE_MODE)
6285     {
6286         if (shouldBreakClosingHeaderBraces
6287                 || getBraceIndent() || getBlockIndent())
6288         {
6289             isInLineBreak = true;
6290         }
6291         else
6292         {
6293             appendSpacePad();
6294             // is closing brace broken?
6295             size_t i = currentLine.find_first_not_of(" \t");
6296             if (i != string::npos && currentLine[i] == '}')
6297                 isInLineBreak = false;
6298 
6299             if (shouldBreakBlocks)
6300                 isAppendPostBlockEmptyLineRequested = false;
6301         }
6302     }
6303     // braceFormatMode == ATTACH_MODE, LINUX_MODE
6304     else
6305     {
6306         if (shouldBreakClosingHeaderBraces
6307                 || getBraceIndent() || getBlockIndent())
6308         {
6309             isInLineBreak = true;
6310         }
6311         else
6312         {
6313             appendClosingHeader();
6314             if (shouldBreakBlocks)
6315                 isAppendPostBlockEmptyLineRequested = false;
6316         }
6317     }
6318 }
6319 
6320 /**
6321  * Append a closing header to the previous closing brace, if possible
6322  */
6323 void ASFormatter::appendClosingHeader()
6324 {
6325     // if a blank line does not precede this
6326     // or last line is not a one line block, attach header
6327     bool previousLineIsEmpty = isEmptyLine(formattedLine);
6328     int previousLineIsOneLineBlock = 0;
6329     size_t firstBrace = findNextChar(formattedLine, '{');
6330     if (firstBrace != string::npos)
6331         previousLineIsOneLineBlock = isOneLineBlockReached(formattedLine, firstBrace);
6332     if (!previousLineIsEmpty
6333             && previousLineIsOneLineBlock == 0)
6334     {
6335         isInLineBreak = false;
6336         appendSpacePad();
6337         spacePadNum = 0;    // don't count as comment padding
6338     }
6339 }
6340 
6341 /**
6342  * Add braces to a single line statement following a header.
6343  * braces are not added if the proper conditions are not met.
6344  * braces are added to the currentLine.
6345  */
6346 bool ASFormatter::addBracesToStatement()
6347 {
6348     assert(isImmediatelyPostHeader);
6349 
6350     if (currentHeader != &AS_IF
6351             && currentHeader != &AS_ELSE
6352             && currentHeader != &AS_FOR
6353             && currentHeader != &AS_WHILE
6354             && currentHeader != &AS_DO
6355             && currentHeader != &AS_FOREACH
6356             && currentHeader != &AS_QFOREACH
6357             && currentHeader != &AS_QFOREVER
6358             && currentHeader != &AS_FOREVER)
6359         return false;
6360 
6361     if (currentHeader == &AS_WHILE && foundClosingHeader)   // do-while
6362         return false;
6363 
6364     // do not brace an empty statement
6365     if (currentChar == ';')
6366         return false;
6367 
6368     // do not add if a header follows
6369     if (isCharPotentialHeader(currentLine, charNum))
6370         if (findHeader(headers) != nullptr)
6371             return false;
6372 
6373     // find the next semi-colon
6374     size_t nextSemiColon = charNum;
6375     if (currentChar != ';')
6376         nextSemiColon = findNextChar(currentLine, ';', charNum + 1);
6377     if (nextSemiColon == string::npos)
6378         return false;
6379 
6380     // add closing brace before changing the line length
6381     if (nextSemiColon == currentLine.length() - 1)
6382         currentLine.append(" }");
6383     else
6384         currentLine.insert(nextSemiColon + 1, " }");
6385     // add opening brace
6386     currentLine.insert(charNum, "{ ");
6387     assert(computeChecksumIn("{}"));
6388     currentChar = '{';
6389     if ((int) currentLine.find_first_not_of(" \t") == charNum)
6390         currentLineBeginsWithBrace = true;
6391     // remove extra spaces
6392     if (!shouldAddOneLineBraces)
6393     {
6394         size_t lastText = formattedLine.find_last_not_of(" \t");
6395         if ((formattedLine.length() - 1) - lastText > 1)
6396             formattedLine.erase(lastText + 1);
6397     }
6398     return true;
6399 }
6400 
6401 /**
6402  * Remove braces from a single line statement following a header.
6403  * braces are not removed if the proper conditions are not met.
6404  * The first brace is replaced by a space.
6405  */
6406 bool ASFormatter::removeBracesFromStatement()
6407 {
6408     assert(isImmediatelyPostHeader);
6409     assert(currentChar == '{');
6410 
6411     if (currentHeader != &AS_IF
6412             && currentHeader != &AS_ELSE
6413             && currentHeader != &AS_FOR
6414             && currentHeader != &AS_WHILE
6415             && currentHeader != &AS_FOREACH)
6416         return false;
6417 
6418     if (currentHeader == &AS_WHILE && foundClosingHeader)   // do-while
6419         return false;
6420 
6421     bool isFirstLine = true;
6422     string nextLine_;
6423     // leave nextLine_ empty if end of line comment follows
6424     if (!isBeforeAnyLineEndComment(charNum) || currentLineBeginsWithBrace)
6425         nextLine_ = currentLine.substr(charNum + 1);
6426     size_t nextChar = 0;
6427 
6428     // find the first non-blank text
6429     ASPeekStream stream(sourceIterator);
6430     while (stream.hasMoreLines() || isFirstLine)
6431     {
6432         if (isFirstLine)
6433             isFirstLine = false;
6434         else
6435         {
6436             nextLine_ = stream.peekNextLine();
6437             nextChar = 0;
6438         }
6439 
6440         nextChar = nextLine_.find_first_not_of(" \t", nextChar);
6441         if (nextChar != string::npos)
6442             break;
6443     }
6444     if (!stream.hasMoreLines())
6445         return false;
6446 
6447     // don't remove if comments or a header follow the brace
6448     if ((nextLine_.compare(nextChar, 2, "/*") == 0)
6449             || (nextLine_.compare(nextChar, 2, "//") == 0)
6450             || (isCharPotentialHeader(nextLine_, nextChar)
6451                 && ASBase::findHeader(nextLine_, nextChar, headers) != nullptr))
6452         return false;
6453 
6454     // find the next semi-colon
6455     size_t nextSemiColon = nextChar;
6456     if (nextLine_[nextChar] != ';')
6457         nextSemiColon = findNextChar(nextLine_, ';', nextChar + 1);
6458     if (nextSemiColon == string::npos)
6459         return false;
6460 
6461     // find the closing brace
6462     isFirstLine = true;
6463     nextChar = nextSemiColon + 1;
6464     while (stream.hasMoreLines() || isFirstLine)
6465     {
6466         if (isFirstLine)
6467             isFirstLine = false;
6468         else
6469         {
6470             nextLine_ = stream.peekNextLine();
6471             nextChar = 0;
6472         }
6473         nextChar = nextLine_.find_first_not_of(" \t", nextChar);
6474         if (nextChar != string::npos)
6475             break;
6476     }
6477     if (nextLine_.length() == 0 || nextLine_[nextChar] != '}')
6478         return false;
6479 
6480     // remove opening brace
6481     currentLine[charNum] = currentChar = ' ';
6482     assert(adjustChecksumIn(-'{'));
6483     return true;
6484 }
6485 
6486 /**
6487  * Find the next character that is not in quotes or a comment.
6488  *
6489  * @param line         the line to be searched.
6490  * @param searchChar   the char to find.
6491  * @param searchStart  the start position on the line (default is 0).
6492  * @return the position on the line or string::npos if not found.
6493  */
6494 size_t ASFormatter::findNextChar(const string& line, char searchChar, int searchStart /*0*/) const
6495 {
6496     // find the next searchChar
6497     size_t i;
6498     for (i = searchStart; i < line.length(); i++)
6499     {
6500         if (line.compare(i, 2, "//") == 0)
6501             return string::npos;
6502         if (line.compare(i, 2, "/*") == 0)
6503         {
6504             size_t endComment = line.find("*/", i + 2);
6505             if (endComment == string::npos)
6506                 return string::npos;
6507             i = endComment + 2;
6508             if (i >= line.length())
6509                 return string::npos;
6510         }
6511         if (line[i] == '"'
6512                 || (line[i] == '\'' && !isDigitSeparator(line, i)))
6513         {
6514             char quote = line[i];
6515             while (i < line.length())
6516             {
6517                 size_t endQuote = line.find(quote, i + 1);
6518                 if (endQuote == string::npos)
6519                     return string::npos;
6520                 i = endQuote;
6521                 if (line[endQuote - 1] != '\\') // check for '\"'
6522                     break;
6523                 if (line[endQuote - 2] == '\\') // check for '\\'
6524                     break;
6525             }
6526         }
6527 
6528         if (line[i] == searchChar)
6529             break;
6530 
6531         // for now don't process C# 'delegate' braces
6532         // do this last in case the search char is a '{'
6533         if (line[i] == '{')
6534             return string::npos;
6535     }
6536     if (i >= line.length()) // didn't find searchChar
6537         return string::npos;
6538 
6539     return i;
6540 }
6541 
6542 /**
6543  * Find split point for break/attach return type.
6544  */
6545 void ASFormatter::findReturnTypeSplitPoint(const string& firstLine)
6546 {
6547     assert((isBraceType(braceTypeStack->back(), NULL_TYPE)
6548             || isBraceType(braceTypeStack->back(), DEFINITION_TYPE)));
6549     assert(shouldBreakReturnType || shouldBreakReturnTypeDecl
6550            || shouldAttachReturnType || shouldAttachReturnTypeDecl);
6551 
6552     bool isFirstLine     = true;
6553     bool isInComment_    = false;
6554     bool isInQuote_      = false;
6555     bool foundSplitPoint = false;
6556     bool isAlreadyBroken = false;
6557     char quoteChar_      = ' ';
6558     char currNonWSChar   = ' ';
6559     char prevNonWSChar   = ' ';
6560     size_t parenCount    = 0;
6561     size_t squareCount   = 0;
6562     size_t angleCount    = 0;
6563     size_t breakLineNum  = 0;
6564     size_t breakCharNum  = string::npos;
6565     string line          = firstLine;
6566 
6567     // Process the lines until a ';' or '{'.
6568     ASPeekStream stream(sourceIterator);
6569     while (stream.hasMoreLines() || isFirstLine)
6570     {
6571         if (isFirstLine)
6572             isFirstLine = false;
6573         else
6574         {
6575             if (isInQuote_)
6576                 return;
6577             line = stream.peekNextLine();
6578             if (!foundSplitPoint)
6579                 ++breakLineNum;
6580         }
6581         size_t firstCharNum = line.find_first_not_of(" \t");
6582         if (firstCharNum == string::npos)
6583             continue;
6584         if (line[firstCharNum] == '#')
6585         {
6586             // don't attach to a preprocessor
6587             if (shouldAttachReturnType || shouldAttachReturnTypeDecl)
6588                 return;
6589             else
6590                 continue;
6591         }
6592         // parse the line
6593         for (size_t i = 0; i < line.length(); i++)
6594         {
6595             if (!isWhiteSpace(line[i]))
6596             {
6597                 prevNonWSChar = currNonWSChar;
6598                 currNonWSChar = line[i];
6599             }
6600             else if (line[i] == '\t' && shouldConvertTabs)
6601             {
6602                 size_t tabSize = getTabLength();
6603                 size_t numSpaces = tabSize - ((tabIncrementIn + i) % tabSize);
6604                 line.replace(i, 1, numSpaces, ' ');
6605                 currentChar = line[i];
6606             }
6607             if (line.compare(i, 2, "/*") == 0)
6608                 isInComment_ = true;
6609             if (isInComment_)
6610             {
6611                 if (line.compare(i, 2, "*/") == 0)
6612                 {
6613                     isInComment_ = false;
6614                     ++i;
6615                 }
6616                 continue;
6617             }
6618             if (line[i] == '\\')
6619             {
6620                 ++i;
6621                 continue;
6622             }
6623 
6624             if (isInQuote_)
6625             {
6626                 if (line[i] == quoteChar_)
6627                     isInQuote_ = false;
6628                 continue;
6629             }
6630 
6631             if (line[i] == '"'
6632                     || (line[i] == '\'' && !isDigitSeparator(line, i)))
6633             {
6634                 isInQuote_ = true;
6635                 quoteChar_ = line[i];
6636                 continue;
6637             }
6638             if (line.compare(i, 2, "//") == 0)
6639             {
6640                 i = line.length();
6641                 continue;
6642             }
6643             // not in quote or comment
6644             if (!foundSplitPoint)
6645             {
6646                 if (line[i] == '<')
6647                 {
6648                     ++angleCount;
6649                     continue;
6650                 }
6651                 if (line[i] == '>')
6652                 {
6653                     if (angleCount)
6654                         --angleCount;
6655                     if (!angleCount)
6656                     {
6657                         size_t nextCharNum = line.find_first_not_of(" \t*&", i + 1);
6658                         if (nextCharNum == string::npos)
6659                         {
6660                             breakCharNum  = string::npos;
6661                             continue;
6662                         }
6663                         if (line[nextCharNum] != ':')       // scope operator
6664                             breakCharNum  = nextCharNum;
6665                     }
6666                     continue;
6667                 }
6668                 if (angleCount)
6669                     continue;
6670                 if (line[i] == '[')
6671                 {
6672                     ++squareCount;
6673                     continue;
6674                 }
6675                 if (line[i] == ']')
6676                 {
6677                     if (squareCount)
6678                         --squareCount;
6679                     continue;
6680                 }
6681                 // an assignment before the parens is not a function
6682                 if (line[i] == '=')
6683                     return;
6684                 if (isWhiteSpace(line[i]) || line[i] == '*' || line[i] == '&')
6685                 {
6686                     size_t nextNum = line.find_first_not_of(" \t", i + 1);
6687                     if (nextNum == string::npos)
6688                         breakCharNum = string::npos;
6689                     else
6690                     {
6691                         if (line.length() > nextNum + 1
6692                                 && line[nextNum] == ':' && line[nextNum + 1] == ':')
6693                             i = --nextNum;
6694                         else if (line[nextNum] != '(')
6695                             breakCharNum = string::npos;
6696                     }
6697                     continue;
6698                 }
6699                 if ((isLegalNameChar(line[i]) || line[i] == '~')
6700                         && breakCharNum == string::npos)
6701                 {
6702                     breakCharNum = i;
6703                     if (isLegalNameChar(line[i])
6704                             && findKeyword(line, i, AS_OPERATOR))
6705                     {
6706                         if (breakCharNum == firstCharNum)
6707                             isAlreadyBroken = true;
6708                         foundSplitPoint = true;
6709                         // find the operator, may be parens
6710                         size_t parenNum =
6711                             line.find_first_not_of(" \t", i + AS_OPERATOR.length());
6712                         if (parenNum == string::npos)
6713                             return;
6714                         // find paren after the operator
6715                         parenNum = line.find('(', parenNum + 1);
6716                         if (parenNum == string::npos)
6717                             return;
6718                         i = --parenNum;
6719                     }
6720                     continue;
6721                 }
6722                 if (line[i] == ':'
6723                         && line.length() > i + 1
6724                         && line[i + 1] == ':')
6725                 {
6726                     size_t nextCharNum = line.find_first_not_of(" \t:", i + 1);
6727                     if (nextCharNum == string::npos)
6728                         return;
6729 
6730                     if (isLegalNameChar(line[nextCharNum])
6731                             && findKeyword(line, nextCharNum, AS_OPERATOR))
6732                     {
6733                         i = nextCharNum;
6734                         if (breakCharNum == firstCharNum)
6735                             isAlreadyBroken = true;
6736                         foundSplitPoint = true;
6737                         // find the operator, may be parens
6738                         size_t parenNum =
6739                             line.find_first_not_of(" \t", i + AS_OPERATOR.length());
6740                         if (parenNum == string::npos)
6741                             return;
6742                         // find paren after the operator
6743                         parenNum = line.find('(', parenNum + 1);
6744                         if (parenNum == string::npos)
6745                             return;
6746                         i = --parenNum;
6747                     }
6748                     else
6749                         i = --nextCharNum;
6750                     continue;
6751                 }
6752                 if (line[i] == '(' && !squareCount)
6753                 {
6754                     // is line is already broken?
6755                     if (breakCharNum == firstCharNum && breakLineNum > 0)
6756                         isAlreadyBroken = true;
6757                     ++parenCount;
6758                     foundSplitPoint = true;
6759                     continue;
6760                 }
6761             }
6762             // end !foundSplitPoint
6763             if (line[i] == '(')
6764             {
6765                 // consecutive ')(' parens is probably a function pointer
6766                 if (prevNonWSChar == ')' && !parenCount)
6767                     return;
6768                 ++parenCount;
6769                 continue;
6770             }
6771             if (line[i] == ')')
6772             {
6773                 if (parenCount)
6774                     --parenCount;
6775                 continue;
6776             }
6777             if (line[i] == '{')
6778             {
6779                 if (shouldBreakReturnType && foundSplitPoint && !isAlreadyBroken)
6780                 {
6781                     methodBreakCharNum = breakCharNum;
6782                     methodBreakLineNum = breakLineNum;
6783                 }
6784                 if (shouldAttachReturnType && foundSplitPoint && isAlreadyBroken)
6785                 {
6786                     methodAttachCharNum = breakCharNum;
6787                     methodAttachLineNum = breakLineNum;
6788                 }
6789                 return;
6790             }
6791             if (line[i] == ';')
6792             {
6793                 if (shouldBreakReturnTypeDecl && foundSplitPoint && !isAlreadyBroken)
6794                 {
6795                     methodBreakCharNum = breakCharNum;
6796                     methodBreakLineNum = breakLineNum;
6797                 }
6798                 if ((shouldAttachReturnTypeDecl && foundSplitPoint && isAlreadyBroken))
6799                 {
6800                     methodAttachCharNum = breakCharNum;
6801                     methodAttachLineNum = breakLineNum;
6802                 }
6803                 return;
6804             }
6805             if (line[i] == '}')
6806                 return;
6807         }   // end of for loop
6808         if (!foundSplitPoint)
6809             breakCharNum = string::npos;
6810     }   // end of while loop
6811 }
6812 
6813 /**
6814  * Look ahead in the file to see if a struct has access modifiers.
6815  *
6816  * @param firstLine     a reference to the line to indent.
6817  * @param index         the current line index.
6818  * @return              true if the struct has access modifiers.
6819  */
6820 bool ASFormatter::isStructAccessModified(const string& firstLine, size_t index) const
6821 {
6822     assert(firstLine[index] == '{');
6823     assert(isCStyle());
6824 
6825     bool isFirstLine = true;
6826     size_t braceCount = 1;
6827     string nextLine_ = firstLine.substr(index + 1);
6828     ASPeekStream stream(sourceIterator);
6829 
6830     // find the first non-blank text, bypassing all comments and quotes.
6831     bool isInComment_ = false;
6832     bool isInQuote_ = false;
6833     char quoteChar_ = ' ';
6834     while (stream.hasMoreLines() || isFirstLine)
6835     {
6836         if (isFirstLine)
6837             isFirstLine = false;
6838         else
6839             nextLine_ = stream.peekNextLine();
6840         // parse the line
6841         for (size_t i = 0; i < nextLine_.length(); i++)
6842         {
6843             if (isWhiteSpace(nextLine_[i]))
6844                 continue;
6845             if (nextLine_.compare(i, 2, "/*") == 0)
6846                 isInComment_ = true;
6847             if (isInComment_)
6848             {
6849                 if (nextLine_.compare(i, 2, "*/") == 0)
6850                 {
6851                     isInComment_ = false;
6852                     ++i;
6853                 }
6854                 continue;
6855             }
6856             if (nextLine_[i] == '\\')
6857             {
6858                 ++i;
6859                 continue;
6860             }
6861 
6862             if (isInQuote_)
6863             {
6864                 if (nextLine_[i] == quoteChar_)
6865                     isInQuote_ = false;
6866                 continue;
6867             }
6868 
6869             if (nextLine_[i] == '"'
6870                     || (nextLine_[i] == '\'' && !isDigitSeparator(nextLine_, i)))
6871             {
6872                 isInQuote_ = true;
6873                 quoteChar_ = nextLine_[i];
6874                 continue;
6875             }
6876             if (nextLine_.compare(i, 2, "//") == 0)
6877             {
6878                 i = nextLine_.length();
6879                 continue;
6880             }
6881             // handle braces
6882             if (nextLine_[i] == '{')
6883                 ++braceCount;
6884             if (nextLine_[i] == '}')
6885                 --braceCount;
6886             if (braceCount == 0)
6887                 return false;
6888             // check for access modifiers
6889             if (isCharPotentialHeader(nextLine_, i))
6890             {
6891                 if (findKeyword(nextLine_, i, AS_PUBLIC)
6892                         || findKeyword(nextLine_, i, AS_PRIVATE)
6893                         || findKeyword(nextLine_, i, AS_PROTECTED))
6894                     return true;
6895                 string name = getCurrentWord(nextLine_, i);
6896                 i += name.length() - 1;
6897             }
6898         }   // end of for loop
6899     }   // end of while loop
6900 
6901     return false;
6902 }
6903 
6904 /**
6905 * Look ahead in the file to see if a preprocessor block is indentable.
6906 *
6907 * @param firstLine     a reference to the line to indent.
6908 * @param index         the current line index.
6909 * @return              true if the block is indentable.
6910 */
6911 bool ASFormatter::isIndentablePreprocessorBlock(const string& firstLine, size_t index)
6912 {
6913     assert(firstLine[index] == '#');
6914 
6915     bool isFirstLine = true;
6916     bool isInIndentableBlock = false;
6917     bool blockContainsBraces = false;
6918     bool blockContainsDefineContinuation = false;
6919     bool isInClassConstructor = false;
6920     bool isPotentialHeaderGuard = false;    // ifndef is first preproc statement
6921     bool isPotentialHeaderGuard2 = false;   // define is within the first proproc
6922     int  numBlockIndents = 0;
6923     int  lineParenCount = 0;
6924     string nextLine_ = firstLine.substr(index);
6925     auto stream = make_shared<ASPeekStream>(sourceIterator);
6926 
6927     // find end of the block, bypassing all comments and quotes.
6928     bool isInComment_ = false;
6929     bool isInQuote_ = false;
6930     char quoteChar_ = ' ';
6931     while (stream->hasMoreLines() || isFirstLine)
6932     {
6933         if (isFirstLine)
6934             isFirstLine = false;
6935         else
6936             nextLine_ = stream->peekNextLine();
6937         // parse the line
6938         for (size_t i = 0; i < nextLine_.length(); i++)
6939         {
6940             if (isWhiteSpace(nextLine_[i]))
6941                 continue;
6942             if (nextLine_.compare(i, 2, "/*") == 0)
6943                 isInComment_ = true;
6944             if (isInComment_)
6945             {
6946                 if (nextLine_.compare(i, 2, "*/") == 0)
6947                 {
6948                     isInComment_ = false;
6949                     ++i;
6950                 }
6951                 continue;
6952             }
6953             if (nextLine_[i] == '\\')
6954             {
6955                 ++i;
6956                 continue;
6957             }
6958             if (isInQuote_)
6959             {
6960                 if (nextLine_[i] == quoteChar_)
6961                     isInQuote_ = false;
6962                 continue;
6963             }
6964 
6965             if (nextLine_[i] == '"'
6966                     || (nextLine_[i] == '\'' && !isDigitSeparator(nextLine_, i)))
6967             {
6968                 isInQuote_ = true;
6969                 quoteChar_ = nextLine_[i];
6970                 continue;
6971             }
6972             if (nextLine_.compare(i, 2, "//") == 0)
6973             {
6974                 i = nextLine_.length();
6975                 continue;
6976             }
6977             // handle preprocessor statement
6978             if (nextLine_[i] == '#')
6979             {
6980                 string preproc = ASBeautifier::extractPreprocessorStatement(nextLine_);
6981                 if (preproc.length() >= 2 && preproc.substr(0, 2) == "if") // #if, #ifdef, #ifndef
6982                 {
6983                     numBlockIndents += 1;
6984                     isInIndentableBlock = true;
6985                     // flag first preprocessor conditional for header include guard check
6986                     if (!processedFirstConditional)
6987                     {
6988                         processedFirstConditional = true;
6989                         isFirstPreprocConditional = true;
6990                         if (isNDefPreprocStatement(nextLine_, preproc))
6991                             isPotentialHeaderGuard = true;
6992                     }
6993                 }
6994                 else if (preproc == "endif")
6995                 {
6996                     if (numBlockIndents > 0)
6997                         numBlockIndents -= 1;
6998                     // must exit BOTH loops
6999                     if (numBlockIndents == 0)
7000                         goto EndOfWhileLoop;
7001                 }
7002                 else if (preproc == "define")
7003                 {
7004                     if (nextLine_[nextLine_.length() - 1] == '\\')
7005                         blockContainsDefineContinuation = true;
7006                     // check for potential header include guards
7007                     else if (isPotentialHeaderGuard && numBlockIndents == 1)
7008                         isPotentialHeaderGuard2 = true;
7009                 }
7010                 i = nextLine_.length();
7011                 continue;
7012             }
7013             // handle exceptions
7014             if (nextLine_[i] == '{' || nextLine_[i] == '}')
7015                 blockContainsBraces = true;
7016             else if (nextLine_[i] == '(')
7017                 ++lineParenCount;
7018             else if (nextLine_[i] == ')')
7019                 --lineParenCount;
7020             else if (nextLine_[i] == ':')
7021             {
7022                 // check for '::'
7023                 if (nextLine_.length() > i + 1 && nextLine_[i + 1] == ':')
7024                     ++i;
7025                 else
7026                     isInClassConstructor = true;
7027             }
7028             // bypass unnecessary parsing - must exit BOTH loops
7029             if (blockContainsBraces || isInClassConstructor || blockContainsDefineContinuation)
7030                 goto EndOfWhileLoop;
7031         }   // end of for loop, end of line
7032         if (lineParenCount != 0)
7033             break;
7034     }   // end of while loop
7035 EndOfWhileLoop:
7036     preprocBlockEnd = sourceIterator->tellg();
7037     if (preprocBlockEnd < 0)
7038         preprocBlockEnd = sourceIterator->getStreamLength();
7039     if (blockContainsBraces
7040             || isInClassConstructor
7041             || blockContainsDefineContinuation
7042             || lineParenCount != 0
7043             || numBlockIndents != 0)
7044         isInIndentableBlock = false;
7045     // find next executable instruction
7046     // this WILL RESET the get pointer
7047     string nextText = peekNextText("", false, stream);
7048     // bypass header include guards
7049     if (isFirstPreprocConditional)
7050     {
7051         isFirstPreprocConditional = false;
7052         if (nextText.empty() && isPotentialHeaderGuard2)
7053         {
7054             isInIndentableBlock = false;
7055             preprocBlockEnd = 0;
7056         }
7057     }
7058     // this allows preprocessor blocks within this block to be indented
7059     if (!isInIndentableBlock)
7060         preprocBlockEnd = 0;
7061     // peekReset() is done by previous peekNextText()
7062     return isInIndentableBlock;
7063 }
7064 
7065 bool ASFormatter::isNDefPreprocStatement(const string& nextLine_, const string& preproc) const
7066 {
7067     if (preproc == "ifndef")
7068         return true;
7069     // check for '!defined'
7070     if (preproc == "if")
7071     {
7072         size_t i = nextLine_.find('!');
7073         if (i == string::npos)
7074             return false;
7075         i = nextLine_.find_first_not_of(" \t", ++i);
7076         if (i != string::npos && nextLine_.compare(i, 7, "defined") == 0)
7077             return true;
7078     }
7079     return false;
7080 }
7081 
7082 /**
7083  * Check to see if this is an EXEC SQL statement.
7084  *
7085  * @param line          a reference to the line to indent.
7086  * @param index         the current line index.
7087  * @return              true if the statement is EXEC SQL.
7088  */
7089 bool ASFormatter::isExecSQL(const string& line, size_t index) const
7090 {
7091     if (line[index] != 'e' && line[index] != 'E')   // quick check to reject most
7092         return false;
7093     string word;
7094     if (isCharPotentialHeader(line, index))
7095         word = getCurrentWord(line, index);
7096     for (size_t i = 0; i < word.length(); i++)
7097         word[i] = (char) toupper(word[i]);
7098     if (word != "EXEC")
7099         return false;
7100     size_t index2 = index + word.length();
7101     index2 = line.find_first_not_of(" \t", index2);
7102     if (index2 == string::npos)
7103         return false;
7104     word.erase();
7105     if (isCharPotentialHeader(line, index2))
7106         word = getCurrentWord(line, index2);
7107     for (size_t i = 0; i < word.length(); i++)
7108         word[i] = (char) toupper(word[i]);
7109     if (word != "SQL")
7110         return false;
7111     return true;
7112 }
7113 
7114 /**
7115  * The continuation lines must be adjusted so the leading spaces
7116  *     is equivalent to the text on the opening line.
7117  *
7118  * Updates currentLine and charNum.
7119  */
7120 void ASFormatter::trimContinuationLine()
7121 {
7122     size_t len = currentLine.length();
7123     size_t tabSize = getTabLength();
7124     charNum = 0;
7125 
7126     if (leadingSpaces > 0 && len > 0)
7127     {
7128         size_t i;
7129         size_t continuationIncrementIn = 0;
7130         for (i = 0; (i < len) && (i + continuationIncrementIn < leadingSpaces); i++)
7131         {
7132             if (!isWhiteSpace(currentLine[i]))      // don't delete any text
7133             {
7134                 if (i < continuationIncrementIn)
7135                     leadingSpaces = i + tabIncrementIn;
7136                 continuationIncrementIn = tabIncrementIn;
7137                 break;
7138             }
7139             if (currentLine[i] == '\t')
7140                 continuationIncrementIn += tabSize - 1 - ((continuationIncrementIn + i) % tabSize);
7141         }
7142 
7143         if ((int) continuationIncrementIn == tabIncrementIn)
7144             charNum = i;
7145         else
7146         {
7147             // build a new line with the equivalent leading chars
7148             string newLine;
7149             int leadingChars = 0;
7150             if ((int) leadingSpaces > tabIncrementIn)
7151                 leadingChars = leadingSpaces - tabIncrementIn;
7152             newLine.append(leadingChars, ' ');
7153             newLine.append(currentLine, i, len - i);
7154             currentLine = newLine;
7155             charNum = leadingChars;
7156             if (currentLine.length() == 0)
7157                 currentLine = string(" ");        // a null is inserted if this is not done
7158         }
7159         if (i >= len)
7160             charNum = 0;
7161     }
7162 }
7163 
7164 /**
7165  * Determine if a header is a closing header
7166  *
7167  * @return      true if the header is a closing header.
7168  */
7169 bool ASFormatter::isClosingHeader(const string* header) const
7170 {
7171     return (header == &AS_ELSE
7172             || header == &AS_CATCH
7173             || header == &AS_FINALLY);
7174 }
7175 
7176 /**
7177  * Determine if a * following a closing paren is immediately.
7178  * after a cast. If so it is a deference and not a multiply.
7179  * e.g. "(int*) *ptr" is a deference.
7180  */
7181 bool ASFormatter::isImmediatelyPostCast() const
7182 {
7183     assert(previousNonWSChar == ')' && currentChar == '*');
7184     // find preceding closing paren on currentLine or readyFormattedLine
7185     string line;        // currentLine or readyFormattedLine
7186     size_t paren = currentLine.rfind(')', charNum);
7187     if (paren != string::npos)
7188         line = currentLine;
7189     // if not on currentLine it must be on the previous line
7190     else
7191     {
7192         line = readyFormattedLine;
7193         paren = line.rfind(')');
7194         if (paren == string::npos)
7195             return false;
7196     }
7197     if (paren == 0)
7198         return false;
7199 
7200     // find character preceding the closing paren
7201     size_t lastChar = line.find_last_not_of(" \t", paren - 1);
7202     if (lastChar == string::npos)
7203         return false;
7204     // check for pointer cast
7205     if (line[lastChar] == '*')
7206         return true;
7207     return false;
7208 }
7209 
7210 /**
7211  * Determine if a < is a template definition or instantiation.
7212  * Sets the class variables isInTemplate and templateDepth.
7213  */
7214 void ASFormatter::checkIfTemplateOpener()
7215 {
7216     assert(!isInTemplate && currentChar == '<');
7217 
7218     // find first char after the '<' operators
7219     size_t firstChar = currentLine.find_first_not_of("< \t", charNum);
7220     if (firstChar == string::npos
7221             || currentLine[firstChar] == '=')
7222     {
7223         // this is not a template -> leave...
7224         isInTemplate = false;
7225         return;
7226     }
7227 
7228     bool isFirstLine = true;
7229     int parenDepth_ = 0;
7230     int maxTemplateDepth = 0;
7231     templateDepth = 0;
7232     string nextLine_ = currentLine.substr(charNum);
7233     ASPeekStream stream(sourceIterator);
7234 
7235     // find the angle braces, bypassing all comments and quotes.
7236     bool isInComment_ = false;
7237     bool isInQuote_ = false;
7238     char quoteChar_ = ' ';
7239     while (stream.hasMoreLines() || isFirstLine)
7240     {
7241         if (isFirstLine)
7242             isFirstLine = false;
7243         else
7244             nextLine_ = stream.peekNextLine();
7245         // parse the line
7246         for (size_t i = 0; i < nextLine_.length(); i++)
7247         {
7248             char currentChar_ = nextLine_[i];
7249             if (isWhiteSpace(currentChar_))
7250                 continue;
7251             if (nextLine_.compare(i, 2, "/*") == 0)
7252                 isInComment_ = true;
7253             if (isInComment_)
7254             {
7255                 if (nextLine_.compare(i, 2, "*/") == 0)
7256                 {
7257                     isInComment_ = false;
7258                     ++i;
7259                 }
7260                 continue;
7261             }
7262             if (currentChar_ == '\\')
7263             {
7264                 ++i;
7265                 continue;
7266             }
7267 
7268             if (isInQuote_)
7269             {
7270                 if (currentChar_ == quoteChar_)
7271                     isInQuote_ = false;
7272                 continue;
7273             }
7274 
7275             if (currentChar_ == '"'
7276                     || (currentChar_ == '\'' && !isDigitSeparator(nextLine_, i)))
7277             {
7278                 isInQuote_ = true;
7279                 quoteChar_ = currentChar_;
7280                 continue;
7281             }
7282             if (nextLine_.compare(i, 2, "//") == 0)
7283             {
7284                 i = nextLine_.length();
7285                 continue;
7286             }
7287 
7288             // not in a comment or quote
7289             if (currentChar_ == '<')
7290             {
7291                 ++templateDepth;
7292                 ++maxTemplateDepth;
7293                 continue;
7294             }
7295             else if (currentChar_ == '>')
7296             {
7297                 --templateDepth;
7298                 if (templateDepth == 0)
7299                 {
7300                     if (parenDepth_ == 0)
7301                     {
7302                         // this is a template!
7303                         isInTemplate = true;
7304                         templateDepth = maxTemplateDepth;
7305                     }
7306                     return;
7307                 }
7308                 continue;
7309             }
7310             else if (currentChar_ == '(' || currentChar_ == ')')
7311             {
7312                 if (currentChar_ == '(')
7313                     ++parenDepth_;
7314                 else
7315                     --parenDepth_;
7316                 if (parenDepth_ >= 0)
7317                     continue;
7318                 // this is not a template -> leave...
7319                 isInTemplate = false;
7320                 templateDepth = 0;
7321                 return;
7322             }
7323             else if (nextLine_.compare(i, 2, AS_AND) == 0
7324                      || nextLine_.compare(i, 2, AS_OR) == 0)
7325             {
7326                 // this is not a template -> leave...
7327                 isInTemplate = false;
7328                 templateDepth = 0;
7329                 return;
7330             }
7331             else if (currentChar_ == ','  // comma,     e.g. A<int, char>
7332                      || currentChar_ == '&'    // reference, e.g. A<int&>
7333                      || currentChar_ == '*'    // pointer,   e.g. A<int*>
7334                      || currentChar_ == '^'    // C++/CLI managed pointer, e.g. A<int^>
7335                      || currentChar_ == ':'    // ::,        e.g. std::string
7336                      || currentChar_ == '='    // assign     e.g. default parameter
7337                      || currentChar_ == '['    // []         e.g. string[]
7338                      || currentChar_ == ']'    // []         e.g. string[]
7339                      || currentChar_ == '('    // (...)      e.g. function definition
7340                      || currentChar_ == ')'    // (...)      e.g. function definition
7341                      || (isJavaStyle() && currentChar_ == '?')   // Java wildcard
7342                     )
7343             {
7344                 continue;
7345             }
7346             else if (!isLegalNameChar(currentChar_))
7347             {
7348                 // this is not a template -> leave...
7349                 isInTemplate = false;
7350                 templateDepth = 0;
7351                 return;
7352             }
7353             string name = getCurrentWord(nextLine_, i);
7354             i += name.length() - 1;
7355         }   // end for loop
7356     }   // end while loop
7357 }
7358 
7359 void ASFormatter::updateFormattedLineSplitPoints(char appendedChar)
7360 {
7361     assert(maxCodeLength != string::npos);
7362     assert(formattedLine.length() > 0);
7363 
7364     if (!isOkToSplitFormattedLine())
7365         return;
7366 
7367     char nextChar = peekNextChar();
7368 
7369     // don't split before an end of line comment
7370     if (nextChar == '/')
7371         return;
7372 
7373     // don't split before or after a brace
7374     if (appendedChar == '{' || appendedChar == '}'
7375             || previousNonWSChar == '{' || previousNonWSChar == '}'
7376             || nextChar == '{' || nextChar == '}'
7377             || currentChar == '{' || currentChar == '}')    // currentChar tests for an appended brace
7378         return;
7379 
7380     // don't split before or after a block paren
7381     if (appendedChar == '[' || appendedChar == ']'
7382             || previousNonWSChar == '['
7383             || nextChar == '[' || nextChar == ']')
7384         return;
7385 
7386     if (isWhiteSpace(appendedChar))
7387     {
7388         if (nextChar != ')'                     // space before a closing paren
7389                 && nextChar != '('              // space before an opening paren
7390                 && nextChar != '/'              // space before a comment
7391                 && nextChar != ':'              // space before a colon
7392                 && currentChar != ')'           // appended space before and after a closing paren
7393                 && currentChar != '('           // appended space before and after a opening paren
7394                 && previousNonWSChar != '('     // decided at the '('
7395                 // don't break before a pointer or reference aligned to type
7396                 && !(nextChar == '*'
7397                      && !isCharPotentialOperator(previousNonWSChar)
7398                      && pointerAlignment == PTR_ALIGN_TYPE)
7399                 && !(nextChar == '&'
7400                      && !isCharPotentialOperator(previousNonWSChar)
7401                      && (referenceAlignment == REF_ALIGN_TYPE
7402                          || (referenceAlignment == REF_SAME_AS_PTR && pointerAlignment == PTR_ALIGN_TYPE)))
7403            )
7404         {
7405             if (formattedLine.length() - 1 <= maxCodeLength)
7406                 maxWhiteSpace = formattedLine.length() - 1;
7407             else
7408                 maxWhiteSpacePending = formattedLine.length() - 1;
7409         }
7410     }
7411     // unpadded closing parens may split after the paren (counts as whitespace)
7412     else if (appendedChar == ')')
7413     {
7414         if (nextChar != ')'
7415                 && nextChar != ' '
7416                 && nextChar != ';'
7417                 && nextChar != ','
7418                 && nextChar != '.'
7419                 && !(nextChar == '-' && pointerSymbolFollows()))    // check for ->
7420         {
7421             if (formattedLine.length() <= maxCodeLength)
7422                 maxWhiteSpace = formattedLine.length();
7423             else
7424                 maxWhiteSpacePending = formattedLine.length();
7425         }
7426     }
7427     // unpadded commas may split after the comma
7428     else if (appendedChar == ',')
7429     {
7430         if (formattedLine.length() <= maxCodeLength)
7431             maxComma = formattedLine.length();
7432         else
7433             maxCommaPending = formattedLine.length();
7434     }
7435     else if (appendedChar == '(')
7436     {
7437         if (nextChar != ')' && nextChar != '(' && nextChar != '"' && nextChar != '\'')
7438         {
7439             // if follows an operator break before
7440             size_t parenNum;
7441             if (previousNonWSChar != ' ' && isCharPotentialOperator(previousNonWSChar))
7442                 parenNum = formattedLine.length() - 1;
7443             else
7444                 parenNum = formattedLine.length();
7445             if (formattedLine.length() <= maxCodeLength)
7446                 maxParen = parenNum;
7447             else
7448                 maxParenPending = parenNum;
7449         }
7450     }
7451     else if (appendedChar == ';')
7452     {
7453         if (nextChar != ' '  && nextChar != '}' && nextChar != '/') // check for following comment
7454         {
7455             if (formattedLine.length() <= maxCodeLength)
7456                 maxSemi = formattedLine.length();
7457             else
7458                 maxSemiPending = formattedLine.length();
7459         }
7460     }
7461 }
7462 
7463 void ASFormatter::updateFormattedLineSplitPointsOperator(const string& sequence)
7464 {
7465     assert(maxCodeLength != string::npos);
7466     assert(formattedLine.length() > 0);
7467 
7468     if (!isOkToSplitFormattedLine())
7469         return;
7470 
7471     char nextChar = peekNextChar();
7472 
7473     // don't split before an end of line comment
7474     if (nextChar == '/')
7475         return;
7476 
7477     // check for logical conditional
7478     if (sequence == "||" || sequence == "&&" || sequence == "or" || sequence == "and")
7479     {
7480         if (shouldBreakLineAfterLogical)
7481         {
7482             if (formattedLine.length() <= maxCodeLength)
7483                 maxAndOr = formattedLine.length();
7484             else
7485                 maxAndOrPending = formattedLine.length();
7486         }
7487         else
7488         {
7489             // adjust for leading space in the sequence
7490             size_t sequenceLength = sequence.length();
7491             if (formattedLine.length() > sequenceLength
7492                     && isWhiteSpace(formattedLine[formattedLine.length() - sequenceLength - 1]))
7493                 sequenceLength++;
7494             if (formattedLine.length() - sequenceLength <= maxCodeLength)
7495                 maxAndOr = formattedLine.length() - sequenceLength;
7496             else
7497                 maxAndOrPending = formattedLine.length() - sequenceLength;
7498         }
7499     }
7500     // comparison operators will split after the operator (counts as whitespace)
7501     else if (sequence == "==" || sequence == "!=" || sequence == ">=" || sequence == "<=")
7502     {
7503         if (formattedLine.length() <= maxCodeLength)
7504             maxWhiteSpace = formattedLine.length();
7505         else
7506             maxWhiteSpacePending = formattedLine.length();
7507     }
7508     // unpadded operators that will split BEFORE the operator (counts as whitespace)
7509     else if (sequence == "+" || sequence == "-" || sequence == "?")
7510     {
7511         if (charNum > 0
7512                 && !(sequence == "+" && isInExponent())
7513                 && !(sequence == "-"  && isInExponent())
7514                 && (isLegalNameChar(currentLine[charNum - 1])
7515                     || currentLine[charNum - 1] == ')'
7516                     || currentLine[charNum - 1] == ']'
7517                     || currentLine[charNum - 1] == '\"'))
7518         {
7519             if (formattedLine.length() - 1 <= maxCodeLength)
7520                 maxWhiteSpace = formattedLine.length() - 1;
7521             else
7522                 maxWhiteSpacePending = formattedLine.length() - 1;
7523         }
7524     }
7525     // unpadded operators that will USUALLY split AFTER the operator (counts as whitespace)
7526     else if (sequence == "=" || sequence == ":")
7527     {
7528         // split BEFORE if the line is too long
7529         // do NOT use <= here, must allow for a brace attached to an array
7530         size_t splitPoint = 0;
7531         if (formattedLine.length() < maxCodeLength)
7532             splitPoint = formattedLine.length();
7533         else
7534             splitPoint = formattedLine.length() - 1;
7535         // padded or unpadded arrays
7536         if (previousNonWSChar == ']')
7537         {
7538             if (formattedLine.length() - 1 <= maxCodeLength)
7539                 maxWhiteSpace = splitPoint;
7540             else
7541                 maxWhiteSpacePending = splitPoint;
7542         }
7543         else if (charNum > 0
7544                  && (isLegalNameChar(currentLine[charNum - 1])
7545                      || currentLine[charNum - 1] == ')'
7546                      || currentLine[charNum - 1] == ']'))
7547         {
7548             if (formattedLine.length() <= maxCodeLength)
7549                 maxWhiteSpace = splitPoint;
7550             else
7551                 maxWhiteSpacePending = splitPoint;
7552         }
7553     }
7554 }
7555 
7556 /**
7557  * Update the split point when a pointer or reference is formatted.
7558  * The argument is the maximum index of the last whitespace character.
7559  */
7560 void ASFormatter::updateFormattedLineSplitPointsPointerOrReference(size_t index)
7561 {
7562     assert(maxCodeLength != string::npos);
7563     assert(formattedLine.length() > 0);
7564     assert(index < formattedLine.length());
7565 
7566     if (!isOkToSplitFormattedLine())
7567         return;
7568 
7569     if (index < maxWhiteSpace)      // just in case
7570         return;
7571 
7572     if (index <= maxCodeLength)
7573         maxWhiteSpace = index;
7574     else
7575         maxWhiteSpacePending = index;
7576 }
7577 
7578 bool ASFormatter::isOkToSplitFormattedLine()
7579 {
7580     assert(maxCodeLength != string::npos);
7581     // Is it OK to split the line?
7582     if (shouldKeepLineUnbroken
7583             || isInLineComment
7584             || isInComment
7585             || isInQuote
7586             || isInCase
7587             || isInPreprocessor
7588             || isInExecSQL
7589             || isInAsm || isInAsmOneLine || isInAsmBlock
7590             || isInTemplate)
7591         return false;
7592 
7593     if (!isOkToBreakBlock(braceTypeStack->back()) && currentChar != '{')
7594     {
7595         shouldKeepLineUnbroken = true;
7596         clearFormattedLineSplitPoints();
7597         return false;
7598     }
7599     if (isBraceType(braceTypeStack->back(), ARRAY_TYPE))
7600     {
7601         shouldKeepLineUnbroken = true;
7602         if (!isBraceType(braceTypeStack->back(), ARRAY_NIS_TYPE))
7603             clearFormattedLineSplitPoints();
7604         return false;
7605     }
7606     return true;
7607 }
7608 
7609 /* This is called if the option maxCodeLength is set.
7610  */
7611 void ASFormatter::testForTimeToSplitFormattedLine()
7612 {
7613     //  DO NOT ASSERT maxCodeLength HERE
7614     // should the line be split
7615     if (formattedLine.length() > maxCodeLength && !isLineReady)
7616     {
7617         size_t splitPoint = findFormattedLineSplitPoint();
7618         if (splitPoint > 0 && splitPoint < formattedLine.length())
7619         {
7620             string splitLine = formattedLine.substr(splitPoint);
7621             formattedLine = formattedLine.substr(0, splitPoint);
7622             breakLine(true);
7623             formattedLine = splitLine;
7624             // if break-blocks is requested and this is a one-line statement
7625             string nextWord = ASBeautifier::getNextWord(currentLine, charNum - 1);
7626             if (isAppendPostBlockEmptyLineRequested
7627                     && (nextWord == "break" || nextWord == "continue"))
7628             {
7629                 isAppendPostBlockEmptyLineRequested = false;
7630                 isPrependPostBlockEmptyLineRequested = true;
7631             }
7632             else
7633                 isPrependPostBlockEmptyLineRequested = false;
7634             // adjust max split points
7635             maxAndOr = (maxAndOr > splitPoint) ? (maxAndOr - splitPoint) : 0;
7636             maxSemi = (maxSemi > splitPoint) ? (maxSemi - splitPoint) : 0;
7637             maxComma = (maxComma > splitPoint) ? (maxComma - splitPoint) : 0;
7638             maxParen = (maxParen > splitPoint) ? (maxParen - splitPoint) : 0;
7639             maxWhiteSpace = (maxWhiteSpace > splitPoint) ? (maxWhiteSpace - splitPoint) : 0;
7640             if (maxSemiPending > 0)
7641             {
7642                 maxSemi = (maxSemiPending > splitPoint) ? (maxSemiPending - splitPoint) : 0;
7643                 maxSemiPending = 0;
7644             }
7645             if (maxAndOrPending > 0)
7646             {
7647                 maxAndOr = (maxAndOrPending > splitPoint) ? (maxAndOrPending - splitPoint) : 0;
7648                 maxAndOrPending = 0;
7649             }
7650             if (maxCommaPending > 0)
7651             {
7652                 maxComma = (maxCommaPending > splitPoint) ? (maxCommaPending - splitPoint) : 0;
7653                 maxCommaPending = 0;
7654             }
7655             if (maxParenPending > 0)
7656             {
7657                 maxParen = (maxParenPending > splitPoint) ? (maxParenPending - splitPoint) : 0;
7658                 maxParenPending = 0;
7659             }
7660             if (maxWhiteSpacePending > 0)
7661             {
7662                 maxWhiteSpace = (maxWhiteSpacePending > splitPoint) ? (maxWhiteSpacePending - splitPoint) : 0;
7663                 maxWhiteSpacePending = 0;
7664             }
7665             // don't allow an empty formatted line
7666             size_t firstText = formattedLine.find_first_not_of(" \t");
7667             if (firstText == string::npos && formattedLine.length() > 0)
7668             {
7669                 formattedLine.erase();
7670                 clearFormattedLineSplitPoints();
7671                 if (isWhiteSpace(currentChar))
7672                     for (size_t i = charNum + 1; i < currentLine.length() && isWhiteSpace(currentLine[i]); i++)
7673                         goForward(1);
7674             }
7675             else if (firstText > 0)
7676             {
7677                 formattedLine.erase(0, firstText);
7678                 maxSemi = (maxSemi > firstText) ? (maxSemi - firstText) : 0;
7679                 maxAndOr = (maxAndOr > firstText) ? (maxAndOr - firstText) : 0;
7680                 maxComma = (maxComma > firstText) ? (maxComma - firstText) : 0;
7681                 maxParen = (maxParen > firstText) ? (maxParen - firstText) : 0;
7682                 maxWhiteSpace = (maxWhiteSpace > firstText) ? (maxWhiteSpace - firstText) : 0;
7683             }
7684             // reset formattedLineCommentNum
7685             if (formattedLineCommentNum != string::npos)
7686             {
7687                 formattedLineCommentNum = formattedLine.find("//");
7688                 if (formattedLineCommentNum == string::npos)
7689                     formattedLineCommentNum = formattedLine.find("/*");
7690             }
7691         }
7692     }
7693 }
7694 
7695 size_t ASFormatter::findFormattedLineSplitPoint() const
7696 {
7697     assert(maxCodeLength != string::npos);
7698     // determine where to split
7699     size_t minCodeLength = 10;
7700     size_t splitPoint = 0;
7701     splitPoint = maxSemi;
7702     if (maxAndOr >= minCodeLength)
7703         splitPoint = maxAndOr;
7704     if (splitPoint < minCodeLength)
7705     {
7706         splitPoint = maxWhiteSpace;
7707         // use maxParen instead if it is long enough
7708         if (maxParen > splitPoint
7709                 || maxParen >= maxCodeLength * .7)
7710             splitPoint = maxParen;
7711         // use maxComma instead if it is long enough
7712         // increasing the multiplier causes more splits at whitespace
7713         if (maxComma > splitPoint
7714                 || maxComma >= maxCodeLength * .3)
7715             splitPoint = maxComma;
7716     }
7717     // replace split point with first available break point
7718     if (splitPoint < minCodeLength)
7719     {
7720         splitPoint = string::npos;
7721         if (maxSemiPending > 0 && maxSemiPending < splitPoint)
7722             splitPoint = maxSemiPending;
7723         if (maxAndOrPending > 0 && maxAndOrPending < splitPoint)
7724             splitPoint = maxAndOrPending;
7725         if (maxCommaPending > 0 && maxCommaPending < splitPoint)
7726             splitPoint = maxCommaPending;
7727         if (maxParenPending > 0 && maxParenPending < splitPoint)
7728             splitPoint = maxParenPending;
7729         if (maxWhiteSpacePending > 0 && maxWhiteSpacePending < splitPoint)
7730             splitPoint = maxWhiteSpacePending;
7731         if (splitPoint == string::npos)
7732             splitPoint = 0;
7733     }
7734     // if remaining line after split is too long
7735     else if (formattedLine.length() - splitPoint > maxCodeLength)
7736     {
7737         // if end of the currentLine, find a new split point
7738         size_t newCharNum;
7739         if (!isWhiteSpace(currentChar) && isCharPotentialHeader(currentLine, charNum))
7740             newCharNum = getCurrentWord(currentLine, charNum).length() + charNum;
7741         else
7742             newCharNum = charNum + 2;
7743         if (newCharNum + 1 > currentLine.length())
7744         {
7745             // don't move splitPoint from before a conditional to after
7746             if (maxWhiteSpace > splitPoint + 3)
7747                 splitPoint = maxWhiteSpace;
7748             if (maxParen > splitPoint)
7749                 splitPoint = maxParen;
7750         }
7751     }
7752 
7753     return splitPoint;
7754 }
7755 
7756 void ASFormatter::clearFormattedLineSplitPoints()
7757 {
7758     maxSemi = 0;
7759     maxAndOr = 0;
7760     maxComma = 0;
7761     maxParen = 0;
7762     maxWhiteSpace = 0;
7763     maxSemiPending = 0;
7764     maxAndOrPending = 0;
7765     maxCommaPending = 0;
7766     maxParenPending = 0;
7767     maxWhiteSpacePending = 0;
7768 }
7769 
7770 /**
7771  * Check if a pointer symbol (->) follows on the currentLine.
7772  */
7773 bool ASFormatter::pointerSymbolFollows() const
7774 {
7775     size_t peekNum = currentLine.find_first_not_of(" \t", charNum + 1);
7776     if (peekNum == string::npos || currentLine.compare(peekNum, 2, "->") != 0)
7777         return false;
7778     return true;
7779 }
7780 
7781 /**
7782  * Compute the input checksum.
7783  * This is called as an assert so it for is debug config only
7784  */
7785 bool ASFormatter::computeChecksumIn(const string& currentLine_)
7786 {
7787     for (size_t i = 0; i < currentLine_.length(); i++)
7788         if (!isWhiteSpace(currentLine_[i]))
7789             checksumIn += currentLine_[i];
7790     return true;
7791 }
7792 
7793 /**
7794  * Adjust the input checksum for deleted chars.
7795  * This is called as an assert so it for is debug config only
7796  */
7797 bool ASFormatter::adjustChecksumIn(int adjustment)
7798 {
7799     checksumIn += adjustment;
7800     return true;
7801 }
7802 
7803 /**
7804  * get the value of checksumIn for unit testing
7805  *
7806  * @return   checksumIn.
7807  */
7808 size_t ASFormatter::getChecksumIn() const
7809 {
7810     return checksumIn;
7811 }
7812 
7813 /**
7814  * Compute the output checksum.
7815  * This is called as an assert so it is for debug config only
7816  */
7817 bool ASFormatter::computeChecksumOut(const string& beautifiedLine)
7818 {
7819     for (size_t i = 0; i < beautifiedLine.length(); i++)
7820         if (!isWhiteSpace(beautifiedLine[i]))
7821             checksumOut += beautifiedLine[i];
7822     return true;
7823 }
7824 
7825 /**
7826  * Return isLineReady for the final check at end of file.
7827  */
7828 bool ASFormatter::getIsLineReady() const
7829 {
7830     return isLineReady;
7831 }
7832 
7833 /**
7834  * get the value of checksumOut for unit testing
7835  *
7836  * @return   checksumOut.
7837  */
7838 size_t ASFormatter::getChecksumOut() const
7839 {
7840     return checksumOut;
7841 }
7842 
7843 /**
7844  * Return the difference in checksums.
7845  * If zero all is okay.
7846  */
7847 int ASFormatter::getChecksumDiff() const
7848 {
7849     return checksumOut - checksumIn;
7850 }
7851 
7852 // for unit testing
7853 int ASFormatter::getFormatterFileType() const
7854 {
7855     return formatterFileType;
7856 }
7857 
7858 // Check if an operator follows the next word.
7859 // The next word must be a legal name.
7860 const string* ASFormatter::getFollowingOperator() const
7861 {
7862     // find next word
7863     size_t nextNum = currentLine.find_first_not_of(" \t", charNum + 1);
7864     if (nextNum == string::npos)
7865         return nullptr;
7866 
7867     if (!isLegalNameChar(currentLine[nextNum]))
7868         return nullptr;
7869 
7870     // bypass next word and following spaces
7871     while (nextNum < currentLine.length())
7872     {
7873         if (!isLegalNameChar(currentLine[nextNum])
7874                 && !isWhiteSpace(currentLine[nextNum]))
7875             break;
7876         nextNum++;
7877     }
7878 
7879     if (nextNum >= currentLine.length()
7880             || !isCharPotentialOperator(currentLine[nextNum])
7881             || currentLine[nextNum] == '/')     // comment
7882         return nullptr;
7883 
7884     const string* newOperator = ASBase::findOperator(currentLine, nextNum, operators);
7885     return newOperator;
7886 }
7887 
7888 // Check following data to determine if the current character is an array operator.
7889 bool ASFormatter::isArrayOperator() const
7890 {
7891     assert(currentChar == '*' || currentChar == '&' || currentChar == '^');
7892     assert(isBraceType(braceTypeStack->back(), ARRAY_TYPE));
7893 
7894     // find next word
7895     size_t nextNum = currentLine.find_first_not_of(" \t", charNum + 1);
7896     if (nextNum == string::npos)
7897         return false;
7898 
7899     if (!isLegalNameChar(currentLine[nextNum]))
7900         return false;
7901 
7902     // bypass next word and following spaces
7903     while (nextNum < currentLine.length())
7904     {
7905         if (!isLegalNameChar(currentLine[nextNum])
7906                 && !isWhiteSpace(currentLine[nextNum]))
7907             break;
7908         nextNum++;
7909     }
7910 
7911     // check for characters that indicate an operator
7912     if (currentLine[nextNum] == ','
7913             || currentLine[nextNum] == '}'
7914             || currentLine[nextNum] == ')'
7915             || currentLine[nextNum] == '(')
7916         return true;
7917     return false;
7918 }
7919 
7920 // Reset the flags that indicate various statement information.
7921 void ASFormatter::resetEndOfStatement()
7922 {
7923     foundQuestionMark = false;
7924     foundNamespaceHeader = false;
7925     foundClassHeader = false;
7926     foundStructHeader = false;
7927     foundInterfaceHeader = false;
7928     foundPreDefinitionHeader = false;
7929     foundPreCommandHeader = false;
7930     foundPreCommandMacro = false;
7931     foundTrailingReturnType = false;
7932     foundCastOperator = false;
7933     isInPotentialCalculation = false;
7934     isSharpAccessor = false;
7935     isSharpDelegate = false;
7936     isInObjCMethodDefinition = false;
7937     isImmediatelyPostObjCMethodPrefix = false;
7938     isInObjCReturnType = false;
7939     isInObjCParam = false;
7940     isInObjCInterface = false;
7941     isInObjCSelector = false;
7942     isInEnum = false;
7943     isInExternC = false;
7944     elseHeaderFollowsComments = false;
7945     returnTypeChecked = false;
7946     nonInStatementBrace = 0;
7947     while (!questionMarkStack->empty())
7948         questionMarkStack->pop_back();
7949 }
7950 
7951 // Find the colon alignment for Objective-C method definitions and method calls.
7952 int ASFormatter::findObjCColonAlignment() const
7953 {
7954     assert(currentChar == '+' || currentChar == '-' || currentChar == '[');
7955     assert(getAlignMethodColon());
7956 
7957     bool isFirstLine = true;
7958     bool haveFirstColon = false;
7959     bool foundMethodColon = false;
7960     bool isInComment_ = false;
7961     bool isInQuote_ = false;
7962     bool haveTernary = false;
7963     char quoteChar_ = ' ';
7964     int  sqBracketCount = 0;
7965     int  colonAdjust = 0;
7966     int  colonAlign = 0;
7967     string nextLine_ = currentLine;
7968     ASPeekStream stream(sourceIterator);
7969 
7970     // peek next line
7971     while (sourceIterator->hasMoreLines() || isFirstLine)
7972     {
7973         if (!isFirstLine)
7974             nextLine_ = stream.peekNextLine();
7975         // parse the line
7976         haveFirstColon = false;
7977         nextLine_ = ASBeautifier::trim(nextLine_);
7978         for (size_t i = 0; i < nextLine_.length(); i++)
7979         {
7980             if (isWhiteSpace(nextLine_[i]))
7981                 continue;
7982             if (nextLine_.compare(i, 2, "/*") == 0)
7983                 isInComment_ = true;
7984             if (isInComment_)
7985             {
7986                 if (nextLine_.compare(i, 2, "*/") == 0)
7987                 {
7988                     isInComment_ = false;
7989                     ++i;
7990                 }
7991                 continue;
7992             }
7993             if (nextLine_[i] == '\\')
7994             {
7995                 ++i;
7996                 continue;
7997             }
7998             if (isInQuote_)
7999             {
8000                 if (nextLine_[i] == quoteChar_)
8001                     isInQuote_ = false;
8002                 continue;
8003             }
8004 
8005             if (nextLine_[i] == '"'
8006                     || (nextLine_[i] == '\'' && !isDigitSeparator(nextLine_, i)))
8007             {
8008                 isInQuote_ = true;
8009                 quoteChar_ = nextLine_[i];
8010                 continue;
8011             }
8012             if (nextLine_.compare(i, 2, "//") == 0)
8013             {
8014                 i = nextLine_.length();
8015                 continue;
8016             }
8017             // process the current char
8018             if ((nextLine_[i] == '{' && (currentChar == '-' || currentChar == '+'))
8019                     || nextLine_[i] == ';')
8020                 goto EndOfWhileLoop;       // end of method definition
8021             if (nextLine_[i] == ']')
8022             {
8023                 --sqBracketCount;
8024                 if (sqBracketCount == 0)
8025                     goto EndOfWhileLoop;   // end of method call
8026             }
8027             if (nextLine_[i] == '[')
8028                 ++sqBracketCount;
8029             if (isFirstLine)     // colon align does not include the first line
8030                 continue;
8031             if (sqBracketCount > 1)
8032                 continue;
8033             if (haveFirstColon)  // multiple colons per line
8034                 continue;
8035             if (nextLine_[i] == '?')
8036             {
8037                 haveTernary = true;
8038                 continue;
8039             }
8040             // compute colon adjustment
8041             if (nextLine_[i] == ':')
8042             {
8043                 if (haveTernary)
8044                 {
8045                     haveTernary = false;
8046                     continue;
8047                 }
8048                 haveFirstColon = true;
8049                 foundMethodColon = true;
8050                 if (shouldPadMethodColon)
8051                 {
8052                     int spacesStart;
8053                     for (spacesStart = i; spacesStart > 0; spacesStart--)
8054                         if (!isWhiteSpace(nextLine_[spacesStart - 1]))
8055                             break;
8056                     int spaces = i - spacesStart;
8057                     if (objCColonPadMode == COLON_PAD_ALL || objCColonPadMode == COLON_PAD_BEFORE)
8058                         colonAdjust = 1 - spaces;
8059                     else if (objCColonPadMode == COLON_PAD_NONE || objCColonPadMode == COLON_PAD_AFTER)
8060                         colonAdjust = 0 - spaces;
8061                 }
8062                 // compute alignment
8063                 int colonPosition = i + colonAdjust;
8064                 if (colonPosition > colonAlign)
8065                     colonAlign = colonPosition;
8066             }
8067         }   // end of for loop
8068         isFirstLine = false;
8069     }   // end of while loop
8070 EndOfWhileLoop:
8071     if (!foundMethodColon)
8072         colonAlign = -1;
8073     return colonAlign;
8074 }
8075 
8076 // pad an Objective-C method colon
8077 void ASFormatter::padObjCMethodColon()
8078 {
8079     assert(currentChar == ':');
8080     int commentAdjust = 0;
8081     char nextChar = peekNextChar();
8082     if (objCColonPadMode == COLON_PAD_NONE
8083             || objCColonPadMode == COLON_PAD_AFTER
8084             || nextChar == ')')
8085     {
8086         // remove spaces before
8087         for (int i = formattedLine.length() - 1; (i > -1) && isWhiteSpace(formattedLine[i]); i--)
8088         {
8089             formattedLine.erase(i);
8090             --commentAdjust;
8091         }
8092     }
8093     else
8094     {
8095         // pad space before
8096         for (int i = formattedLine.length() - 1; (i > 0) && isWhiteSpace(formattedLine[i]); i--)
8097             if (isWhiteSpace(formattedLine[i - 1]))
8098             {
8099                 formattedLine.erase(i);
8100                 --commentAdjust;
8101             }
8102         if (formattedLine.length() > 0)
8103         {
8104             appendSpacePad();
8105             formattedLine.back() = ' ';  // convert any tab to space
8106         }
8107     }
8108     if (objCColonPadMode == COLON_PAD_NONE
8109             || objCColonPadMode == COLON_PAD_BEFORE
8110             || nextChar == ')')
8111     {
8112         // remove spaces after
8113         size_t nextText = currentLine.find_first_not_of(" \t", charNum + 1);
8114         if (nextText == string::npos)
8115             nextText = currentLine.length();
8116         int spaces = nextText - charNum - 1;
8117         if (spaces > 0)
8118         {
8119             // do not use goForward here
8120             currentLine.erase(charNum + 1, spaces);
8121             spacePadNum -= spaces;
8122         }
8123     }
8124     else
8125     {
8126         // pad space after
8127         size_t nextText = currentLine.find_first_not_of(" \t", charNum + 1);
8128         if (nextText == string::npos)
8129             nextText = currentLine.length();
8130         int spaces = nextText - charNum - 1;
8131         if (spaces == 0)
8132         {
8133             currentLine.insert(charNum + 1, 1, ' ');
8134             spacePadNum += 1;
8135         }
8136         else if (spaces > 1)
8137         {
8138             // do not use goForward here
8139             currentLine.erase(charNum + 1, spaces - 1);
8140             currentLine[charNum + 1] = ' ';  // convert any tab to space
8141             spacePadNum -= spaces - 1;
8142         }
8143     }
8144     spacePadNum += commentAdjust;
8145 }
8146 
8147 // Remove the leading '*' from a comment line and indent to the next tab.
8148 void ASFormatter::stripCommentPrefix()
8149 {
8150     int firstChar = formattedLine.find_first_not_of(" \t");
8151     if (firstChar < 0)
8152         return;
8153 
8154     if (isInCommentStartLine)
8155     {
8156         // comment opener must begin the line
8157         if (formattedLine.compare(firstChar, 2, "/*") != 0)
8158             return;
8159         int commentOpener = firstChar;
8160         // ignore single line comments
8161         int commentEnd = formattedLine.find("*/", firstChar + 2);
8162         if (commentEnd != -1)
8163             return;
8164         // first char after the comment opener must be at least one indent
8165         int followingText = formattedLine.find_first_not_of(" \t", commentOpener + 2);
8166         if (followingText < 0)
8167             return;
8168         if (formattedLine[followingText] == '*' || formattedLine[followingText] == '!')
8169             followingText = formattedLine.find_first_not_of(" \t", followingText + 1);
8170         if (followingText < 0)
8171             return;
8172         if (formattedLine[followingText] == '*')
8173             return;
8174         int indentLen = getIndentLength();
8175         int followingTextIndent = followingText - commentOpener;
8176         if (followingTextIndent < indentLen)
8177         {
8178             string stringToInsert(indentLen - followingTextIndent, ' ');
8179             formattedLine.insert(followingText, stringToInsert);
8180         }
8181         return;
8182     }
8183     // comment body including the closer
8184     if (formattedLine[firstChar] == '*')
8185     {
8186         if (formattedLine.compare(firstChar, 2, "*/") == 0)
8187         {
8188             // line starts with an end comment
8189             formattedLine = "*/";
8190         }
8191         else
8192         {
8193             // build a new line with one indent
8194             int secondChar = formattedLine.find_first_not_of(" \t", firstChar + 1);
8195             if (secondChar < 0)
8196             {
8197                 adjustChecksumIn(-'*');
8198                 formattedLine.erase();
8199                 return;
8200             }
8201             if (formattedLine[secondChar] == '*')
8202                 return;
8203             // replace the leading '*'
8204             int indentLen = getIndentLength();
8205             adjustChecksumIn(-'*');
8206             // second char must be at least one indent
8207             if (formattedLine.substr(0, secondChar).find('\t') != string::npos)
8208             {
8209                 formattedLine.erase(firstChar, 1);
8210             }
8211             else
8212             {
8213                 int spacesToInsert = 0;
8214                 if (secondChar >= indentLen)
8215                     spacesToInsert = secondChar;
8216                 else
8217                     spacesToInsert = indentLen;
8218                 formattedLine = string(spacesToInsert, ' ') + formattedLine.substr(secondChar);
8219             }
8220             // remove a trailing '*'
8221             int lastChar = formattedLine.find_last_not_of(" \t");
8222             if (lastChar > -1 && formattedLine[lastChar] == '*')
8223             {
8224                 adjustChecksumIn(-'*');
8225                 formattedLine[lastChar] = ' ';
8226             }
8227         }
8228     }
8229     else
8230     {
8231         // first char not a '*'
8232         // first char must be at least one indent
8233         if (formattedLine.substr(0, firstChar).find('\t') == string::npos)
8234         {
8235             int indentLen = getIndentLength();
8236             if (firstChar < indentLen)
8237             {
8238                 string stringToInsert(indentLen, ' ');
8239                 formattedLine = stringToInsert + formattedLine.substr(firstChar);
8240             }
8241         }
8242     }
8243 }
8244 
8245 }   // end namespace astyle