File indexing completed on 2024-04-28 08:27:16

0001 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
0002  *
0003  *   Copyright (C) 2006-2010 by Jim Pattee <jimp03@email.com>
0004  *   Copyright (C) 1998-2002 by Tal Davidson
0005  *   <http://www.gnu.org/licenses/lgpl-3.0.html>
0006  *
0007  *   This file is a part of Artistic Style - an indentation and
0008  *   reformatting tool for C, C++, C# and Java source files.
0009  *   <http://astyle.sourceforge.net>
0010  *
0011  *   Artistic Style is free software: you can redistribute it and/or modify
0012  *   it under the terms of the GNU Lesser General Public License as published
0013  *   by the Free Software Foundation, either version 3 of the License, or
0014  *   (at your option) any later version.
0015  *
0016  *   Artistic Style is distributed in the hope that it will be useful,
0017  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
0018  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0019  *   GNU Lesser General Public License for more details.
0020  *
0021  *   You should have received a copy of the GNU Lesser General Public License
0022  *   along with Artistic Style.  If not, see <http://www.gnu.org/licenses/>.
0023  *
0024  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
0025  */
0026 
0027 #include "astyle.h"
0028 
0029 #include <algorithm>
0030 #include <fstream>
0031 #include <iostream>
0032 
0033 
0034 namespace astyle
0035 {
0036 // static member variables
0037 int ASFormatter::formatterFileType = 9;     // initialized with an invalid type
0038 vector<const string*>* ASFormatter::headers = NULL;
0039 vector<const string*>* ASFormatter::nonParenHeaders = NULL;
0040 vector<const string*>* ASFormatter::preDefinitionHeaders = NULL;
0041 vector<const string*>* ASFormatter::preCommandHeaders = NULL;
0042 vector<const string*>* ASFormatter::operators = NULL;
0043 vector<const string*>* ASFormatter::assignmentOperators = NULL;
0044 vector<const string*>* ASFormatter::castOperators = NULL;
0045 
0046 /**
0047  * Constructor of ASFormatter
0048  */
0049 ASFormatter::ASFormatter()
0050 {
0051     sourceIterator = NULL;
0052     enhancer = new ASEnhancer;
0053     preBracketHeaderStack = NULL;
0054     bracketTypeStack = NULL;
0055     parenStack = NULL;
0056     structStack = NULL;
0057     lineCommentNoIndent = false;
0058     formattingStyle = STYLE_NONE;
0059     bracketFormatMode = NONE_MODE;
0060     pointerAlignment = ALIGN_NONE;
0061     lineEnd = LINEEND_DEFAULT;
0062     shouldPadOperators = false;
0063     shouldPadParensOutside = false;
0064     shouldPadParensInside = false;
0065     shouldPadHeader = false;
0066     shouldUnPadParens = false;
0067     shouldBreakOneLineBlocks = true;
0068     shouldBreakOneLineStatements = true;
0069     shouldConvertTabs = false;
0070     shouldIndentCol1Comments = false;
0071     shouldBreakBlocks = false;
0072     shouldBreakClosingHeaderBlocks = false;
0073     shouldBreakClosingHeaderBrackets = false;
0074     shouldDeleteEmptyLines = false;
0075     shouldBreakElseIfs = false;
0076     shouldAddBrackets = false;
0077     shouldAddOneLineBrackets = false;
0078 
0079     // initialize ASFormatter static member vectors
0080     formatterFileType = 9;      // reset to an invalid type
0081     initVector(headers);
0082     initVector(nonParenHeaders);
0083     initVector(preDefinitionHeaders);
0084     initVector(preCommandHeaders);
0085     initVector(operators);
0086     initVector(assignmentOperators);
0087     initVector(castOperators);
0088 
0089     // the following prevents warning messages with cppcheck
0090     // it will NOT compile if activated
0091 //  init();
0092 }
0093 
0094 /**
0095  * Destructor of ASFormatter
0096  */
0097 ASFormatter::~ASFormatter()
0098 {
0099     // delete ASFormatter stack vectors
0100     deleteContainer(preBracketHeaderStack);
0101     deleteContainer(bracketTypeStack);
0102     deleteContainer(parenStack);
0103     deleteContainer(structStack);
0104 
0105     // delete static member vectors using swap to eliminate memory leak reporting
0106     // delete ASFormatter static member vectors
0107     formatterFileType = 9;      // reset to an invalid type
0108     deleteVector(headers);
0109     deleteVector(nonParenHeaders);
0110     deleteVector(preDefinitionHeaders);
0111     deleteVector(preCommandHeaders);
0112     deleteVector(operators);
0113     deleteVector(assignmentOperators);
0114     deleteVector(castOperators);
0115 
0116     // delete ASBeautifier static member vectors
0117     // must be done when the ASFormatter object is deleted (not ASBeautifier)
0118     ASBeautifier::deleteStaticVectors();
0119 
0120     delete enhancer;
0121 }
0122 
0123 /**
0124  * initialize the ASFormatter.
0125  *
0126  * init() should be called every time a ASFormatter object is to start
0127  * formatting a NEW source file.
0128  * init() recieves a pointer to a ASSourceIterator object that will be
0129  * used to iterate through the source code.
0130  *
0131  * @param sourceIterator     a pointer to the ASSourceIterator or ASStreamIterator object.
0132  */
0133 void ASFormatter::init(ASSourceIterator *si)
0134 {
0135     buildLanguageVectors();
0136     fixOptionVariableConflicts();
0137 
0138     ASBeautifier::init(si);
0139     enhancer->init(getFileType(),
0140                    getIndentLength(),
0141                    getIndentString(),
0142                    getCaseIndent(),
0143                    getEmptyLineFill());
0144     sourceIterator = si;
0145 
0146     initContainer(preBracketHeaderStack, new vector<const string*>);
0147     initContainer(parenStack, new vector<int>);
0148     initContainer(structStack, new vector<bool>);
0149     parenStack->push_back(0);               // parenStack must contain this default entry
0150     initContainer(bracketTypeStack, new vector<BracketType>);
0151     bracketTypeStack->push_back(NULL_TYPE);
0152 
0153     currentHeader = NULL;
0154     currentLine = "";
0155     readyFormattedLine = "";
0156     formattedLine = "";
0157     currentChar = ' ';
0158     previousChar = ' ';
0159     previousCommandChar = ' ';
0160     previousNonWSChar = ' ';
0161     quoteChar = '"';
0162     charNum = 0;
0163     leadingSpaces = 0;
0164     formattedLineCommentNum = 0;
0165     preprocBracketTypeStackSize = 0;
0166     spacePadNum = 0;
0167     nextLineSpacePadNum = 0;
0168     currentLineFirstBracketNum = string::npos;
0169     previousReadyFormattedLineLength = string::npos;
0170     templateDepth = 0;
0171     traceLineNumber = 0;
0172     horstmannIndentChars = 0;
0173     tabIncrementIn = 0;
0174     previousBracketType = NULL_TYPE;
0175     previousOperator = NULL;
0176 
0177     isVirgin = true;
0178     isInLineComment = false;
0179     isInComment = false;
0180     noTrimCommentContinuation = false;
0181     isInPreprocessor = false;
0182     doesLineStartComment = false;
0183     lineEndsInCommentOnly = false;
0184     lineIsLineCommentOnly = false;
0185     lineIsEmpty = false;
0186     isImmediatelyPostCommentOnly = false;
0187     isImmediatelyPostEmptyLine = false;
0188     isInQuote = false;
0189     isInVerbatimQuote = false;
0190     haveLineContinuationChar = false;
0191     isInQuoteContinuation = false;
0192     isSpecialChar = false;
0193     isNonParenHeader = false;
0194     foundNamespaceHeader = false;
0195     foundClassHeader = false;
0196     foundStructHeader = false;
0197     foundInterfaceHeader = false;
0198     foundPreDefinitionHeader = false;
0199     foundPreCommandHeader = false;
0200     foundCastOperator = false;
0201     foundQuestionMark = false;
0202     isInLineBreak = false;
0203     endOfCodeReached = false;
0204     isInExecSQL = false;
0205     isInAsm = false;
0206     isInAsmOneLine = false;
0207     isInAsmBlock = false;
0208     isLineReady = false;
0209     isPreviousBracketBlockRelated = false;
0210     isInPotentialCalculation = false;
0211     shouldReparseCurrentChar = false;
0212     needHeaderOpeningBracket = false;
0213     shouldBreakLineAtNextChar = false;
0214     passedSemicolon = false;
0215     passedColon = false;
0216     clearNonInStatement = false;
0217     isInTemplate = false;
0218     isInBlParen = false;
0219     isImmediatelyPostComment = false;
0220     isImmediatelyPostLineComment = false;
0221     isImmediatelyPostEmptyBlock = false;
0222     isImmediatelyPostPreprocessor = false;
0223     isImmediatelyPostReturn = false;
0224     isImmediatelyPostOperator = false;
0225     isCharImmediatelyPostReturn = false;
0226     isCharImmediatelyPostOperator = false;
0227     isCharImmediatelyPostComment = false;
0228     isPreviousCharPostComment = false;
0229     isCharImmediatelyPostLineComment = false;
0230     isCharImmediatelyPostOpenBlock = false;
0231     isCharImmediatelyPostCloseBlock = false;
0232     isCharImmediatelyPostTemplate = false;
0233     breakCurrentOneLineBlock = false;
0234     isInHorstmannRunIn = false;
0235     currentLineBeginsWithBracket = false;
0236     isPrependPostBlockEmptyLineRequested = false;
0237     isAppendPostBlockEmptyLineRequested = false;
0238     prependEmptyLine = false;
0239     appendOpeningBracket = false;
0240     foundClosingHeader = false;
0241     isImmediatelyPostHeader = false;
0242     isInHeader = false;
0243     isInCase = false;
0244     isJavaStaticConstructor = false;
0245 }
0246 
0247 /**
0248  * build vectors for each programing language
0249  * depending on the file extension.
0250  */
0251 void ASFormatter::buildLanguageVectors()
0252 {
0253     if (getFileType() == formatterFileType)  // don't build unless necessary
0254         return;
0255 
0256     formatterFileType = getFileType();
0257 
0258     headers->clear();
0259     nonParenHeaders->clear();
0260     preDefinitionHeaders->clear();
0261     preCommandHeaders->clear();
0262     operators->clear();
0263     assignmentOperators->clear();
0264     castOperators->clear();
0265 
0266     ASResource::buildHeaders(headers, getFileType());
0267     ASResource::buildNonParenHeaders(nonParenHeaders, getFileType());
0268     ASResource::buildPreDefinitionHeaders(preDefinitionHeaders, getFileType());
0269     ASResource::buildPreCommandHeaders(preCommandHeaders, getFileType());
0270     if (operators->size() == 0)
0271         ASResource::buildOperators(operators);
0272     if (assignmentOperators->size() == 0)
0273         ASResource::buildAssignmentOperators(assignmentOperators);
0274     if (castOperators->size() == 0)
0275         ASResource::buildCastOperators(castOperators);
0276 }
0277 
0278 /**
0279  * set the variables for each preefined style.
0280  * this will override any previous settings.
0281  */
0282 void ASFormatter::fixOptionVariableConflicts()
0283 {
0284     if (formattingStyle == STYLE_ALLMAN)
0285     {
0286         setBracketFormatMode(BREAK_MODE);
0287         setBlockIndent(false);
0288         setBracketIndent(false);
0289     }
0290     else if (formattingStyle == STYLE_JAVA)
0291     {
0292         setBracketFormatMode(ATTACH_MODE);
0293         setBlockIndent(false);
0294         setBracketIndent(false);
0295     }
0296     else if (formattingStyle == STYLE_KandR)
0297     {
0298         setBracketFormatMode(LINUX_MODE);
0299         setBlockIndent(false);
0300         setBracketIndent(false);
0301     }
0302     else if (formattingStyle == STYLE_STROUSTRUP)
0303     {
0304         setBracketFormatMode(STROUSTRUP_MODE);
0305         setBlockIndent(false);
0306         setBracketIndent(false);
0307         if (!getIndentManuallySet())
0308         {
0309             if (getIndentString() == "\t")
0310                 setTabIndentation(5, getForceTabIndentation());
0311             else
0312                 setSpaceIndentation(5);
0313         }
0314     }
0315     else if (formattingStyle == STYLE_WHITESMITH)
0316     {
0317         setBracketFormatMode(BREAK_MODE);
0318         setBlockIndent(false);
0319         setBracketIndent(true);
0320         setClassIndent(true);
0321         setSwitchIndent(true);
0322     }
0323     else if (formattingStyle == STYLE_BANNER)
0324     {
0325         setBracketFormatMode(ATTACH_MODE);
0326         setBlockIndent(false);
0327         setBracketIndent(true);
0328         setClassIndent(true);
0329         setSwitchIndent(true);
0330     }
0331     else if (formattingStyle == STYLE_GNU)
0332     {
0333         setBracketFormatMode(BREAK_MODE);
0334         setBlockIndent(true);
0335         setBracketIndent(false);
0336         if (!getIndentManuallySet())
0337         {
0338             if (getIndentString() == "\t")
0339                 setTabIndentation(2, getForceTabIndentation());
0340             else
0341                 setSpaceIndentation(2);
0342         }
0343     }
0344     else if (formattingStyle == STYLE_LINUX)
0345     {
0346         setBracketFormatMode(LINUX_MODE);
0347         setBlockIndent(false);
0348         setBracketIndent(false);
0349         if (!getIndentManuallySet())
0350         {
0351             if (getIndentString() == "\t")
0352                 setTabIndentation(8, getForceTabIndentation());
0353             else
0354                 setSpaceIndentation(8);
0355         }
0356         if (!getMinConditionalManuallySet())
0357             setMinConditionalIndentLength(getIndentLength() / 2);
0358     }
0359     else if (formattingStyle == STYLE_HORSTMANN)
0360     {
0361         setBracketFormatMode(HORSTMANN_MODE);
0362         setBlockIndent(false);
0363         setBracketIndent(false);
0364         setSwitchIndent(true);
0365         if (!getIndentManuallySet())
0366         {
0367             if (getIndentString() == "\t")
0368                 setTabIndentation(3, getForceTabIndentation());
0369             else
0370                 setSpaceIndentation(3);
0371         }
0372     }
0373     else if (formattingStyle == STYLE_1TBS)
0374     {
0375         setBracketFormatMode(LINUX_MODE);
0376         setBlockIndent(false);
0377         setBracketIndent(false);
0378         setAddBracketsMode(true);
0379     }
0380 
0381     // add-one-line-brackets implies keep-one-line-blocks
0382     if (shouldAddOneLineBrackets)
0383         setBreakOneLineBlocksMode(false);
0384     // cannot have both indent-blocks and indent-brackets, default to indent-blocks
0385     if (getBlockIndent())
0386         setBracketIndent(false);
0387 }
0388 
0389 /**
0390  * get the next formatted line.
0391  *
0392  * @return    formatted line.
0393  */
0394 
0395 string ASFormatter::nextLine()
0396 {
0397     const string *newHeader;
0398     bool isInVirginLine = isVirgin;
0399     isCharImmediatelyPostComment = false;
0400     isPreviousCharPostComment = false;
0401     isCharImmediatelyPostLineComment = false;
0402     isCharImmediatelyPostOpenBlock = false;
0403     isCharImmediatelyPostCloseBlock = false;
0404     isCharImmediatelyPostTemplate = false;
0405     traceLineNumber++;
0406 
0407     while (!isLineReady)
0408     {
0409         if (shouldReparseCurrentChar)
0410             shouldReparseCurrentChar = false;
0411         else if (!getNextChar())
0412         {
0413             breakLine();
0414             return beautify(readyFormattedLine);
0415         }
0416         else // stuff to do when reading a new character...
0417         {
0418             // make sure that a virgin '{' at the begining of the file will be treated as a block...
0419             if (isInVirginLine && currentChar == '{'
0420                     && currentLineBeginsWithBracket // lineBeginsWith('{')
0421                     && previousCommandChar == ' ')
0422                 previousCommandChar = '{';
0423             if (clearNonInStatement)
0424             {
0425                 isNonInStatementArray = false;
0426                 clearNonInStatement = false;
0427             }
0428             if (isInHorstmannRunIn)
0429                 isInLineBreak = false;
0430             if (!isWhiteSpace(currentChar))
0431                 isInHorstmannRunIn = false;
0432             isPreviousCharPostComment = isCharImmediatelyPostComment;
0433             isCharImmediatelyPostComment = false;
0434             isCharImmediatelyPostTemplate = false;
0435             isCharImmediatelyPostReturn = false;
0436             isCharImmediatelyPostOperator = false;
0437             isCharImmediatelyPostOpenBlock = false;
0438             isCharImmediatelyPostCloseBlock = false;
0439         }
0440 
0441 //      if (inLineNumber >= 7)
0442 //          int x = 1;
0443 
0444         if (shouldBreakLineAtNextChar && !isWhiteSpace(currentChar))
0445         {
0446             isInLineBreak = true;
0447             shouldBreakLineAtNextChar = false;
0448         }
0449 
0450         if (isInExecSQL && !passedSemicolon)
0451         {
0452             if (currentChar == ';')
0453                 passedSemicolon = true;
0454             appendCurrentChar();
0455             continue;
0456         }
0457 
0458         if (isInLineComment)
0459         {
0460             formatLineCommentBody();
0461             continue;
0462         }
0463         else if (isInComment)
0464         {
0465             formatCommentBody();
0466             continue;
0467         }
0468 
0469         // not in line comment or comment
0470 
0471         else if (isInQuote)
0472         {
0473             formatQuoteBody();
0474             continue;
0475         }
0476 
0477         if (isSequenceReached("//"))
0478         {
0479             formatLineCommentOpener();
0480             continue;
0481         }
0482         else if (isSequenceReached("/*"))
0483         {
0484             formatCommentOpener();
0485             continue;
0486         }
0487         else if (currentChar == '"' || currentChar == '\'')
0488         {
0489             formatQuoteOpener();
0490             continue;
0491         }
0492         // treat these preprocessor statements as a line comment
0493         else if (currentChar =='#')
0494         {
0495             if (isSequenceReached("#region")
0496                     || isSequenceReached("#endregion")
0497                     || isSequenceReached("#error")
0498                     || isSequenceReached("#warning"))
0499             {
0500                 // check for horstmann run-in
0501                 if (formattedLine[0] == '{')
0502                 {
0503                     isInLineBreak = true;
0504                     isInHorstmannRunIn = false;
0505                 }
0506                 isInLineComment = true;
0507                 appendCurrentChar();
0508                 continue;
0509             }
0510         }
0511 
0512         if (isInPreprocessor)
0513         {
0514             appendCurrentChar();
0515             continue;
0516         }
0517 
0518         // handle white space - needed to simplify the rest.
0519         if (isWhiteSpace(currentChar))
0520         {
0521             appendCurrentChar();
0522             continue;
0523         }
0524 
0525         /* not in MIDDLE of quote or comment or SQL or white-space of any type ... */
0526 
0527         // check if in preprocessor
0528         // ** isInPreprocessor will be automatically reset at the begining
0529         //    of a new line in getnextChar()
0530         if (currentChar == '#')
0531         {
0532             isInPreprocessor = true;
0533             // check for horstmann run-in
0534             if (formattedLine[0] == '{')
0535             {
0536                 isInLineBreak = true;
0537                 isInHorstmannRunIn = false;
0538             }
0539             processPreprocessor();
0540             //  need to fall thru here to reset the variables
0541         }
0542 
0543         /* not in preprocessor ... */
0544 
0545         if (isImmediatelyPostComment)
0546         {
0547             isImmediatelyPostComment = false;
0548             isCharImmediatelyPostComment = true;
0549         }
0550 
0551         if (isImmediatelyPostLineComment)
0552         {
0553             isImmediatelyPostLineComment = false;
0554             isCharImmediatelyPostLineComment = true;
0555         }
0556 
0557         if (isImmediatelyPostReturn)
0558         {
0559             isImmediatelyPostReturn = false;
0560             isCharImmediatelyPostReturn = true;
0561         }
0562 
0563         if (isImmediatelyPostOperator)
0564         {
0565             isImmediatelyPostOperator = false;
0566             isCharImmediatelyPostOperator = true;
0567         }
0568 
0569         // reset isImmediatelyPostHeader information
0570         if (isImmediatelyPostHeader)
0571         {
0572             // should brackets be added
0573             if (currentChar != '{' && shouldAddBrackets)
0574             {
0575                 bool bracketsAdded = addBracketsToStatement();
0576                 if (bracketsAdded && !shouldAddOneLineBrackets)
0577                 {
0578                     size_t firstText = currentLine.find_first_not_of(" \t");
0579                     assert(firstText != string::npos);
0580                     if ((int) firstText == charNum)
0581                         breakCurrentOneLineBlock = true;
0582                 }
0583             }
0584 
0585             // Make sure headers are broken from their succeeding blocks
0586             // (e.g.
0587             //     if (isFoo) DoBar();
0588             //  should become
0589             //     if (isFoo)
0590             //         DoBar;
0591             // )
0592             // But treat else if() as a special case which should not be broken!
0593             if (shouldBreakOneLineStatements
0594                     && isOkToBreakBlock(bracketTypeStack->back()))
0595             {
0596                 // if may break 'else if()'s, then simply break the line
0597                 if (shouldBreakElseIfs)
0598                     isInLineBreak = true;
0599             }
0600 
0601             isImmediatelyPostHeader = false;
0602         }
0603 
0604         if (passedSemicolon)    // need to break the formattedLine
0605         {
0606             passedSemicolon = false;
0607             if (parenStack->back() == 0 && currentChar != ';') // allow ;;
0608             {
0609                 // does a one-line statement have ending comments?
0610                 if (isBracketType(bracketTypeStack->back(), SINGLE_LINE_TYPE))
0611                 {
0612                     size_t blockEnd = currentLine.rfind(AS_CLOSE_BRACKET);
0613                     assert(blockEnd != string::npos);
0614                     // move ending comments to this formattedLine
0615                     if (isBeforeAnyLineEndComment(blockEnd))
0616                     {
0617                         size_t commentStart = currentLine.find_first_not_of(" \t", blockEnd + 1);
0618                         assert(commentStart != string::npos);
0619                         assert((currentLine.compare(commentStart, 2, "//") == 0)
0620                                || (currentLine.compare(commentStart, 2, "/*") == 0));
0621                         size_t commentLength = currentLine.length() - commentStart;
0622                         formattedLine.append(getIndentLength() - 1, ' ');
0623                         formattedLine.append(currentLine, commentStart, commentLength);
0624                         currentLine.erase(commentStart, commentLength);
0625                     }
0626                 }
0627                 isInExecSQL = false;
0628                 shouldReparseCurrentChar = true;
0629                 isInLineBreak = true;
0630                 if (needHeaderOpeningBracket)
0631                 {
0632                     isCharImmediatelyPostCloseBlock = true;
0633                     needHeaderOpeningBracket = false;
0634                 }
0635                 continue;
0636             }
0637         }
0638 
0639         if (passedColon)
0640         {
0641             passedColon = false;
0642             if (parenStack->back() == 0 && !isBeforeAnyComment())
0643             {
0644                 shouldReparseCurrentChar = true;
0645                 isInLineBreak = true;
0646                 continue;
0647             }
0648         }
0649 
0650         // Check if in template declaration, e.g. foo<bar> or foo<bar,fig>
0651         // If so, set isInTemplate to true
0652         if (!isInTemplate && currentChar == '<')
0653         {
0654             int maxTemplateDepth = 0;
0655             templateDepth = 0;
0656             for (size_t i = charNum;
0657                     i < currentLine.length();
0658                     i++)
0659             {
0660                 char currentChar = currentLine[i];
0661 
0662                 if (currentChar == '<')
0663                 {
0664                     templateDepth++;
0665                     maxTemplateDepth++;
0666                 }
0667                 else if (currentChar == '>')
0668                 {
0669                     templateDepth--;
0670                     if (templateDepth == 0)
0671                     {
0672                         // this is a template!
0673                         isInTemplate = true;
0674                         templateDepth = maxTemplateDepth;
0675                         break;
0676                     }
0677                 }
0678                 else if (currentLine.compare(i, 2, "&&") == 0
0679                          || currentLine.compare(i, 2, "||") == 0)
0680                 {
0681                     // this is not a template -> leave...
0682                     isInTemplate = false;
0683                     break;
0684                 }
0685                 else if (currentChar == ','       // comma,     e.g. A<int, char>
0686                          || currentChar == '&'    // reference, e.g. A<int&>
0687                          || currentChar == '*'    // pointer,   e.g. A<int*>
0688                          || currentChar == ':'    // ::,        e.g. std::string
0689                          || currentChar == '['    // []         e.g. string[]
0690                          || currentChar == ']'    // []         e.g. string[]
0691                          || currentChar == '('    // (...)      e.g. function definition
0692                          || currentChar == ')')   // (...)      e.g. function definition
0693                 {
0694                     continue;
0695                 }
0696                 else if (!isLegalNameChar(currentChar) && !isWhiteSpace(currentChar))
0697                 {
0698                     // this is not a template -> leave...
0699                     isInTemplate = false;
0700                     break;
0701                 }
0702             }
0703         }
0704 
0705         // handle parenthesies
0706         if (currentChar == '(' || currentChar == '[' || (isInTemplate && currentChar == '<'))
0707         {
0708             parenStack->back()++;
0709             if (currentChar == '[')
0710                 isInBlParen = true;
0711         }
0712         else if (currentChar == ')' || currentChar == ']' || (isInTemplate && currentChar == '>'))
0713         {
0714             parenStack->back()--;
0715             if (isInTemplate && currentChar == '>')
0716             {
0717                 templateDepth--;
0718                 if (templateDepth == 0)
0719                 {
0720                     isInTemplate = false;
0721                     isCharImmediatelyPostTemplate = true;
0722                 }
0723             }
0724 
0725             // check if this parenthesis closes a header, e.g. if (...), while (...)
0726             if (isInHeader && parenStack->back() == 0)
0727             {
0728                 isInHeader = false;
0729                 isImmediatelyPostHeader = true;
0730             }
0731             if (currentChar == ']')
0732                 isInBlParen = false;
0733             if (currentChar == ')')
0734             {
0735                 foundCastOperator = false;
0736                 if (parenStack->back() == 0)
0737                     isInAsm = false;
0738             }
0739         }
0740 
0741         // handle brackets
0742         if (currentChar == '{' || currentChar == '}')
0743         {
0744             // if appendOpeningBracket this was already done for the original bracket
0745             if (currentChar == '{' && !appendOpeningBracket)
0746             {
0747                 BracketType newBracketType = getBracketType();
0748                 foundNamespaceHeader = false;
0749                 foundClassHeader = false;
0750                 foundStructHeader = false;
0751                 foundInterfaceHeader = false;
0752                 foundPreDefinitionHeader = false;
0753                 foundPreCommandHeader = false;
0754                 isInPotentialCalculation = false;
0755                 isJavaStaticConstructor = false;
0756                 needHeaderOpeningBracket = false;
0757 
0758                 isPreviousBracketBlockRelated = !isBracketType(newBracketType, ARRAY_TYPE);
0759                 bracketTypeStack->push_back(newBracketType);
0760                 preBracketHeaderStack->push_back(currentHeader);
0761                 currentHeader = NULL;
0762                 structStack->push_back(isInIndentableStruct);
0763                 if (isBracketType(newBracketType, STRUCT_TYPE) && isCStyle())
0764                     isInIndentableStruct = isStructAccessModified(currentLine, charNum);
0765                 else
0766                     isInIndentableStruct = false;
0767             }
0768 
0769             // this must be done before the bracketTypeStack is popped
0770             BracketType bracketType = bracketTypeStack->back();
0771             bool isOpeningArrayBracket = (isBracketType(bracketType, ARRAY_TYPE)
0772                                           && bracketTypeStack->size() >= 2
0773                                           && !isBracketType((*bracketTypeStack)[bracketTypeStack->size()-2], ARRAY_TYPE)
0774                                          );
0775 
0776             if (currentChar == '}')
0777             {
0778                 // if a request has been made to append a post block empty line,
0779                 // but the block exists immediately before a closing bracket,
0780                 // then there is no need for the post block empty line.
0781                 isAppendPostBlockEmptyLineRequested = false;
0782                 breakCurrentOneLineBlock = false;
0783                 isInAsmBlock = false;
0784 
0785                 // added for release 1.24
0786                 // TODO: remove at the appropriate time
0787                 assert(isInAsm == false);
0788                 assert(isInAsmOneLine == false);
0789                 assert(isInQuote == false);
0790                 isInAsm = isInAsmOneLine = isInQuote = false;
0791                 // end remove
0792 
0793                 if (bracketTypeStack->size() > 1)
0794                 {
0795                     previousBracketType = bracketTypeStack->back();
0796                     bracketTypeStack->pop_back();
0797                     isPreviousBracketBlockRelated = !isBracketType(bracketType, ARRAY_TYPE);
0798                 }
0799                 else
0800                 {
0801                     previousBracketType = NULL_TYPE;
0802                     isPreviousBracketBlockRelated = false;
0803                 }
0804 
0805                 if (!preBracketHeaderStack->empty())
0806                 {
0807                     currentHeader = preBracketHeaderStack->back();
0808                     preBracketHeaderStack->pop_back();
0809                 }
0810                 else
0811                     currentHeader = NULL;
0812 
0813                 if (!structStack->empty())
0814                 {
0815                     isInIndentableStruct = structStack->back();
0816                     structStack->pop_back();
0817                 }
0818                 else
0819                     isInIndentableStruct = false;
0820 
0821                 if (isBracketType(bracketType, ARRAY_NIS_TYPE) && !isBracketType(bracketType, SINGLE_LINE_TYPE))
0822                     clearNonInStatement = true;
0823             }
0824 
0825             // format brackets
0826             appendOpeningBracket = false;
0827             if (isBracketType(bracketType, ARRAY_TYPE))
0828             {
0829                 formatArrayBrackets(bracketType, isOpeningArrayBracket);
0830             }
0831             else
0832             {
0833                 if (currentChar == '{')
0834                     formatOpeningBracket(bracketType);
0835                 else
0836                     formatClosingBracket(bracketType);
0837             }
0838             continue;
0839         }
0840 
0841         if ((((previousCommandChar == '{' && isPreviousBracketBlockRelated)
0842                 || ((previousCommandChar == '}'
0843                      && !isImmediatelyPostEmptyBlock
0844                      && isPreviousBracketBlockRelated
0845                      && !isPreviousCharPostComment       // Fixes wrongly appended newlines after '}' immediately after comments
0846                      && peekNextChar() != ' '
0847                      && !isBracketType(previousBracketType,  DEFINITION_TYPE))
0848                     && !isBracketType(bracketTypeStack->back(),  DEFINITION_TYPE)))
0849                 && isOkToBreakBlock(bracketTypeStack->back()))
0850                 // check for array
0851                 || (isBracketType(bracketTypeStack->back(), ARRAY_TYPE)
0852                     && !isBracketType(bracketTypeStack->back(), SINGLE_LINE_TYPE)
0853                     && isNonInStatementArray))
0854         {
0855             isCharImmediatelyPostOpenBlock = (previousCommandChar == '{');
0856             isCharImmediatelyPostCloseBlock = (previousCommandChar == '}');
0857 
0858             if (isCharImmediatelyPostOpenBlock
0859                     && !isCharImmediatelyPostComment
0860                     && !isCharImmediatelyPostLineComment)
0861             {
0862                 previousCommandChar = ' ';
0863 
0864                 if (bracketFormatMode == NONE_MODE)
0865                 {
0866                     if (shouldBreakOneLineBlocks
0867                             && isBracketType(bracketTypeStack->back(),  SINGLE_LINE_TYPE))
0868                         isInLineBreak = true;
0869                     else if (currentLineBeginsWithBracket)
0870                         formatRunIn();
0871                     else
0872                         breakLine();
0873                 }
0874                 else if (bracketFormatMode == HORSTMANN_MODE
0875                          && currentChar != '#')
0876                     formatRunIn();
0877                 else
0878                     isInLineBreak = true;
0879             }
0880             else if (isCharImmediatelyPostCloseBlock
0881                      && shouldBreakOneLineStatements
0882                      && (isLegalNameChar(currentChar) && currentChar != '.')
0883                      && !isCharImmediatelyPostComment)
0884             {
0885                 previousCommandChar = ' ';
0886                 isInLineBreak = true;
0887             }
0888         }
0889 
0890         // reset block handling flags
0891         isImmediatelyPostEmptyBlock = false;
0892 
0893         // look for headers
0894         bool isPotentialHeader = isCharPotentialHeader(currentLine, charNum);
0895 
0896         if (isPotentialHeader && !isInTemplate)
0897         {
0898             isNonParenHeader = false;
0899             foundClosingHeader = false;
0900             newHeader = findHeader(headers);
0901 
0902             if (newHeader != NULL)
0903             {
0904                 char peekChar = ASBase::peekNextChar(currentLine, charNum + newHeader->length() - 1);
0905 
0906                 // is not a header if part of a definition
0907                 if (peekChar == ',' || peekChar == ')')
0908                     newHeader = NULL;
0909                 // the following accessor definitions are NOT headers
0910                 // goto default; is NOT a header
0911                 else if ((newHeader == &AS_GET || newHeader == &AS_SET || newHeader == &AS_DEFAULT)
0912                          && peekChar == ';')
0913                 {
0914                     newHeader = NULL;
0915                 }
0916             }
0917 
0918             if (newHeader != NULL)
0919             {
0920                 const string *previousHeader;
0921 
0922                 // recognize closing headers of do..while, if..else, try..catch..finally
0923                 if ((newHeader == &AS_ELSE && currentHeader == &AS_IF)
0924                         || (newHeader == &AS_WHILE && currentHeader == &AS_DO)
0925                         || (newHeader == &AS_CATCH && currentHeader == &AS_TRY)
0926                         || (newHeader == &AS_CATCH && currentHeader == &AS_CATCH)
0927                         || (newHeader == &AS_FINALLY && currentHeader == &AS_TRY)
0928                         || (newHeader == &AS_FINALLY && currentHeader == &AS_CATCH)
0929                         || (newHeader == &AS_SET && currentHeader == &AS_GET)
0930                         || (newHeader == &AS_REMOVE && currentHeader == &AS_ADD))
0931                     foundClosingHeader = true;
0932 
0933                 previousHeader = currentHeader;
0934                 currentHeader = newHeader;
0935                 needHeaderOpeningBracket = true;
0936 
0937                 if (foundClosingHeader && previousNonWSChar == '}')
0938                 {
0939                     if (isOkToBreakBlock(bracketTypeStack->back()))
0940                         isLineBreakBeforeClosingHeader();
0941 
0942                     // get the adjustment for a comment following the closing header
0943                     if (isInLineBreak)
0944                         nextLineSpacePadNum = getNextLineCommentAdjustment();
0945                     else
0946                         spacePadNum = getCurrentLineCommentAdjustment();
0947                 }
0948 
0949                 // check if the found header is non-paren header
0950                 isNonParenHeader = findHeader(nonParenHeaders) != NULL;
0951 
0952                 // join 'else if' statements
0953                 if (currentHeader == &AS_IF && previousHeader == &AS_ELSE && isInLineBreak
0954                         && !shouldBreakElseIfs && !isCharImmediatelyPostLineComment)
0955                 {
0956                     // 'else' must be last thing on the line, but must not be #else
0957                     size_t start = formattedLine.length() >= 6 ? formattedLine.length()-6 : 0;
0958                     if (formattedLine.find("else", start) != string::npos
0959                             && formattedLine.find("#else", start) == string::npos)
0960                     {
0961                         appendSpacePad();
0962                         isInLineBreak = false;
0963                     }
0964                 }
0965 
0966                 appendSequence(*currentHeader);
0967                 goForward(currentHeader->length() - 1);
0968                 // if a paren-header is found add a space after it, if needed
0969                 // this checks currentLine, appendSpacePad() checks formattedLine
0970                 // in C# 'catch' can be either a paren or non-paren header
0971                 if (shouldPadHeader
0972                         && (!isNonParenHeader || (currentHeader == &AS_CATCH && peekNextChar() == '('))
0973                         && charNum < (int) currentLine.length() && !isWhiteSpace(currentLine[charNum+1]))
0974                     appendSpacePad();
0975 
0976                 // Signal that a header has been reached
0977                 // *** But treat a closing while() (as in do...while)
0978                 //     as if it were NOT a header since a closing while()
0979                 //     should never have a block after it!
0980                 if (!(foundClosingHeader && currentHeader == &AS_WHILE))
0981                 {
0982                     isInHeader = true;
0983 
0984                     // in C# 'catch' and 'delegate' can be a paren or non-paren header
0985                     if (isNonParenHeader && !isSharpStyleWithParen(currentHeader))
0986                     {
0987                         isImmediatelyPostHeader = true;
0988                         isInHeader = false;
0989                     }
0990                 }
0991 
0992                 if (shouldBreakBlocks
0993                         && isOkToBreakBlock(bracketTypeStack->back()))
0994                 {
0995                     if (previousHeader == NULL
0996                             && !foundClosingHeader
0997                             && !isCharImmediatelyPostOpenBlock
0998                             && !isImmediatelyPostCommentOnly)
0999                     {
1000                         isPrependPostBlockEmptyLineRequested = true;
1001                     }
1002 
1003                     if (currentHeader == &AS_ELSE
1004                             || currentHeader == &AS_CATCH
1005                             || currentHeader == &AS_FINALLY
1006                             || foundClosingHeader)
1007                     {
1008                         isPrependPostBlockEmptyLineRequested = false;
1009                     }
1010 
1011                     if (shouldBreakClosingHeaderBlocks
1012                             && isCharImmediatelyPostCloseBlock
1013                             && !isImmediatelyPostCommentOnly
1014                             && currentHeader != &AS_WHILE)    // closing do-while block
1015                     {
1016                         isPrependPostBlockEmptyLineRequested = true;
1017                     }
1018 
1019                 }
1020 
1021                 continue;
1022             }
1023             else if ((newHeader = findHeader(preDefinitionHeaders)) != NULL
1024                      && parenStack->back() == 0)
1025             {
1026                 if (newHeader == &AS_NAMESPACE)
1027                     foundNamespaceHeader = true;
1028                 if (newHeader == &AS_CLASS)
1029                     foundClassHeader = true;
1030                 if (newHeader == &AS_STRUCT)
1031                     foundStructHeader = true;
1032                 if (newHeader == &AS_INTERFACE)
1033                     foundInterfaceHeader = true;
1034                 foundPreDefinitionHeader = true;
1035                 appendSequence(*newHeader);
1036                 goForward(newHeader->length() - 1);
1037 
1038                 continue;
1039             }
1040             else if ((newHeader = findHeader(preCommandHeaders)) != NULL)
1041             {
1042                 if (!(*newHeader == AS_CONST && previousCommandChar != ')')) // 'const' member functions is a command bracket
1043                     foundPreCommandHeader = true;
1044                 appendSequence(*newHeader);
1045                 goForward(newHeader->length() - 1);
1046 
1047                 continue;
1048             }
1049             else if ((newHeader = findHeader(castOperators)) != NULL)
1050             {
1051                 foundCastOperator = true;
1052                 appendSequence(*newHeader);
1053                 goForward(newHeader->length() - 1);
1054                 continue;
1055             }
1056         }   // (isPotentialHeader && !isInTemplate)
1057 
1058         if (isInLineBreak)          // OK to break line here
1059         {
1060             breakLine();
1061             if (isInVirginLine)     // adjust for the first line
1062             {
1063                 lineCommentNoBeautify = lineCommentNoIndent;
1064                 lineCommentNoIndent = false;
1065             }
1066         }
1067 
1068         if (previousNonWSChar == '}' || currentChar == ';')
1069         {
1070             if (currentChar == ';')
1071             {
1072                 if ((shouldBreakOneLineStatements
1073                         || isBracketType(bracketTypeStack->back(),  SINGLE_LINE_TYPE))
1074                         && isOkToBreakBlock(bracketTypeStack->back()))
1075                 {
1076                     passedSemicolon = true;
1077                 }
1078 
1079                 // append post block empty line for unbracketed header
1080                 if (shouldBreakBlocks && currentHeader != NULL && parenStack->back() == 0)
1081                 {
1082                     isAppendPostBlockEmptyLineRequested = true;
1083                 }
1084             }
1085 
1086             // end of block if a closing bracket was found
1087             // or an opening bracket was not found (';' closes)
1088             if (currentChar != ';'
1089                     || (needHeaderOpeningBracket && parenStack->back() == 0))
1090                 currentHeader = NULL;
1091 
1092             foundQuestionMark = false;
1093             foundNamespaceHeader = false;
1094             foundClassHeader = false;
1095             foundStructHeader = false;
1096             foundInterfaceHeader = false;
1097             foundPreDefinitionHeader = false;
1098             foundPreCommandHeader = false;
1099             foundCastOperator = false;
1100             isInPotentialCalculation = false;
1101             isSharpAccessor = false;
1102             isSharpDelegate = false;
1103             isInExtern = false;
1104             nonInStatementBracket = 0;
1105         }
1106 
1107         if (currentChar == ':' && shouldBreakOneLineStatements)
1108         {
1109             if (isInCase
1110                     && previousChar != ':'          // not part of '::'
1111                     && peekNextChar() != ':')       // not part of '::'
1112             {
1113                 isInCase = false;
1114                 passedColon = true;
1115             }
1116             else if (isCStyle()                     // for C/C++ only
1117                      && !foundQuestionMark          // not in a ... ? ... : ... sequence
1118                      && !foundPreDefinitionHeader   // not in a definition block (e.g. class foo : public bar
1119                      && previousCommandChar != ')'  // not immediately after closing paren of a method header, e.g. ASFormatter::ASFormatter(...) : ASBeautifier(...)
1120                      && previousChar != ':'         // not part of '::'
1121                      && peekNextChar() != ':'       // not part of '::'
1122                      && !isdigit(peekNextChar())    // not a bit field
1123                      && !isInAsm                    // not in extended assembler
1124                      && !isInAsmOneLine             // not in extended assembler
1125                      && !isInAsmBlock)              // not in extended assembler
1126             {
1127                 passedColon = true;
1128             }
1129         }
1130 
1131         if (currentChar == '?')
1132             foundQuestionMark = true;
1133 
1134         if (isPotentialHeader &&  !isInTemplate)
1135         {
1136             if (findKeyword(currentLine, charNum, AS_CASE)
1137                     || findKeyword(currentLine, charNum, AS_DEFAULT))
1138                 isInCase = true;
1139 
1140             if (findKeyword(currentLine, charNum, AS_NEW))
1141                 isInPotentialCalculation = false;
1142 
1143             if (findKeyword(currentLine, charNum, AS_RETURN))
1144             {
1145                 isInPotentialCalculation = true;    // return is the same as an = sign
1146                 isImmediatelyPostReturn = true;
1147             }
1148 
1149             if (findKeyword(currentLine, charNum, AS_OPERATOR))
1150                 isImmediatelyPostOperator = true;
1151 
1152             if (isCStyle() && findKeyword(currentLine, charNum, AS_EXTERN))
1153                 isInExtern = true;
1154 
1155             if (isCStyle() && isExecSQL(currentLine, charNum))
1156                 isInExecSQL = true;
1157 
1158             if (isCStyle())
1159             {
1160                 if (findKeyword(currentLine, charNum, AS_ASM)
1161                         || findKeyword(currentLine, charNum, AS__ASM__))
1162                 {
1163                     isInAsm = true;
1164                 }
1165                 else if (findKeyword(currentLine, charNum, AS_MS_ASM)       // microsoft specific
1166                          || findKeyword(currentLine, charNum, AS_MS__ASM))
1167                 {
1168                     int index = 4;
1169                     if (peekNextChar() == '_')  // check for __asm
1170                         index = 5;
1171 
1172                     char peekedChar = ASBase::peekNextChar(currentLine, charNum + index);
1173                     if (peekedChar == '{' || peekedChar == ' ')
1174                         isInAsmBlock = true;
1175                     else
1176                         isInAsmOneLine = true;
1177                 }
1178             }
1179 
1180             if (isJavaStyle()
1181                     && (findKeyword(currentLine, charNum, AS_STATIC)
1182                         && isNextCharOpeningBracket(charNum + 6)))
1183                 isJavaStaticConstructor = true;
1184 
1185             if (isSharpStyle()
1186                     && (findKeyword(currentLine, charNum, AS_DELEGATE)
1187                         || findKeyword(currentLine, charNum, AS_UNCHECKED)))
1188                 isSharpDelegate = true;
1189 
1190             // append the entire name
1191             string name = getCurrentWord(currentLine, charNum);
1192             appendSequence(name);
1193             goForward(name.length() - 1);
1194 
1195             continue;
1196 
1197         }   // (isPotentialHeader &&  !isInTemplate)
1198 
1199         // determine if this is a potential calculation
1200 
1201         bool isPotentialOperator = isCharPotentialOperator(currentChar);
1202         newHeader = NULL;
1203 
1204         if (isPotentialOperator)
1205         {
1206             newHeader = findOperator(operators);
1207 
1208             if (newHeader != NULL)
1209             {
1210                 // correct mistake of two >> closing a template
1211                 if (isInTemplate && (newHeader == &AS_GR_GR || newHeader == &AS_GR_GR_GR))
1212                     newHeader = &AS_GR;
1213 
1214                 if (!isInPotentialCalculation)
1215                 {
1216                     // must determine if newHeader is an assignment operator
1217                     // do NOT use findOperator!!!
1218                     if (find(assignmentOperators->begin(), assignmentOperators->end(), newHeader)
1219                             != assignmentOperators->end())
1220                     {
1221                         char peekedChar = peekNextChar();
1222                         isInPotentialCalculation = (!(newHeader == &AS_EQUAL && peekedChar == '*')
1223                                                     && !(newHeader == &AS_EQUAL && peekedChar == '&'));
1224                     }
1225                 }
1226             }
1227         }
1228 
1229         // process pointers and references
1230         // check new header to elimnate things like '&&' sequence
1231         if (isCStyle()
1232                 && (newHeader == &AS_MULT || newHeader == &AS_BIT_AND)
1233                 && isPointerOrReference()
1234                 && !isDereferenceOrAddressOf())
1235         {
1236             formatPointerOrReference();
1237             continue;
1238         }
1239 
1240         if (shouldPadOperators && newHeader != NULL)
1241         {
1242             padOperators(newHeader);
1243             continue;
1244         }
1245 
1246         // pad commas and semi-colons
1247         if (currentChar == ';'
1248                 || (currentChar == ',' && shouldPadOperators))
1249         {
1250             char nextChar = ' ';
1251             if (charNum + 1 < (int) currentLine.length())
1252                 nextChar = currentLine[charNum+1];
1253             if (!isWhiteSpace(nextChar)
1254                     && nextChar != '}'
1255                     && nextChar != ')'
1256                     && nextChar != ']'
1257                     && nextChar != '>'
1258                     && nextChar != ';'
1259                     && !isBeforeAnyComment()
1260                     /* && !(isBracketType(bracketTypeStack->back(), ARRAY_TYPE)) */
1261                )
1262             {
1263                 appendCurrentChar();
1264                 appendSpaceAfter();
1265                 continue;
1266             }
1267         }
1268 
1269         if ((shouldPadParensOutside || shouldPadParensInside || shouldUnPadParens)
1270                 && (currentChar == '(' || currentChar == ')'))
1271         {
1272             padParens();
1273             continue;
1274         }
1275 
1276         appendCurrentChar();
1277     }   // end of while loop  *  end of while loop  *  end of while loop  *  end of while loop
1278 
1279     // return a beautified (i.e. correctly indented) line.
1280 
1281     string beautifiedLine;
1282     size_t readyFormattedLineLength = trim(readyFormattedLine).length();
1283 
1284     if (prependEmptyLine                // prepend a blank line before this formatted line
1285             && readyFormattedLineLength > 0
1286             && previousReadyFormattedLineLength > 0)
1287     {
1288         isLineReady = true;             // signal a waiting readyFormattedLine
1289         beautifiedLine = beautify("");
1290         previousReadyFormattedLineLength = 0;
1291     }
1292     else                                // format the current formatted line
1293     {
1294         isLineReady = false;
1295         horstmannIndentInStatement = horstmannIndentChars;
1296         beautifiedLine = beautify(readyFormattedLine);
1297         previousReadyFormattedLineLength = readyFormattedLineLength;
1298         // the enhancer is not called for new empty lines
1299         // or no-indent line comments
1300         if (!lineCommentNoBeautify)
1301             enhancer->enhance(beautifiedLine, isInBeautifySQL);
1302         horstmannIndentChars = 0;
1303         lineCommentNoBeautify = lineCommentNoIndent;
1304         lineCommentNoIndent = false;
1305         isInBeautifySQL = isInExecSQL;
1306     }
1307 
1308     prependEmptyLine = false;
1309     return beautifiedLine;
1310 }
1311 
1312 
1313 /**
1314  * check if there are any indented lines ready to be read by nextLine()
1315  *
1316  * @return    are there any indented lines ready?
1317  */
1318 bool ASFormatter::hasMoreLines() const
1319 {
1320     return !endOfCodeReached;
1321 }
1322 
1323 /**
1324  * comparison function for BracketType enum
1325  */
1326 bool ASFormatter::isBracketType(BracketType a, BracketType b) const
1327 {
1328     return ((a & b) == b);
1329 }
1330 
1331 /**
1332  * set the formatting style.
1333  *
1334  * @param mode         the formatting style.
1335  */
1336 void ASFormatter::setFormattingStyle(FormatStyle style)
1337 {
1338     formattingStyle = style;
1339 }
1340 
1341 /**
1342  * set the add brackets mode.
1343  * options:
1344  *    true     brackets added to headers for single line statements.
1345  *    false    brackets NOT added to headers for single line statements.
1346  *
1347  * @param mode         the bracket formatting mode.
1348  */
1349 void ASFormatter::setAddBracketsMode(bool state)
1350 {
1351     shouldAddBrackets = state;
1352 }
1353 
1354 /**
1355  * set the add one line brackets mode.
1356  * options:
1357  *    true     one line brackets added to headers for single line statements.
1358  *    false    one line brackets NOT added to headers for single line statements.
1359  *
1360  * @param mode         the bracket formatting mode.
1361  */
1362 void ASFormatter::setAddOneLineBracketsMode(bool state)
1363 {
1364     shouldAddBrackets = state;
1365     shouldAddOneLineBrackets = state;
1366 }
1367 
1368 /**
1369  * set the bracket formatting mode.
1370  * options:
1371  *
1372  * @param mode         the bracket formatting mode.
1373  */
1374 void ASFormatter::setBracketFormatMode(BracketMode mode)
1375 {
1376     bracketFormatMode = mode;
1377 }
1378 
1379 /**
1380  * set closing header bracket breaking mode
1381  * options:
1382  *    true     brackets just before closing headers (e.g. 'else', 'catch')
1383  *             will be broken, even if standard brackets are attached.
1384  *    false    closing header brackets will be treated as standard brackets.
1385  *
1386  * @param state         the closing header bracket breaking mode.
1387  */
1388 void ASFormatter::setBreakClosingHeaderBracketsMode(bool state)
1389 {
1390     shouldBreakClosingHeaderBrackets = state;
1391 }
1392 
1393 /**
1394  * set 'else if()' breaking mode
1395  * options:
1396  *    true     'else' headers will be broken from their succeeding 'if' headers.
1397  *    false    'else' headers will be attached to their succeeding 'if' headers.
1398  *
1399  * @param state         the 'else if()' breaking mode.
1400  */
1401 void ASFormatter::setBreakElseIfsMode(bool state)
1402 {
1403     shouldBreakElseIfs = state;
1404 }
1405 
1406 /**
1407  * set operator padding mode.
1408  * options:
1409  *    true     statement operators will be padded with spaces around them.
1410  *    false    statement operators will not be padded.
1411  *
1412  * @param state         the padding mode.
1413  */
1414 void ASFormatter::setOperatorPaddingMode(bool state)
1415 {
1416     shouldPadOperators = state;
1417 }
1418 
1419 /**
1420  * set parenthesis outside padding mode.
1421  * options:
1422  *    true     statement parenthesiss will be padded with spaces around them.
1423  *    false    statement parenthesiss will not be padded.
1424  *
1425  * @param state         the padding mode.
1426  */
1427 void ASFormatter::setParensOutsidePaddingMode(bool state)
1428 {
1429     shouldPadParensOutside = state;
1430 }
1431 
1432 /**
1433  * set parenthesis inside padding mode.
1434  * options:
1435  *    true     statement parenthesis will be padded with spaces around them.
1436  *    false    statement parenthesis will not be padded.
1437  *
1438  * @param state         the padding mode.
1439  */
1440 void ASFormatter::setParensInsidePaddingMode(bool state)
1441 {
1442     shouldPadParensInside = state;
1443 }
1444 
1445 /**
1446  * set header padding mode.
1447  * options:
1448  *    true     headers will be padded with spaces around them.
1449  *    false    headers will not be padded.
1450  *
1451  * @param state         the padding mode.
1452  */
1453 void ASFormatter::setParensHeaderPaddingMode(bool state)
1454 {
1455     shouldPadHeader = state;
1456 }
1457 
1458 /**
1459  * set parenthesis unpadding mode.
1460  * options:
1461  *    true     statement parenthesis will be unpadded with spaces removed around them.
1462  *    false    statement parenthesis will not be unpadded.
1463  *
1464  * @param state         the padding mode.
1465  */
1466 void ASFormatter::setParensUnPaddingMode(bool state)
1467 {
1468     shouldUnPadParens = state;
1469 }
1470 
1471 /**
1472  * set option to break/not break one-line blocks
1473  *
1474  * @param state        true = break, false = don't break.
1475  */
1476 void ASFormatter::setBreakOneLineBlocksMode(bool state)
1477 {
1478     shouldBreakOneLineBlocks = state;
1479 }
1480 
1481 /**
1482  * set option to break/not break lines consisting of multiple statements.
1483  *
1484  * @param state        true = break, false = don't break.
1485  */
1486 void ASFormatter::setSingleStatementsMode(bool state)
1487 {
1488     shouldBreakOneLineStatements = state;
1489 }
1490 
1491 /**
1492  * set option to convert tabs to spaces.
1493  *
1494  * @param state        true = convert, false = don't convert.
1495  */
1496 void ASFormatter::setTabSpaceConversionMode(bool state)
1497 {
1498     shouldConvertTabs = state;
1499 }
1500 
1501 /**
1502  * set option to indent comments in column 1.
1503  *
1504  * @param state        true = indent, false = don't indent.
1505  */
1506 void ASFormatter::setIndentCol1CommentsMode(bool state)
1507 {
1508     shouldIndentCol1Comments = state;
1509 }
1510 
1511 /**
1512  * set option to force all line ends to a particular style.
1513  *
1514  * @param fmt           format enum value
1515  */
1516 void ASFormatter::setLineEndFormat(LineEndFormat fmt)
1517 {
1518     lineEnd = fmt;
1519 }
1520 
1521 /**
1522  * set option to break unrelated blocks of code with empty lines.
1523  *
1524  * @param state        true = convert, false = don't convert.
1525  */
1526 void ASFormatter::setBreakBlocksMode(bool state)
1527 {
1528     shouldBreakBlocks = state;
1529 }
1530 
1531 /**
1532  * set option to break closing header blocks of code (such as 'else', 'catch', ...) with empty lines.
1533  *
1534  * @param state        true = convert, false = don't convert.
1535  */
1536 void ASFormatter::setBreakClosingHeaderBlocksMode(bool state)
1537 {
1538     shouldBreakClosingHeaderBlocks = state;
1539 }
1540 
1541 /**
1542  * set option to delete empty lines.
1543  *
1544  * @param state        true = delete, false = don't delete.
1545  */
1546 void ASFormatter::setDeleteEmptyLinesMode(bool state)
1547 {
1548     shouldDeleteEmptyLines = state;
1549 }
1550 
1551 /**
1552  * set the pointer alignment.
1553  * options:
1554  *
1555  * @param alignment    the pointer alignment.
1556  */
1557 void ASFormatter::setPointerAlignment(PointerAlign alignment)
1558 {
1559     pointerAlignment = alignment;
1560 }
1561 
1562 /**
1563  * jump over several characters.
1564  *
1565  * @param i       the number of characters to jump over.
1566  */
1567 void ASFormatter::goForward(int i)
1568 {
1569     while (--i >= 0)
1570         getNextChar();
1571 }
1572 
1573 /**
1574  * peek at the next unread character.
1575  *
1576  * @return     the next unread character.
1577  */
1578 char ASFormatter::peekNextChar() const
1579 {
1580     char ch = ' ';
1581     size_t peekNum = currentLine.find_first_not_of(" \t", charNum + 1);
1582 
1583     if (peekNum == string::npos)
1584         return ch;
1585 
1586     ch = currentLine[peekNum];
1587 
1588     return ch;
1589 }
1590 
1591 /**
1592  * check if current placement is before a comment
1593  *
1594  * @return     is before a comment.
1595  */
1596 bool ASFormatter::isBeforeComment() const
1597 {
1598     bool foundComment = false;
1599     size_t peekNum = currentLine.find_first_not_of(" \t", charNum + 1);
1600 
1601     if (peekNum == string::npos)
1602         return foundComment;
1603 
1604     foundComment = (currentLine.compare(peekNum, 2, "/*") == 0);
1605 
1606     return foundComment;
1607 }
1608 
1609 /**
1610  * check if current placement is before a comment or line-comment
1611  *
1612  * @return     is before a comment or line-comment.
1613  */
1614 bool ASFormatter::isBeforeAnyComment() const
1615 {
1616     bool foundComment = false;
1617     size_t peekNum = currentLine.find_first_not_of(" \t", charNum + 1);
1618 
1619     if (peekNum == string::npos)
1620         return foundComment;
1621 
1622     foundComment = (currentLine.compare(peekNum, 2, "/*") == 0
1623                     || currentLine.compare(peekNum, 2, "//") == 0);
1624 
1625     return foundComment;
1626 }
1627 
1628 /**
1629  * check if current placement is before a comment or line-comment
1630  * if a block comment it must be at the end of the line
1631  *
1632  * @return     is before a comment or line-comment.
1633  */
1634 bool ASFormatter::isBeforeAnyLineEndComment(int startPos) const
1635 {
1636     bool foundLineEndComment = false;
1637     size_t peekNum = currentLine.find_first_not_of(" \t", startPos + 1);
1638 
1639     if (peekNum != string::npos)
1640     {
1641         if (currentLine.compare(peekNum, 2, "//") == 0)
1642             foundLineEndComment = true;
1643         else if (currentLine.compare(peekNum, 2, "/*") == 0)
1644         {
1645             // comment must be closed on this line with nothing after it
1646             size_t endNum = currentLine.find("*/", peekNum + 2);
1647             if (endNum != string::npos)
1648             {
1649                 size_t nextChar = currentLine.find_first_not_of(" \t", endNum + 2);
1650                 if (nextChar == string::npos)
1651                     foundLineEndComment = true;
1652             }
1653         }
1654     }
1655     return foundLineEndComment;
1656 }
1657 
1658 /**
1659  * check if current placement is before a comment followed by a line-comment
1660  *
1661  * @return     is before a multiple line-end comment.
1662  */
1663 bool ASFormatter::isBeforeMultipleLineEndComments(int startPos) const
1664 {
1665     bool foundMultipleLineEndComment = false;
1666     size_t peekNum = currentLine.find_first_not_of(" \t", startPos + 1);
1667 
1668     if (peekNum != string::npos)
1669     {
1670         if (currentLine.compare(peekNum, 2, "/*") == 0)
1671         {
1672             // comment must be closed on this line with nothing after it
1673             size_t endNum = currentLine.find("*/", peekNum + 2);
1674             if (endNum != string::npos)
1675             {
1676                 size_t nextChar = currentLine.find_first_not_of(" \t", endNum + 2);
1677                 if (nextChar != string::npos
1678                         && currentLine.compare(nextChar, 2, "//") == 0)
1679                     foundMultipleLineEndComment = true;
1680             }
1681         }
1682     }
1683     return foundMultipleLineEndComment;
1684 }
1685 
1686 
1687 /**
1688  * get the next character, increasing the current placement in the process.
1689  * the new character is inserted into the variable currentChar.
1690  *
1691  * @return   whether succeded to recieve the new character.
1692  */
1693 bool ASFormatter::getNextChar()
1694 {
1695     isInLineBreak = false;
1696     previousChar = currentChar;
1697 
1698     if (!isWhiteSpace(currentChar))
1699     {
1700         previousNonWSChar = currentChar;
1701         if (!isInComment && !isInLineComment && !isInQuote
1702                 && !isImmediatelyPostComment
1703                 && !isImmediatelyPostLineComment
1704                 && !isInPreprocessor
1705                 && !isSequenceReached("/*")
1706                 && !isSequenceReached("//"))
1707             previousCommandChar = currentChar;
1708     }
1709 
1710     if (charNum + 1 < (int) currentLine.length()
1711             && (!isWhiteSpace(peekNextChar()) || isInComment || isInLineComment))
1712     {
1713         currentChar = currentLine[++charNum];
1714 
1715         if (shouldConvertTabs && currentChar == '\t')
1716             convertTabToSpaces();
1717 
1718         return true;
1719     }
1720 
1721     // end of line has been reached
1722     return getNextLine();
1723 }
1724 
1725 /**
1726  * get the next line of input, increasing the current placement in the process.
1727  *
1728  * @param sequence         the sequence to append.
1729  * @return   whether succeded in reading the next line.
1730  */
1731 bool ASFormatter::getNextLine(bool emptyLineWasDeleted /*false*/)
1732 {
1733     if (sourceIterator->hasMoreLines())
1734     {
1735         if (appendOpeningBracket)
1736             currentLine = "{";      // append bracket that was removed from the previous line
1737         else
1738             currentLine = sourceIterator->nextLine(emptyLineWasDeleted);
1739         // reset variables for new line
1740         inLineNumber++;
1741         isInCase = false;
1742         isInAsmOneLine = false;
1743         isInQuoteContinuation = isInVerbatimQuote | haveLineContinuationChar;
1744         haveLineContinuationChar= false;
1745         isImmediatelyPostEmptyLine = lineIsEmpty;
1746         previousChar = ' ';
1747 
1748         if (currentLine.length() == 0)
1749         {
1750             currentLine = string(" ");        // a null is inserted if this is not done
1751         }
1752 
1753         // unless reading in the first line of the file, break a new line.
1754         if (!isVirgin)
1755             isInLineBreak = true;
1756         else
1757             isVirgin = false;
1758 
1759         // check if is in preprocessor before line trimming
1760         // a blank line after a \ will remove the flag
1761         isImmediatelyPostPreprocessor = isInPreprocessor;
1762         if (previousNonWSChar != '\\'
1763                 || isEmptyLine(currentLine))
1764             isInPreprocessor = false;
1765 
1766         if (passedSemicolon)
1767             isInExecSQL = false;
1768         initNewLine();
1769         currentChar = currentLine[charNum];
1770         if (isInHorstmannRunIn && previousNonWSChar == '{')
1771             isInLineBreak = false;
1772         isInHorstmannRunIn = false;
1773 
1774         if (shouldConvertTabs && currentChar == '\t')
1775             convertTabToSpaces();
1776 
1777         // check for an empty line inside a command bracket.
1778         // if yes then read the next line (calls getNextLine recursively).
1779         // must be after initNewLine.
1780         if (shouldDeleteEmptyLines
1781                 && lineIsEmpty
1782                 && isBracketType((*bracketTypeStack)[bracketTypeStack->size()-1], COMMAND_TYPE))
1783         {
1784             // but do NOT delete an empty line between comments if blocks are being broken
1785             if (!(shouldBreakBlocks || shouldBreakClosingHeaderBlocks)
1786                     || !isImmediatelyPostCommentOnly
1787                     || !commentAndHeaderFollows())
1788             {
1789                 isInPreprocessor = isImmediatelyPostPreprocessor;       // restore
1790                 lineIsEmpty = false;
1791                 return getNextLine(true);
1792             }
1793         }
1794 
1795         return true;
1796     }
1797     else
1798     {
1799         endOfCodeReached = true;
1800         return false;
1801     }
1802 }
1803 
1804 /**
1805  * jump over the leading white space in the current line,
1806  * IF the line does not begin a comment or is in a preprocessor definition.
1807  */
1808 void ASFormatter::initNewLine()
1809 {
1810     size_t len = currentLine.length();
1811     size_t indent = getIndentLength();
1812     charNum = 0;
1813 
1814     if (isInPreprocessor || isInQuoteContinuation)
1815         return;
1816 
1817     // SQL continuation lines must be adjusted so the leading spaces
1818     // is equivalent to the opening EXEC SQL
1819     if (isInExecSQL)
1820     {
1821         // replace leading tabs with spaces
1822         // so that continuation indent will be spaces
1823         size_t tabCount = 0;
1824         size_t i;
1825         for (i = 0; i < currentLine.length(); i++)
1826         {
1827             if (!isWhiteSpace(currentLine[i]))      // stop at first text
1828                 break;
1829             if (currentLine[i] == '\t')
1830             {
1831                 size_t numSpaces = indent - ((tabCount + i) % indent);
1832                 currentLine.replace(i, 1, numSpaces, ' ');
1833                 tabCount++;
1834                 i += indent - 1;
1835             }
1836         }
1837         // correct the format if EXEC SQL is not a hanging indent
1838         if (i < leadingSpaces)
1839             currentLine.insert((size_t)0, leadingSpaces - i, ' ');
1840         trimContinuationLine();
1841         return;
1842     }
1843 
1844     // comment continuation lines must be adjusted so the leading spaces
1845     // is equivalent to the opening comment
1846     if (isInComment)
1847     {
1848         if (noTrimCommentContinuation)
1849             leadingSpaces = tabIncrementIn = 0;
1850         trimContinuationLine();
1851         return;
1852     }
1853 
1854     // compute leading spaces
1855     isImmediatelyPostCommentOnly = lineIsLineCommentOnly || lineEndsInCommentOnly;
1856     lineIsLineCommentOnly = false;
1857     lineEndsInCommentOnly = false;
1858     doesLineStartComment = false;
1859     currentLineBeginsWithBracket = false;
1860     lineIsEmpty = false;
1861     currentLineFirstBracketNum = string::npos;
1862     tabIncrementIn = 0;
1863 
1864     for (charNum = 0; isWhiteSpace(currentLine[charNum]) && charNum + 1 < (int) len; charNum++)
1865     {
1866         if (currentLine[charNum] == '\t')
1867             tabIncrementIn += indent - 1 - ((tabIncrementIn + charNum) % indent);
1868     }
1869     leadingSpaces = charNum + tabIncrementIn;
1870 
1871     if (isSequenceReached("/*"))
1872     {
1873         doesLineStartComment = true;
1874     }
1875     else if (isSequenceReached("//"))
1876     {
1877         lineIsLineCommentOnly = true;
1878     }
1879     else if (isSequenceReached("{"))
1880     {
1881         currentLineBeginsWithBracket = true;
1882         currentLineFirstBracketNum = charNum;
1883         size_t firstText = currentLine.find_first_not_of(" \t", charNum + 1);
1884         if (firstText != string::npos)
1885         {
1886             if (currentLine.compare(firstText, 2, "//") == 0)
1887                 lineIsLineCommentOnly = true;
1888             else if (currentLine.compare(firstText, 2, "/*") == 0
1889                      || isExecSQL(currentLine, firstText))
1890             {
1891                 // get the extra adjustment
1892                 size_t j;
1893                 for (j = charNum + 1; isWhiteSpace(currentLine[j]) && j < firstText; j++)
1894                 {
1895                     if (currentLine[j] == '\t')
1896                         tabIncrementIn += indent - 1 - ((tabIncrementIn + j) % indent);
1897                 }
1898                 leadingSpaces = j + tabIncrementIn;
1899                 if (currentLine.compare(firstText, 2, "/*") == 0)
1900                     doesLineStartComment = true;
1901             }
1902         }
1903     }
1904     else if (isWhiteSpace(currentLine[charNum]) && !(charNum + 1 < (int) currentLine.length()))
1905     {
1906         lineIsEmpty = true;
1907     }
1908 }
1909 
1910 /**
1911  * append a string sequence to the current formatted line.
1912  * Unless disabled (via canBreakLine == false), first check if a
1913  * line-break has been registered, and if so break the
1914  * formatted line, and only then append the sequence into
1915  * the next formatted line.
1916  *
1917  * @param sequence         the sequence to append.
1918  * @param canBreakLine     if true, a registered line-break
1919  */
1920 void ASFormatter::appendSequence(const string &sequence, bool canBreakLine)
1921 {
1922     if (canBreakLine && isInLineBreak)
1923         breakLine();
1924     formattedLine.append(sequence);
1925 }
1926 
1927 /**
1928  * append a space to the current formattedline, UNLESS the
1929  * last character is already a white-space character.
1930  */
1931 void ASFormatter::appendSpacePad()
1932 {
1933     int len = formattedLine.length();
1934     if (len > 0 && !isWhiteSpace(formattedLine[len-1]))
1935     {
1936         formattedLine.append(1, ' ');
1937         spacePadNum++;
1938     }
1939 }
1940 
1941 /**
1942  * append a space to the current formattedline, UNLESS the
1943  * next character is already a white-space character.
1944  */
1945 void ASFormatter::appendSpaceAfter()
1946 {
1947     int len = currentLine.length();
1948     if (charNum + 1 < len && !isWhiteSpace(currentLine[charNum+1]))
1949     {
1950         formattedLine.append(1, ' ');
1951         spacePadNum++;
1952     }
1953 }
1954 
1955 /**
1956  * register a line break for the formatted line.
1957  */
1958 void ASFormatter::breakLine()
1959 {
1960     isLineReady = true;
1961     isInLineBreak = false;
1962     spacePadNum = nextLineSpacePadNum;
1963     nextLineSpacePadNum = 0;
1964     formattedLineCommentNum = string::npos;
1965 
1966     // queue an empty line prepend request if one exists
1967     prependEmptyLine = isPrependPostBlockEmptyLineRequested;
1968 
1969     readyFormattedLine =  formattedLine;
1970     if (isAppendPostBlockEmptyLineRequested)
1971     {
1972         isAppendPostBlockEmptyLineRequested = false;
1973         isPrependPostBlockEmptyLineRequested = true;
1974     }
1975     else
1976     {
1977         isPrependPostBlockEmptyLineRequested = false;
1978     }
1979 
1980     formattedLine = "";
1981 }
1982 
1983 /**
1984  * check if the currently reached open-bracket (i.e. '{')
1985  * opens a:
1986  * - a definition type block (such as a class or namespace),
1987  * - a command block (such as a method block)
1988  * - a static array
1989  * this method takes for granted that the current character
1990  * is an opening bracket.
1991  *
1992  * @return    the type of the opened block.
1993  */
1994 BracketType ASFormatter::getBracketType()
1995 {
1996     assert(currentChar == '{');
1997 
1998     BracketType returnVal;
1999 
2000     if ((previousNonWSChar == '='
2001             || isBracketType(bracketTypeStack->back(),  ARRAY_TYPE))
2002             && previousCommandChar != ')')
2003         returnVal = ARRAY_TYPE;
2004     else if (foundPreDefinitionHeader)
2005     {
2006         returnVal = DEFINITION_TYPE;
2007         if (foundNamespaceHeader)
2008             returnVal = (BracketType)(returnVal | NAMESPACE_TYPE);
2009         else if (foundClassHeader)
2010             returnVal = (BracketType)(returnVal | CLASS_TYPE);
2011         else if (foundStructHeader)
2012             returnVal = (BracketType)(returnVal | STRUCT_TYPE);
2013         else if (foundInterfaceHeader)
2014             returnVal = (BracketType)(returnVal | INTERFACE_TYPE);
2015     }
2016     else
2017     {
2018         bool isCommandType = (foundPreCommandHeader
2019                               || (currentHeader != NULL && isNonParenHeader)
2020                               || (previousCommandChar == ')')
2021                               || (previousCommandChar == ':' && !foundQuestionMark)
2022                               || (previousCommandChar == ';')
2023                               || ((previousCommandChar == '{' ||  previousCommandChar == '}')
2024                                   && isPreviousBracketBlockRelated)
2025                               || isJavaStaticConstructor
2026                               || isSharpDelegate);
2027 
2028         // C# methods containing 'get', 'set', 'add', and 'remove' do NOT end with parens
2029         if (!isCommandType && isSharpStyle() && isNextWordSharpNonParenHeader(charNum + 1))
2030         {
2031             isCommandType = true;
2032             isSharpAccessor = true;
2033         }
2034 
2035         if (!isCommandType && isInExtern)
2036             returnVal = EXTERN_TYPE;
2037         else
2038             returnVal = (isCommandType ? COMMAND_TYPE : ARRAY_TYPE);
2039     }
2040 
2041     if (isOneLineBlockReached(currentLine, charNum))
2042         returnVal = (BracketType)(returnVal | SINGLE_LINE_TYPE);
2043 
2044     if (isBracketType(returnVal, ARRAY_TYPE) && isNonInStatementArrayBracket())
2045     {
2046         returnVal = (BracketType)(returnVal | ARRAY_NIS_TYPE);
2047         isNonInStatementArray = true;
2048         nonInStatementBracket = formattedLine.length() - 1;
2049     }
2050 
2051     return returnVal;
2052 }
2053 
2054 /**
2055  * check if a line is empty
2056  *
2057  * @return        whether line is empty
2058  */
2059 bool ASFormatter::isEmptyLine(const string &line) const
2060 {
2061     return line.find_first_not_of(" \t") == string::npos;
2062 }
2063 
2064 /**
2065  * Check if the currently reached  '*' or '&' character is
2066  * a pointer-or-reference symbol, or another operator.
2067  * A pointer dereference (*) or an "address of" character (&)
2068  * counts as a pointer or reference because it is not an
2069  * arithmetic operator.
2070  *
2071  * @return        whether current character is a reference-or-pointer
2072  */
2073 bool ASFormatter::isPointerOrReference() const
2074 {
2075     assert(currentChar == '*' || currentChar == '&');
2076 
2077     if (!isCStyle())
2078         return false;
2079 
2080     if (currentChar == '&' && previousChar == '&')
2081         return false;
2082 
2083     if (previousNonWSChar == '=' || isCharImmediatelyPostReturn)
2084         return true;
2085 
2086     if (currentHeader == &AS_CATCH)
2087         return true;
2088 
2089     // get the last legal word (may be a number)
2090     string lastWord = getPreviousWord(currentLine, charNum);
2091     if (lastWord.empty())
2092         lastWord[0] = ' ';
2093     char nextChar = peekNextChar();
2094 
2095     // check for preceding or following numeric values
2096     if (isdigit(lastWord[0])
2097             || isdigit(nextChar))
2098         return false;
2099 
2100     // checks on other chars
2101     if (isLegalNameChar(lastWord[0])
2102             && isLegalNameChar(nextChar)
2103             && parenStack->back() > 0)
2104     {
2105         // if followed by an assignment it is a pointer or reference
2106         size_t nextNum = currentLine.find_first_of("=;)", charNum + 1);
2107         if (nextNum != string::npos && currentLine[nextNum] == '=')
2108             return true;
2109 
2110         // if a function definition it is a pointer or reference
2111         // otherwise it is an arithmetic operator
2112         if (!isBracketType(bracketTypeStack->back(), COMMAND_TYPE))
2113             return true;
2114         else
2115             return false;
2116     }
2117 
2118     if (nextChar == '-'
2119             || nextChar == '+')
2120     {
2121         size_t nextNum = currentLine.find_first_not_of(" \t", charNum + 1);
2122         if (nextNum != string::npos)
2123         {
2124             if (currentLine.compare(nextNum, 2, "++") != 0
2125                     && currentLine.compare(nextNum, 2, "--") != 0)
2126                 return false;
2127         }
2128     }
2129 
2130     bool isPR = (!isInPotentialCalculation
2131                  || isBracketType(bracketTypeStack->back(), DEFINITION_TYPE)
2132                  || (!isLegalNameChar(previousNonWSChar)
2133                      && !(previousNonWSChar == ')' && nextChar == '(')
2134                      && !(previousNonWSChar == ')' && currentChar == '*')
2135                      && previousNonWSChar != ']')
2136                 );
2137 
2138     if (!isPR)
2139     {
2140         isPR |= (!isWhiteSpace(nextChar)
2141                  && nextChar != '-'
2142                  && nextChar != '('
2143                  && nextChar != '['
2144                  && !isLegalNameChar(nextChar));
2145     }
2146 
2147     return isPR;
2148 }
2149 
2150 /**
2151  * Check if the currently reached  '*' or '&' character is
2152  * a dereferenced pointer or "address of" symbol.
2153  * NOTE: this MUST be a pointer or reference as determined by
2154  * the function isPointerOrReference().
2155  *
2156  * @return        whether current character is a dereference or address of
2157  */
2158 bool ASFormatter::isDereferenceOrAddressOf() const
2159 {
2160     assert(isPointerOrReference());
2161 
2162     if (previousNonWSChar == '='
2163             || previousNonWSChar == ','
2164             || previousNonWSChar == '.'
2165             || previousNonWSChar == '>'
2166             || previousNonWSChar == '<'
2167             || isCharImmediatelyPostReturn)
2168         return true;
2169 
2170     // check for **
2171     if (currentChar == '*'
2172             && (int) currentLine.length() > charNum
2173             && currentLine[charNum+1] == '*')
2174     {
2175         if (previousNonWSChar == '(')
2176             return true;
2177         if ((int) currentLine.length() < charNum + 2)
2178             return true;
2179         return false;
2180     }
2181 
2182     // check first char on the line
2183     if (charNum == (int) currentLine.find_first_not_of(" \t"))
2184         return true;
2185 
2186     size_t nextChar = currentLine.find_first_not_of(" \t", charNum+1);
2187     if (nextChar != string::npos
2188             && (currentLine[nextChar] == ')'
2189                 || currentLine[nextChar] == '>'
2190                 || currentLine[nextChar] == ','))
2191         return false;
2192 
2193     string lastWord = getPreviousWord(currentLine, charNum);
2194     if (lastWord == "else" || lastWord == "delete")
2195         return true;
2196 
2197     bool isDA = (!(isLegalNameChar(previousNonWSChar) || previousNonWSChar == '>')
2198                  || !isLegalNameChar(peekNextChar())
2199                  || (ispunct(previousNonWSChar) && previousNonWSChar != '.')
2200                  || isCharImmediatelyPostReturn);
2201 
2202     return isDA;
2203 }
2204 
2205 /**
2206  * Check if the currently reached  '*' or '&' character is
2207  * centered with one space on each side.
2208  * Only spaces are checked, not tabs.
2209  * If true then a space wil be deleted on the output.
2210  *
2211  * @return        whether current character is centered.
2212  */
2213 bool ASFormatter::isPointerOrReferenceCentered() const
2214 {
2215     assert(currentLine[charNum] == '*' || currentLine[charNum] == '&');
2216 
2217     int prNum = charNum;
2218     int lineLength = (int) currentLine.length();
2219     // check space before
2220     if (prNum < 1
2221             || currentLine[prNum-1] != ' ')
2222         return false;
2223 
2224     // check no space before that
2225     if (prNum < 2
2226             || currentLine[prNum-2] == ' ')
2227         return false;
2228 
2229     // check for **
2230     if (prNum + 1 < lineLength
2231             && currentLine[prNum+1] == '*')
2232         prNum++;
2233 
2234     // check space after
2235     if (prNum + 1 < lineLength
2236             && currentLine[prNum+1] != ' ')
2237         return false;
2238 
2239     // check no space after that
2240     if (prNum + 2 < lineLength
2241             && currentLine[prNum+2] == ' ')
2242         return false;
2243 
2244     return true;
2245 }
2246 
2247 /**
2248  * check if the currently reached '+' or '-' character is a unary operator
2249  * this method takes for granted that the current character
2250  * is a '+' or '-'.
2251  *
2252  * @return        whether the current '+' or '-' is a unary operator.
2253  */
2254 bool ASFormatter::isUnaryOperator() const
2255 {
2256     assert(currentChar == '+' || currentChar == '-');
2257 
2258     return ((isCharImmediatelyPostReturn || !isLegalNameChar(previousCommandChar))
2259             && previousCommandChar != '.'
2260             && previousCommandChar != '\"'
2261             && previousCommandChar != '\''
2262             && previousCommandChar != ')'
2263             && previousCommandChar != ']');
2264 }
2265 
2266 
2267 /**
2268  * check if the currently reached '+' or '-' character is
2269  * part of an exponent, i.e. 0.2E-5.
2270  *
2271  * this method takes for granted that the current character
2272  * is a '+' or '-'.
2273  *
2274  * @return        whether the current '+' or '-' is in an exponent.
2275  */
2276 bool ASFormatter::isInExponent() const
2277 {
2278     assert(currentChar == '+' || currentChar == '-');
2279 
2280     int formattedLineLength = formattedLine.length();
2281     if (formattedLineLength >= 2)
2282     {
2283         char prevPrevFormattedChar = formattedLine[formattedLineLength - 2];
2284         char prevFormattedChar = formattedLine[formattedLineLength - 1];
2285 
2286         return ((prevFormattedChar == 'e' || prevFormattedChar == 'E')
2287                 && (prevPrevFormattedChar == '.' || isdigit(prevPrevFormattedChar)));
2288     }
2289     else
2290         return false;
2291 }
2292 
2293 /**
2294  * check if an array bracket should NOT have an in-statement indent
2295  *
2296  * @return        the array is non in-statement
2297  */
2298 bool ASFormatter::isNonInStatementArrayBracket() const
2299 {
2300     bool returnVal = false;
2301     char nextChar = peekNextChar();
2302     // if this opening bracket begins the line there will be no inStatement indent
2303     if (currentLineBeginsWithBracket
2304             && charNum == (int) currentLineFirstBracketNum
2305             && nextChar != '}')
2306         returnVal = true;
2307     // if an opening bracket ends the line there will be no inStatement indent
2308     if (isWhiteSpace(nextChar)
2309             || isBeforeAnyLineEndComment(charNum)
2310             || nextChar == '{')
2311         returnVal = true;
2312 
2313     // Java "new Type [] {...}" IS an inStatement indent
2314     if (isJavaStyle() && previousNonWSChar == ']')
2315         returnVal = false;
2316 
2317     // trace
2318     //if (isNonInStatementArray)
2319     //  cout << traceLineNumber << " " << 'x' << endl;
2320     //else
2321     //  cout << traceLineNumber << " " << ' ' << endl
2322 
2323     return returnVal;
2324 }
2325 
2326 /**
2327  * check if a one-line bracket has been reached,
2328  * i.e. if the currently reached '{' character is closed
2329  * with a complimentry '}' elsewhere on the current line,
2330  *.
2331  * @return        has a one-line bracket been reached?
2332  */
2333 bool ASFormatter::isOneLineBlockReached(string& line, int startChar) const
2334 {
2335     assert(line[startChar] == '{');
2336 
2337     bool isInComment = false;
2338     bool isInQuote = false;
2339     int bracketCount = 1;
2340     int lineLength = line.length();
2341     char quoteChar = ' ';
2342 
2343     for (int i = startChar + 1; i < lineLength; ++i)
2344     {
2345         char ch = line[i];
2346 
2347         if (isInComment)
2348         {
2349             if (line.compare(i, 2, "*/") == 0)
2350             {
2351                 isInComment = false;
2352                 ++i;
2353             }
2354             continue;
2355         }
2356 
2357         if (ch == '\\')
2358         {
2359             ++i;
2360             continue;
2361         }
2362 
2363         if (isInQuote)
2364         {
2365             if (ch == quoteChar)
2366                 isInQuote = false;
2367             continue;
2368         }
2369 
2370         if (ch == '"' || ch == '\'')
2371         {
2372             isInQuote = true;
2373             quoteChar = ch;
2374             continue;
2375         }
2376 
2377         if (line.compare(i, 2, "//") == 0)
2378             break;
2379 
2380         if (line.compare(i, 2, "/*") == 0)
2381         {
2382             isInComment = true;
2383             ++i;
2384             continue;
2385         }
2386 
2387         if (ch == '{')
2388             ++bracketCount;
2389         else if (ch == '}')
2390             --bracketCount;
2391 
2392         if (bracketCount == 0)
2393             return true;
2394     }
2395 
2396     return false;
2397 }
2398 
2399 /**
2400  * peek at the next word to determine if it is a C# non-paren header.
2401  * will look ahead in the input file if necessary.
2402  *
2403  * @param       char position on currentLine to start the search
2404  * @return      true if the next word is get or set.
2405  */
2406 bool ASFormatter::isNextWordSharpNonParenHeader(int startChar) const
2407 {
2408     // look ahead to find the next non-comment text
2409     string nextText = peekNextText(currentLine.substr(startChar));
2410     if (nextText.length() == 0)
2411         return false;
2412     if (nextText[0] == '[')
2413         return true;
2414     if (!isCharPotentialHeader(nextText, 0))
2415         return false;
2416     if (findKeyword(nextText, 0, AS_GET) || findKeyword(nextText, 0, AS_SET)
2417             || findKeyword(nextText, 0, AS_ADD) || findKeyword(nextText, 0, AS_REMOVE))
2418         return true;
2419     return false;
2420 }
2421 
2422 /**
2423  * peek at the next char to determine if it is an opening bracket.
2424  * will look ahead in the input file if necessary.
2425  * this determines a java static constructor.
2426  *
2427  * @param       char position on currentLine to start the search
2428  * @return      true if the next word is an opening bracket.
2429  */
2430 bool ASFormatter::isNextCharOpeningBracket(int startChar) const
2431 {
2432     bool retVal = false;
2433     string nextText = peekNextText(currentLine.substr(startChar));
2434     if (nextText.compare(0, 1, "{") == 0)
2435         retVal = true;
2436     return retVal;
2437 }
2438 
2439 /**
2440  * get the next non-whitespace substring on following lines, bypassing all comments.
2441  *
2442  * @param   the first line to check
2443  * @return  the next non-whitespace substring.
2444  */
2445 string ASFormatter::peekNextText(const string& firstLine, bool endOnEmptyLine /*false*/) const
2446 {
2447     bool isFirstLine = true;
2448     bool needReset = false;
2449     string nextLine = firstLine;
2450     size_t firstChar= string::npos;
2451 
2452     // find the first non-blank text, bypassing all comments.
2453     bool isInComment = false;
2454     while (sourceIterator->hasMoreLines())
2455     {
2456         if (isFirstLine)
2457             isFirstLine = false;
2458         else
2459         {
2460             nextLine = sourceIterator->peekNextLine();
2461             needReset = true;
2462         }
2463 
2464         firstChar = nextLine.find_first_not_of(" \t");
2465         if (firstChar == string::npos)
2466         {
2467             if (endOnEmptyLine && !isInComment)
2468                 break;
2469             continue;
2470         }
2471 
2472         if (nextLine.compare(firstChar, 2, "/*") == 0)
2473             isInComment = true;
2474 
2475         if (isInComment)
2476         {
2477             firstChar = nextLine.find("*/", firstChar);
2478             if (firstChar == string::npos)
2479                 continue;
2480             firstChar += 2;
2481             isInComment = false;
2482             firstChar = nextLine.find_first_not_of(" \t", firstChar);
2483             if (firstChar == string::npos)
2484                 continue;
2485         }
2486 
2487         if (nextLine.compare(firstChar, 2, "//") == 0)
2488             continue;
2489 
2490         // found the next text
2491         break;
2492     }
2493 
2494     if (needReset)
2495         sourceIterator->peekReset();
2496     if (firstChar == string::npos)
2497         nextLine = "";
2498     else
2499         nextLine = nextLine.substr(firstChar);
2500     return nextLine;
2501 }
2502 
2503 /**
2504  * adjust comment position because of adding or deleting spaces
2505  * the spaces are added or deleted to formattedLine
2506  * spacePadNum contains the adjustment
2507  */
2508 void ASFormatter::adjustComments(void)
2509 {
2510     assert(spacePadNum != 0);
2511     assert(currentLine.compare(charNum, 2, "//") == 0
2512            || currentLine.compare(charNum, 2, "/*") == 0);
2513 
2514 
2515     // block comment must be closed on this line with nothing after it
2516     if (currentLine.compare(charNum, 2, "/*") == 0)
2517     {
2518         size_t endNum = currentLine.find("*/", charNum + 2);
2519         if (endNum == string::npos)
2520             return;
2521         if (currentLine.find_first_not_of(" \t", endNum + 2) != string::npos)
2522             return;
2523     }
2524 
2525     size_t len = formattedLine.length();
2526     // don't adjust a tab
2527     if (formattedLine[len-1] == '\t')
2528         return;
2529     // if spaces were removed, need to add spaces before the comment
2530     if (spacePadNum < 0)
2531     {
2532         int adjust = -spacePadNum;          // make the number positive
2533         formattedLine.append(adjust, ' ');
2534     }
2535     // if spaces were added, need to delete extra spaces before the comment
2536     // if cannot be done put the comment one space after the last text
2537     else if (spacePadNum > 0)
2538     {
2539         int adjust = spacePadNum;
2540         size_t lastText = formattedLine.find_last_not_of(' ');
2541         if (lastText != string::npos
2542                 && lastText < len - adjust - 1)
2543             formattedLine.resize(len - adjust);
2544         else if (len > lastText + 2)
2545             formattedLine.resize(lastText + 2);
2546         else if (len < lastText + 2)
2547             formattedLine.append(len - lastText, ' ');
2548     }
2549 }
2550 
2551 /**
2552  * append the current bracket inside the end of line comments
2553  * currentChar contains the bracket, it will be appended to formattedLine
2554  * formattedLineCommentNum is the comment location on formattedLine
2555  * returns true f appended, false if not
2556  */
2557 void ASFormatter::appendCharInsideComments(void)
2558 {
2559     if (formattedLineCommentNum == string::npos)    // does the comment start on the previous line?
2560     {
2561         appendCurrentChar();                        // don't attach
2562         return; // false;
2563     }
2564     assert(formattedLine.compare(formattedLineCommentNum, 2, "//") == 0
2565            || formattedLine.compare(formattedLineCommentNum, 2, "/*") == 0);
2566 
2567     // find the previous non space char
2568     size_t end = formattedLineCommentNum;
2569     size_t beg = formattedLine.find_last_not_of(" \t", end-1);
2570     if (beg == string::npos)                // is the previous line comment only?
2571     {
2572         appendCurrentChar();                // don't attach
2573         return; // false;
2574     }
2575     beg++;
2576 
2577     // insert the bracket
2578     if (end - beg < 3)                      // is there room to insert?
2579         formattedLine.insert(beg, 3-end+beg, ' ');
2580     if (formattedLine[beg] == '\t')         // don't pad with a tab
2581         formattedLine.insert(beg, 1, ' ');
2582     formattedLine[beg+1] = currentChar;
2583 
2584     if (isBeforeComment())
2585         breakLine();
2586     else if (isCharImmediatelyPostLineComment)
2587         shouldBreakLineAtNextChar = true;
2588     return; // true;
2589 }
2590 
2591 /**
2592  * add or remove space padding to operators
2593  * currentChar contains the paren
2594  * the operators and necessary padding will be appended to formattedLine
2595  * the calling function should have a continue statement after calling this method
2596  *
2597  * @param *newOperator     the operator to be padded
2598  */
2599 void ASFormatter::padOperators(const string *newOperator)
2600 {
2601     assert(newOperator != NULL);
2602 
2603     bool shouldPad = (newOperator != &AS_COLON_COLON
2604                       && newOperator != &AS_PAREN_PAREN
2605                       && newOperator != &AS_BLPAREN_BLPAREN
2606                       && newOperator != &AS_PLUS_PLUS
2607                       && newOperator != &AS_MINUS_MINUS
2608                       && newOperator != &AS_NOT
2609                       && newOperator != &AS_BIT_NOT
2610                       && newOperator != &AS_ARROW
2611                       && !(newOperator == &AS_MINUS && isInExponent())
2612                       && !((newOperator == &AS_PLUS || newOperator == &AS_MINUS)  // check for unary plus or minus
2613                            && (previousNonWSChar == '('
2614                                || previousNonWSChar == '='
2615                                || previousNonWSChar == ','))
2616                       && !(newOperator == &AS_PLUS && isInExponent())
2617                       && !isCharImmediatelyPostOperator
2618                       && !((newOperator == &AS_MULT || newOperator == &AS_BIT_AND)
2619                            && isPointerOrReference())
2620                       && !(newOperator == &AS_MULT
2621                            && (previousNonWSChar == '.'
2622                                || previousNonWSChar == '>'))    // check for ->
2623                       && !((isInTemplate || isCharImmediatelyPostTemplate)
2624                            && (newOperator == &AS_LS || newOperator == &AS_GR))
2625                       && !(newOperator == &AS_GCC_MIN_ASSIGN
2626                            && ASBase::peekNextChar(currentLine, charNum+1) == '>')
2627                       && !(newOperator == &AS_GR && previousNonWSChar == '?')
2628                       && !isInCase
2629                       && !isInAsm
2630                       && !isInAsmOneLine
2631                       && !isInAsmBlock
2632                      );
2633 
2634     // pad before operator
2635     if (shouldPad
2636             && !isInBlParen
2637             && !(newOperator == &AS_COLON && !foundQuestionMark)
2638             && !(newOperator == &AS_QUESTION && isSharpStyle() // check for C# nullable type (e.g. int?)
2639                  && currentLine.find(':', charNum+1) == string::npos)
2640        )
2641         appendSpacePad();
2642     appendSequence(*newOperator);
2643     goForward(newOperator->length() - 1);
2644 
2645     // since this block handles '()' and '[]',
2646     // the parenStack must be updated here accordingly!
2647     if (newOperator == &AS_PAREN_PAREN
2648             || newOperator == &AS_BLPAREN_BLPAREN)
2649         parenStack->back()--;
2650 
2651     currentChar = (*newOperator)[newOperator->length() - 1];
2652     // pad after operator
2653     // but do not pad after a '-' that is a unary-minus.
2654     if (shouldPad
2655             && !isInBlParen
2656             && !isBeforeAnyComment()
2657             && !(newOperator == &AS_PLUS && isUnaryOperator())
2658             && !(newOperator == &AS_MINUS && isUnaryOperator())
2659             && !(currentLine.compare(charNum + 1, 1,  ";") == 0)
2660             && !(currentLine.compare(charNum + 1, 2, "::") == 0)
2661             && !(newOperator == &AS_QUESTION && isSharpStyle() // check for C# nullable type (e.g. int?)
2662                  && currentLine[charNum+1] == '[')
2663        )
2664         appendSpaceAfter();
2665 
2666     previousOperator = newOperator;
2667     return;
2668 }
2669 
2670 /**
2671  * format pointer or reference
2672  * currentChar contains the pointer or reference
2673  * the symbol and necessary padding will be appended to formattedLine
2674  * the calling function should have a continue statement after calling this method
2675  */
2676 void ASFormatter::formatPointerOrReference(void)
2677 {
2678     assert(currentChar == '*' || currentChar == '&');
2679     assert(isCStyle());
2680 
2681     // check for cast
2682     char peekedChar = peekNextChar();
2683     if (currentChar == '*'
2684             && (int) currentLine.length() > charNum
2685             && currentLine[charNum+1] == '*')
2686     {
2687         size_t nextChar = currentLine.find_first_not_of(" \t", charNum+2);
2688         if (nextChar == string::npos)
2689             peekedChar = ' ';
2690         else
2691             peekedChar = currentLine[nextChar];
2692     }
2693     if (peekedChar == ')' || peekedChar =='>' || peekedChar ==',')
2694     {
2695         formatPointerOrReferenceCast();
2696         return;
2697     }
2698 
2699     // do this before bumping charNum
2700     bool isOldPRCentered = isPointerOrReferenceCentered();
2701 
2702     if (pointerAlignment == ALIGN_TYPE)
2703     {
2704         size_t prevCh = formattedLine.find_last_not_of(" \t");
2705         if (prevCh == string::npos)
2706             prevCh = 0;
2707         if (formattedLine.length() == 0 || prevCh == formattedLine.length() - 1)
2708             appendCurrentChar();
2709         else
2710         {
2711             // exchange * or & with character following the type
2712             // this may not work every time with a tab character
2713             string charSave = formattedLine.substr(prevCh+1, 1);
2714             formattedLine[prevCh+1] = currentChar;
2715             formattedLine.append(charSave);
2716         }
2717         if (isSequenceReached("**"))
2718         {
2719             formattedLine.insert(prevCh+2, "*");
2720             goForward(1);
2721         }
2722         // if no space after * then add one
2723         if (charNum < (int) currentLine.length() - 1
2724                 && !isWhiteSpace(currentLine[charNum+1])
2725                 && currentLine[charNum+1] != ')')
2726             appendSpacePad();
2727         // if old pointer or reference is centered, remove a space
2728         if (isOldPRCentered
2729                 && isWhiteSpace(formattedLine[formattedLine.length()-1]))
2730         {
2731             formattedLine.erase(formattedLine.length()-1, 1);
2732             spacePadNum--;
2733         }
2734     }
2735     else if (pointerAlignment == ALIGN_MIDDLE)
2736     {
2737         // compute current whitespace before
2738         size_t wsBefore = currentLine.find_last_not_of(" \t", charNum - 1);
2739         if (wsBefore == string::npos)
2740             wsBefore = 0;
2741         else
2742             wsBefore = charNum - wsBefore - 1;
2743         // adjust for **
2744         string sequenceToInsert = currentChar == '*' ? "*" : "&";
2745         if (isSequenceReached("**"))
2746         {
2747             sequenceToInsert = "**";
2748             goForward(1);
2749         }
2750         size_t charNumSave = charNum;
2751         // goForward() to convert tabs to spaces, if necessary,
2752         // and move following characters to preceding characters
2753         // this may not work every time with tab characters
2754         for (size_t i = charNum+1; i < currentLine.length() && isWhiteSpace(currentLine[i]); i++)
2755         {
2756             goForward(1);
2757             formattedLine.append(1, currentLine[i]);
2758         }
2759         // whitespace should be at least 2 chars
2760         size_t wsAfter = currentLine.find_first_not_of(" \t", charNumSave + 1);
2761         if (wsAfter == string::npos)
2762             wsAfter = 0;
2763         else
2764             wsAfter = wsAfter - charNumSave - 1;
2765         if (wsBefore + wsAfter < 2)
2766         {
2767             size_t charsToAppend = (2 - (wsBefore + wsAfter));
2768             formattedLine.append(charsToAppend, ' ');
2769             spacePadNum += charsToAppend;
2770             if (wsBefore == 0) wsBefore++;
2771             if (wsAfter == 0) wsAfter++;
2772         }
2773         // insert the pointer or reference char
2774         size_t padAfter = (wsBefore + wsAfter) / 2;
2775         formattedLine.insert(formattedLine.length() - padAfter, sequenceToInsert);
2776     }
2777     else if (pointerAlignment == ALIGN_NAME)
2778     {
2779         size_t startNum = formattedLine.find_last_not_of(" \t");
2780         string sequenceToInsert = currentChar == '*' ? "*" : "&";
2781         if (isSequenceReached("**"))
2782         {
2783             sequenceToInsert = "**";
2784             goForward(1);
2785         }
2786         // goForward() to convert tabs to spaces, if necessary,
2787         // and move following characters to preceding characters
2788         // this may not work every time with tab characters
2789         for (size_t i = charNum+1; i < currentLine.length() && isWhiteSpace(currentLine[i]); i++)
2790         {
2791             goForward(1);
2792             formattedLine.append(1, currentLine[i]);
2793         }
2794         appendSequence(sequenceToInsert, false);
2795         // if no space before * then add one
2796         if (startNum != string::npos
2797                 && !isWhiteSpace(formattedLine[startNum+1]))
2798         {
2799             formattedLine.insert(startNum+1 , 1, ' ');
2800             spacePadNum++;
2801         }
2802         // if old pointer or reference is centered, remove a space
2803         if (isOldPRCentered
2804                 && formattedLine.length() > startNum+1
2805                 && isWhiteSpace(formattedLine[startNum+1]))
2806         {
2807             formattedLine.erase(startNum+1, 1);
2808             spacePadNum--;
2809         }
2810     }
2811     else    // pointerAlignment == ALIGN_NONE
2812     {
2813         appendCurrentChar();
2814     }
2815     return;
2816 }
2817 
2818 /**
2819  * format pointer or reference cast
2820  * currentChar contains the pointer or reference
2821  * NOTE: the pointers and references in function definitions
2822  *       are processed as a cast (e.g. void foo(void*, void*))
2823  *       is processed here.
2824  */
2825 void ASFormatter::formatPointerOrReferenceCast(void)
2826 {
2827     assert(currentChar == '*' || currentChar == '&');
2828     assert(isCStyle());
2829 
2830     string sequenceToInsert = currentChar == '*' ? "*" : "&";
2831     if (isSequenceReached("**"))
2832     {
2833         sequenceToInsert = "**";
2834         goForward(1);
2835     }
2836     if (pointerAlignment == ALIGN_NONE)
2837     {
2838         appendSequence(sequenceToInsert, false);
2839         return;
2840     }
2841     // remove trailing whitespace
2842     size_t prevCh = formattedLine.find_last_not_of(" \t");
2843     if (prevCh == string::npos)
2844         prevCh = 0;
2845     if (formattedLine.length() > 0 && isWhiteSpace(formattedLine[prevCh+1]))
2846     {
2847         spacePadNum -= (formattedLine.length() - 1 - prevCh);
2848         formattedLine.erase(prevCh+1);
2849     }
2850     if (pointerAlignment == ALIGN_TYPE)
2851     {
2852         appendSequence(sequenceToInsert, false);
2853     }
2854     else if (pointerAlignment == ALIGN_MIDDLE
2855              || pointerAlignment == ALIGN_NAME)
2856     {
2857         appendSpacePad();
2858         appendSequence(sequenceToInsert, false);
2859     }
2860     else
2861         appendSequence(sequenceToInsert, false);
2862 }
2863 
2864 /**
2865  * add or remove space padding to parens
2866  * currentChar contains the paren
2867  * the parens and necessary padding will be appended to formattedLine
2868  * the calling function should have a continue statement after calling this method
2869  */
2870 void ASFormatter::padParens(void)
2871 {
2872     assert(currentChar == '(' || currentChar == ')');
2873 
2874     int spacesOutsideToDelete = 0;
2875     int spacesInsideToDelete = 0;
2876 
2877     if (currentChar == '(')
2878     {
2879         spacesOutsideToDelete = formattedLine.length() - 1;
2880         spacesInsideToDelete = 0;
2881 
2882         // compute spaces outside the opening paren to delete
2883         if (shouldUnPadParens)
2884         {
2885             char lastChar = ' ';
2886             bool prevIsParenHeader = false;
2887             size_t i = formattedLine.find_last_not_of(" \t");
2888             if (i != string::npos)
2889             {
2890                 // if last char is a bracket the previous whitespace is an indent
2891                 if (formattedLine[i] == '{')
2892                     spacesOutsideToDelete = 0;
2893                 else
2894                 {
2895                     spacesOutsideToDelete -= i;
2896                     lastChar = formattedLine[i];
2897                     // if previous word is a header, it will be a paren header
2898                     string prevWord = getPreviousWord(formattedLine, formattedLine.length());
2899                     const string* prevWordH = NULL;
2900                     if (shouldPadHeader
2901                             && prevWord.length() > 0
2902                             && isCharPotentialHeader(prevWord, 0))
2903                         prevWordH = ASBeautifier::findHeader(prevWord, 0, headers);
2904                     if (prevWordH != NULL)
2905                     {
2906                         prevIsParenHeader = true;
2907                         // trace
2908                         //cout << traceLineNumber << " " << *prevWordH << endl;
2909                     }
2910                     else if (prevWord == "return"   // don't unpad return statements
2911                              || prevWord == "*")    // don't unpad multiply or pointer
2912                     {
2913                         prevIsParenHeader = true;
2914                         // trace
2915                         //cout << traceLineNumber << " " << prevWord << endl;
2916                     }
2917                     // don't unpad variables
2918                     else if (prevWord == "bool"
2919                              || prevWord ==  "int"
2920                              || prevWord ==  "void"
2921                              || prevWord ==  "void*"
2922                              || (prevWord.length() >= 6     // check end of word for _t
2923                                  && prevWord.compare(prevWord.length()-2, 2, "_t") == 0)
2924                              || prevWord ==  "BOOL"
2925                              || prevWord ==  "DWORD"
2926                              || prevWord ==  "HWND"
2927                              || prevWord ==  "INT"
2928                              || prevWord ==  "LPSTR"
2929                              || prevWord ==  "VOID"
2930                              || prevWord ==  "LPVOID"
2931                             )
2932                     {
2933                         prevIsParenHeader = true;
2934                         // trace
2935                         //cout << traceLineNumber << " " << prevWord << endl;
2936                     }
2937                 }
2938             }
2939             // do not unpad operators, but leave them if already padded
2940             if (shouldPadParensOutside || prevIsParenHeader)
2941                 spacesOutsideToDelete--;
2942             else if (lastChar == '|'          // check for ||
2943                      || lastChar == '&'      // check for &&
2944                      || lastChar == ','
2945                      || (lastChar == '>' && !foundCastOperator)
2946                      || lastChar == '<'
2947                      || lastChar == '?'
2948                      || lastChar == ':'
2949                      || lastChar == ';'
2950                      || lastChar == '='
2951                      || lastChar == '+'
2952                      || lastChar == '-'
2953                      || (lastChar == '*' && isInPotentialCalculation)
2954                      || lastChar == '/'
2955                      || lastChar == '%')
2956                 spacesOutsideToDelete--;
2957 
2958             if (spacesOutsideToDelete > 0)
2959             {
2960                 formattedLine.erase(i + 1, spacesOutsideToDelete);
2961                 spacePadNum -= spacesOutsideToDelete;
2962             }
2963         }
2964 
2965         // pad open paren outside
2966         char peekedCharOutside = peekNextChar();
2967         if (shouldPadParensOutside)
2968             if (!(currentChar == '(' && peekedCharOutside == ')'))
2969                 appendSpacePad();
2970 
2971         appendCurrentChar();
2972 
2973         // unpad open paren inside
2974         if (shouldUnPadParens)
2975         {
2976             size_t j = currentLine.find_first_not_of(" \t", charNum + 1);
2977             if (j != string::npos)
2978                 spacesInsideToDelete = j - charNum - 1;
2979             if (shouldPadParensInside)
2980                 spacesInsideToDelete--;
2981             if (spacesInsideToDelete > 0)
2982             {
2983                 currentLine.erase(charNum + 1, spacesInsideToDelete);
2984                 spacePadNum -= spacesInsideToDelete;
2985             }
2986             // convert tab to space if requested
2987             if (shouldConvertTabs
2988                     && (int)currentLine.length() > charNum
2989                     && currentLine[charNum+1] == '\t')
2990                 currentLine[charNum+1] = ' ';
2991 
2992         }
2993 
2994         // pad open paren inside
2995         char peekedCharInside = peekNextChar();
2996         if (shouldPadParensInside)
2997             if (!(currentChar == '(' && peekedCharInside == ')'))
2998                 appendSpaceAfter();
2999         // trace
3000         //if(spacesOutsideToDelete > 0 || spacesInsideToDelete > 0)
3001         //    cout << traceLineNumber << " " << spacesOutsideToDelete << '(' << spacesInsideToDelete << endl;
3002     }
3003     else if (currentChar == ')' /*|| currentChar == ']'*/)
3004     {
3005         spacesOutsideToDelete = 0;
3006         spacesInsideToDelete = formattedLine.length();
3007 
3008         // unpad close paren inside
3009         if (shouldUnPadParens)
3010         {
3011             size_t i = formattedLine.find_last_not_of(" \t");
3012             if (i != string::npos)
3013                 spacesInsideToDelete = formattedLine.length() - 1 - i;
3014             if (shouldPadParensInside)
3015                 spacesInsideToDelete--;
3016             if (spacesInsideToDelete > 0)
3017             {
3018                 formattedLine.erase(i + 1, spacesInsideToDelete);
3019                 spacePadNum -= spacesInsideToDelete;
3020             }
3021         }
3022 
3023         // pad close paren inside
3024         if (shouldPadParensInside)
3025             if (!(previousChar == '(' && currentChar == ')'))
3026                 appendSpacePad();
3027 
3028         appendCurrentChar();
3029 
3030         // unpad close paren outside
3031         if (shouldUnPadParens)
3032         {
3033             // may have end of line comments
3034             size_t j = currentLine.find_first_not_of(" \t", charNum + 1);
3035             if (j != string::npos)
3036                 if (currentLine[j] == '[' || currentLine[j] == ']')
3037                     spacesOutsideToDelete = j - charNum - 1;
3038             if (shouldPadParensOutside)
3039                 spacesOutsideToDelete--;
3040 
3041             if (spacesOutsideToDelete > 0)
3042             {
3043                 currentLine.erase(charNum + 1, spacesOutsideToDelete);
3044                 spacePadNum -= spacesOutsideToDelete;
3045             }
3046         }
3047 
3048         // pad close paren outside
3049         char peekedCharOutside = peekNextChar();
3050         if (shouldPadParensOutside)
3051             if (peekedCharOutside != ';'
3052                     && peekedCharOutside != ','
3053                     && peekedCharOutside != '.'
3054                     && peekedCharOutside != '-')    // check for ->
3055                 appendSpaceAfter();
3056 
3057         // trace
3058         //if(spacesInsideToDelete > 0)
3059         //  cout << traceLineNumber << " " << spacesInsideToDelete << ')' << 0 << endl;
3060     }
3061     return;
3062 }
3063 
3064 /**
3065  * format opening bracket as attached or broken
3066  * currentChar contains the bracket
3067  * the brackets will be appended to the current formattedLine or a new formattedLine as necessary
3068  * the calling function should have a continue statement after calling this method
3069  *
3070  * @param bracketType    the type of bracket to be formatted.
3071  */
3072 void ASFormatter::formatOpeningBracket(BracketType bracketType)
3073 {
3074     assert(!isBracketType(bracketType, ARRAY_TYPE));
3075     assert(currentChar == '{');
3076 
3077     parenStack->push_back(0);
3078 
3079     bool breakBracket = isCurrentBracketBroken();
3080 
3081     if (breakBracket)
3082     {
3083         if (isBeforeAnyComment() && isOkToBreakBlock(bracketType))
3084         {
3085             // if comment is at line end leave the comment on this line
3086             if (isBeforeAnyLineEndComment(charNum) && !currentLineBeginsWithBracket)    // lineBeginsWith('{')
3087             {
3088                 currentChar = ' ';              // remove bracket from current line
3089                 currentLine[charNum] = currentChar;
3090                 appendOpeningBracket = true;    // append bracket to following line
3091             }
3092             // else put comment after the bracket
3093             else if (!isBeforeMultipleLineEndComments(charNum))
3094                 breakLine();
3095         }
3096         else if (!isBracketType(bracketType, SINGLE_LINE_TYPE))
3097             breakLine();
3098         else if (shouldBreakOneLineBlocks && peekNextChar() != '}')
3099             breakLine();
3100         else if (!isInLineBreak)
3101             appendSpacePad();
3102 
3103         appendCurrentChar();
3104 
3105         // should a following comment break from the bracket?
3106         // must break the line AFTER the bracket
3107         if (isBeforeComment()
3108                 && formattedLine[0] == '{'
3109                 && isOkToBreakBlock(bracketType)
3110                 && (bracketFormatMode == BREAK_MODE
3111                     || bracketFormatMode == LINUX_MODE
3112                     || bracketFormatMode == STROUSTRUP_MODE))
3113         {
3114             shouldBreakLineAtNextChar = true;
3115         }
3116 
3117     }
3118     else    // attach bracket
3119     {
3120         // are there comments before the bracket?
3121         if (isCharImmediatelyPostComment || isCharImmediatelyPostLineComment)
3122         {
3123             if (isOkToBreakBlock(bracketType)
3124                     && !(isCharImmediatelyPostComment && isCharImmediatelyPostLineComment)  // don't attach if two comments on the line
3125                     && peekNextChar() != '}'        // don't attach { }
3126                     && previousCommandChar != '{'   // don't attach { {
3127                     && previousCommandChar != '}'   // don't attach } {
3128                     && previousCommandChar != ';')  // don't attach ; {
3129             {
3130                 appendCharInsideComments();
3131             }
3132             else
3133             {
3134                 appendCurrentChar();            // don't attach
3135             }
3136         }
3137         else if (previousCommandChar == '{'
3138                  || previousCommandChar == '}'
3139                  || previousCommandChar == ';')  // '}' , ';' chars added for proper handling of '{' immediately after a '}' or ';'
3140         {
3141             appendCurrentChar();                // don't attach
3142         }
3143         else
3144         {
3145             // if a blank line preceeds this don't attach
3146             if (isEmptyLine(formattedLine))
3147                 appendCurrentChar();            // don't attach
3148             else if (isOkToBreakBlock(bracketType)
3149                      && !(isImmediatelyPostPreprocessor
3150                           && currentLineBeginsWithBracket))     // lineBeginsWith('{')
3151             {
3152                 if (peekNextChar() != '}')
3153                 {
3154                     appendSpacePad();
3155                     appendCurrentChar(false);       // OK to attach
3156                     // should a following comment attach with the bracket?
3157                     // insert spaces to reposition the comment
3158                     if (isBeforeComment()
3159                             && !isBeforeMultipleLineEndComments(charNum)
3160                             && (!isBeforeAnyLineEndComment(charNum) || currentLineBeginsWithBracket))   // lineBeginsWith('{')
3161                     {
3162                         breakLine();
3163                         currentLine.insert(charNum+1, charNum+1, ' ');
3164                     }
3165                 }
3166                 else
3167                 {
3168                     appendSpacePad();
3169                     appendCurrentChar();
3170                 }
3171             }
3172             else
3173             {
3174                 if (!isInLineBreak)
3175                     appendSpacePad();
3176                 appendCurrentChar();            // don't attach
3177             }
3178         }
3179     }
3180 }
3181 
3182 /**
3183  * format closing bracket
3184  * currentChar contains the bracket
3185  * the calling function should have a continue statement after calling this method
3186  *
3187  * @param bracketType    the type of bracket to be formatted.
3188  */
3189 void ASFormatter::formatClosingBracket(BracketType bracketType)
3190 {
3191     assert(!isBracketType(bracketType, ARRAY_TYPE));
3192     assert(currentChar == '}');
3193 
3194     // parenStack must contain one entry
3195     if (parenStack->size() > 1)
3196         parenStack->pop_back();
3197 
3198     // mark state of immediately after empty block
3199     // this state will be used for locating brackets that appear immedately AFTER an empty block (e.g. '{} \n}').
3200     if (previousCommandChar == '{')
3201         isImmediatelyPostEmptyBlock = true;
3202 
3203     if ((!(previousCommandChar == '{' && isPreviousBracketBlockRelated))    // this '{' does not close an empty block
3204             && isOkToBreakBlock(bracketType)                                // astyle is allowed to break on line blocks
3205             && !isImmediatelyPostEmptyBlock)                                // this '}' does not immediately follow an empty block
3206     {
3207         breakLine();
3208         appendCurrentChar();
3209     }
3210     else
3211     {
3212         appendCurrentChar();
3213     }
3214 
3215     // if a declaration follows a definition, space pad
3216     if (isLegalNameChar(peekNextChar()))
3217         appendSpaceAfter();
3218 
3219     if (shouldBreakBlocks && currentHeader != NULL && parenStack->back() == 0)
3220     {
3221         isAppendPostBlockEmptyLineRequested = true;
3222     }
3223 }
3224 
3225 /**
3226  * format array brackets as attached or broken
3227  * determine if the brackets can have an inStatement indent
3228  * currentChar contains the bracket
3229  * the brackets will be appended to the current formattedLine or a new formattedLine as necessary
3230  * the calling function should have a continue statement after calling this method
3231  *
3232  * @param bracketType            the type of bracket to be formatted, must be an ARRAY_TYPE.
3233  * @param isOpeningArrayBracket  indicates if this is the opening bracket for the array block.
3234  */
3235 void ASFormatter::formatArrayBrackets(BracketType bracketType, bool isOpeningArrayBracket)
3236 {
3237     assert(isBracketType(bracketType, ARRAY_TYPE));
3238     assert(currentChar == '{' || currentChar == '}');
3239 
3240     if (currentChar == '{')
3241     {
3242         // is this the first opening bracket in the array?
3243         if (isOpeningArrayBracket)
3244         {
3245             if (bracketFormatMode == ATTACH_MODE
3246                     || bracketFormatMode == LINUX_MODE
3247                     || bracketFormatMode == STROUSTRUP_MODE)
3248             {
3249                 // don't attach to a preprocessor directive
3250                 if (isImmediatelyPostPreprocessor && currentLineBeginsWithBracket)  // lineBeginsWith('{')
3251                 {
3252                     isInLineBreak = true;
3253                     appendCurrentChar();                // don't attach
3254                 }
3255                 else if (isCharImmediatelyPostComment)
3256                 {
3257                     // TODO: attach bracket to line-end comment
3258                     appendCurrentChar();                // don't attach
3259                 }
3260                 else if (isCharImmediatelyPostLineComment)
3261                 {
3262                     appendCharInsideComments();
3263                 }
3264                 else
3265                 {
3266                     // if a blank line preceeds this don't attach
3267                     if (isEmptyLine(formattedLine))
3268                         appendCurrentChar();            // don't attach
3269                     else
3270                     {
3271                         // if bracket is broken or not an assignment
3272                         if (currentLineBeginsWithBracket    // lineBeginsWith('{')
3273                                 && !isBracketType(bracketTypeStack->back(), SINGLE_LINE_TYPE))
3274                         {
3275                             appendSpacePad();
3276                             appendCurrentChar(false);       // OK to attach
3277 
3278                             if (currentLineBeginsWithBracket
3279                                     && (int)currentLineFirstBracketNum == charNum)
3280                                 shouldBreakLineAtNextChar = true;
3281                         }
3282                         else
3283                         {
3284                             appendSpacePad();
3285                             appendCurrentChar();
3286                         }
3287                     }
3288                 }
3289             }
3290             else if (bracketFormatMode == BREAK_MODE)
3291             {
3292                 if (isWhiteSpace(peekNextChar()))
3293                     breakLine();
3294                 else if (isBeforeAnyComment())
3295                 {
3296                     // do not break unless comment is at line end
3297                     if (isBeforeAnyLineEndComment(charNum) && !currentLineBeginsWithBracket)
3298                     {
3299                         currentChar = ' ';              // remove bracket from current line
3300                         appendOpeningBracket = true;    // append bracket to following line
3301                     }
3302                 }
3303                 if (!isInLineBreak)
3304                     appendSpacePad();
3305                 appendCurrentChar();
3306 
3307                 if (currentLineBeginsWithBracket
3308                         && (int)currentLineFirstBracketNum == charNum
3309                         && !isBracketType(bracketTypeStack->back(), SINGLE_LINE_TYPE))
3310                     shouldBreakLineAtNextChar = true;
3311             }
3312             else if (bracketFormatMode == HORSTMANN_MODE)
3313             {
3314                 if (isWhiteSpace(peekNextChar()))
3315                     breakLine();
3316                 else if (isBeforeAnyComment())
3317                 {
3318                     // do not break unless comment is at line end
3319                     if (isBeforeAnyLineEndComment(charNum) && !currentLineBeginsWithBracket)    // lineBeginsWith('{')
3320                     {
3321                         currentChar = ' ';              // remove bracket from current line
3322                         appendOpeningBracket = true;    // append bracket to following line
3323                     }
3324                 }
3325                 if (!isInLineBreak)
3326                     appendSpacePad();
3327                 appendCurrentChar();
3328             }
3329             else if (bracketFormatMode == NONE_MODE)
3330             {
3331                 if (currentLineBeginsWithBracket)       // lineBeginsWith('{')
3332                 {
3333                     appendCurrentChar();                // don't attach
3334                 }
3335                 else
3336                 {
3337                     appendSpacePad();
3338                     appendCurrentChar(false);           // OK to attach
3339                 }
3340             }
3341         }
3342         else         // not the first opening bracket
3343         {
3344             if (bracketFormatMode == HORSTMANN_MODE)
3345             {
3346                 if (previousNonWSChar == '{'
3347                         && bracketTypeStack->size() > 2
3348                         && !isBracketType((*bracketTypeStack)[bracketTypeStack->size()-2], SINGLE_LINE_TYPE))
3349                     formatArrayRunIn();
3350             }
3351             else if (!isInLineBreak
3352                      && !isWhiteSpace(peekNextChar())
3353                      && previousNonWSChar == '{'
3354                      && bracketTypeStack->size() > 2
3355                      && !isBracketType((*bracketTypeStack)[bracketTypeStack->size()-2], SINGLE_LINE_TYPE))
3356                 formatArrayRunIn();
3357 
3358             appendCurrentChar();
3359         }
3360     }
3361     else if (currentChar == '}')
3362     {
3363         // does this close the first opening bracket in the array?
3364         if (!isBracketType(bracketType, SINGLE_LINE_TYPE) )
3365             breakLine();
3366         appendCurrentChar();
3367 
3368         // if a declaration follows an enum definition, space pad
3369         char peekedChar = peekNextChar();
3370         if (isLegalNameChar(peekedChar)
3371                 || peekedChar == '[')
3372             appendSpaceAfter();
3373     }
3374 }
3375 
3376 /**
3377  * determine if a run-in can be attached.
3378  * if it can insert the indents in formattedLine and reset the current line break.
3379  */
3380 void ASFormatter::formatRunIn()
3381 {
3382     assert(bracketFormatMode == HORSTMANN_MODE || bracketFormatMode == NONE_MODE);
3383 
3384     // keep one line blocks returns true without indenting the run-in
3385     if (!isOkToBreakBlock(bracketTypeStack->back()))
3386         return; // true;
3387 
3388     size_t lastText = formattedLine.find_last_not_of(" \t");
3389     if (lastText == string::npos || formattedLine[lastText] != '{')
3390         return; // false;
3391 
3392     // make sure the bracket is broken
3393     if (formattedLine.find_first_not_of(" \t{") != string::npos)
3394         return; // false;
3395 
3396     if (isBracketType(bracketTypeStack->back(), NAMESPACE_TYPE))
3397         return; // false;
3398 
3399     bool extraIndent = false;
3400     isInLineBreak = true;
3401 
3402     // cannot attach a class modifier without indent-classes
3403     if (isCStyle()
3404             && isCharPotentialHeader(currentLine, charNum)
3405             && (isBracketType(bracketTypeStack->back(), CLASS_TYPE)
3406                 || (isBracketType(bracketTypeStack->back(), STRUCT_TYPE)
3407                     && isInIndentableStruct)))
3408     {
3409         if (findKeyword(currentLine, charNum, AS_PUBLIC)
3410                 || findKeyword(currentLine, charNum, AS_PRIVATE)
3411                 || findKeyword(currentLine, charNum, AS_PROTECTED))
3412         {
3413             if (!getClassIndent())
3414                 return; // false;
3415         }
3416         else if (getClassIndent())
3417             extraIndent = true;
3418     }
3419 
3420     // cannot attach a 'case' statement without indent-switches
3421     if (!getSwitchIndent()
3422             && isCharPotentialHeader(currentLine, charNum)
3423             && (findKeyword(currentLine, charNum, AS_CASE)
3424                 || findKeyword(currentLine, charNum, AS_DEFAULT)))
3425         return; // false;
3426 
3427     // extra indent for switch statements
3428     if (getSwitchIndent()
3429             && !preBracketHeaderStack->empty()
3430             && preBracketHeaderStack->back() == &AS_SWITCH
3431             && ((isLegalNameChar(currentChar)
3432                  && !findKeyword(currentLine, charNum, AS_CASE))
3433                 || isSequenceReached("//")
3434                 || isSequenceReached("/*")))
3435         extraIndent = true;
3436 
3437     isInLineBreak = false;
3438     // remove for extra whitespace
3439     if (formattedLine.length() > lastText+1
3440             && formattedLine.find_first_not_of(" \t", lastText+1) == string::npos)
3441         formattedLine.erase(lastText+1);
3442 
3443     if (getIndentString() == "\t")
3444     {
3445         appendChar('\t', false);
3446         horstmannIndentChars = 2;   // one for { and one for tab
3447         if (extraIndent)
3448         {
3449             appendChar('\t', false);
3450             horstmannIndentChars++;
3451         }
3452     }
3453     else
3454     {
3455         int indent = getIndentLength();
3456         formattedLine.append(indent-1, ' ');
3457         horstmannIndentChars = indent;
3458         if (extraIndent)
3459         {
3460             formattedLine.append(indent, ' ');
3461             horstmannIndentChars += indent;
3462         }
3463     }
3464     isInHorstmannRunIn = true;
3465 }
3466 
3467 /**
3468  * remove whitepace and add indentation for an array run-in.
3469  */
3470 void ASFormatter::formatArrayRunIn()
3471 {
3472     assert(isBracketType(bracketTypeStack->back(), ARRAY_TYPE));
3473 
3474     // make sure the bracket is broken
3475     if (formattedLine.find_first_not_of(" \t{") != string::npos)
3476         return;
3477 
3478     size_t lastText = formattedLine.find_last_not_of(" \t");
3479     if (lastText == string::npos || formattedLine[lastText] != '{')
3480         return;
3481 
3482     // check for extra whitespace
3483     if (formattedLine.length() > lastText+1
3484             && formattedLine.find_first_not_of(" \t", lastText+1) == string::npos)
3485         formattedLine.erase(lastText+1);
3486 
3487     if (getIndentString() == "\t")
3488     {
3489         appendChar('\t', false);
3490         horstmannIndentChars = 2;   // one for { and one for tab
3491     }
3492     else
3493     {
3494         int indent = getIndentLength();
3495         formattedLine.append(indent-1, ' ');
3496         horstmannIndentChars = indent;
3497     }
3498     isInHorstmannRunIn = true;
3499     isInLineBreak = false;
3500 }
3501 
3502 /**
3503  * delete a bracketTypeStack vector object
3504  * BracketTypeStack did not work with the DeleteContainer template
3505  */
3506 void ASFormatter::deleteContainer(vector<BracketType>* &container)
3507 {
3508     if (container != NULL)
3509     {
3510         container->clear();
3511         delete (container);
3512         container = NULL;
3513     }
3514 }
3515 
3516 /**
3517  * delete a vector object
3518  * T is the type of vector
3519  * used for all vectors except bracketTypeStack
3520  */
3521 template<typename T>
3522 void ASFormatter::deleteContainer(T &container)
3523 {
3524     if (container != NULL)
3525     {
3526         container->clear();
3527         delete (container);
3528         container = NULL;
3529     }
3530 }
3531 
3532 /**
3533  * initialize a BracketType vector object
3534  * BracketType did not work with the DeleteContainer template
3535  */
3536 void ASFormatter::initContainer(vector<BracketType>* &container, vector<BracketType>* value)
3537 {
3538     if (container != NULL)
3539         deleteContainer(container);
3540     container = value;
3541 }
3542 
3543 /**
3544  * initialize a vector object
3545  * T is the type of vector
3546  * used for all vectors except bracketTypeStack
3547  */
3548 template<typename T>
3549 void ASFormatter::initContainer(T &container, T value)
3550 {
3551     // since the ASFormatter object is never deleted,
3552     // the existing vectors must be deleted before creating new ones
3553     if (container != NULL)
3554         deleteContainer(container);
3555     container = value;
3556 }
3557 
3558 /**
3559  * convert a tab to spaces.
3560  * charNum points to the current character to convert to spaces.
3561  * tabIncrementIn is the increment that must be added for tab indent characters
3562  *     to get the correct column for the current tab.
3563  * replaces the tab in currentLine with the required number of spaces.
3564  * replaces the value of currentChar.
3565  */
3566 void ASFormatter::convertTabToSpaces()
3567 {
3568     assert(currentLine[charNum] == '\t');
3569 
3570     // do NOT replace if in quotes
3571     if (isInQuote || isInQuoteContinuation)
3572         return;
3573 
3574     size_t indent = getIndentLength();
3575     size_t numSpaces = indent - ((tabIncrementIn + charNum) % indent);
3576     currentLine.replace(charNum, 1, numSpaces, ' ');
3577     currentChar = currentLine[charNum];
3578 }
3579 
3580 /**
3581 * is it ok to break this block?
3582 */
3583 bool ASFormatter::isOkToBreakBlock(BracketType bracketType) const
3584 {
3585     // Actually, there should not be an ARRAY_TYPE bracket here.
3586     // But this will avoid breaking a one line block when there is.
3587     // Otherwise they will be formatted differently on consecutive runs.
3588     if (isBracketType(bracketType, ARRAY_TYPE)
3589             && isBracketType(bracketType, SINGLE_LINE_TYPE))
3590         return false;
3591     if (!isBracketType(bracketType, SINGLE_LINE_TYPE)
3592             || shouldBreakOneLineBlocks
3593             || breakCurrentOneLineBlock)
3594         return true;
3595     return false;
3596 }
3597 
3598 /**
3599 * check if a sharp header is a paren or nonparen header
3600 */
3601 bool ASFormatter::isSharpStyleWithParen(const string* header) const
3602 {
3603     if (isSharpStyle() && peekNextChar() == '('
3604             && (header == &AS_CATCH
3605                 || header == &AS_DELEGATE))
3606         return true;
3607     return false;
3608 }
3609 
3610 /**
3611  * check for a following header when a comment is reached.
3612  * if a header follows, the comments are kept as part of the header block.
3613  * firstLine must contain the start of the comment.
3614  */
3615 void ASFormatter::checkForFollowingHeader(const string& firstLine)
3616 {
3617     // look ahead to find the next non-comment text
3618     string nextText = peekNextText(firstLine, true);
3619     if (nextText.length() == 0 || !isCharPotentialHeader(nextText, 0))
3620         return;
3621 
3622     const string* newHeader = ASBeautifier::findHeader(nextText, 0, headers);
3623 
3624     if (newHeader == NULL)
3625         return;
3626 
3627     // may need to break if a header follows
3628     bool isClosingHeader = (newHeader == &AS_ELSE
3629                             || newHeader == &AS_CATCH
3630                             || newHeader == &AS_FINALLY);
3631 
3632     // if a closing header, reset break unless break is requested
3633     if (isClosingHeader)
3634     {
3635         if (!shouldBreakClosingHeaderBlocks)
3636             isPrependPostBlockEmptyLineRequested = false;
3637     }
3638     // if an opening header, break before the comment
3639     else
3640     {
3641         isPrependPostBlockEmptyLineRequested = true;
3642     }
3643 }
3644 
3645 /**
3646  * process preprocessor statements.
3647  * charNum should be the index of the preprocessor directive.
3648  *
3649  * delete bracketTypeStack entries added by #if if a #else is found.
3650  * prevents double entries in the bracketTypeStack.
3651  */
3652 void ASFormatter::processPreprocessor()
3653 {
3654     assert(currentChar == '#');
3655 
3656     const int preproc = charNum + 1;
3657 
3658     if (currentLine.compare(preproc, 2, "if") == 0)
3659     {
3660         preprocBracketTypeStackSize = bracketTypeStack->size();
3661     }
3662     else if (currentLine.compare(preproc, 4, "else") == 0)
3663     {
3664         // delete stack entries added in #if
3665         // should be replaced by #else
3666         if (preprocBracketTypeStackSize > 0)
3667         {
3668             int addedPreproc = bracketTypeStack->size() - preprocBracketTypeStackSize;
3669             for (int i=0; i < addedPreproc; i++)
3670                 bracketTypeStack->pop_back();
3671         }
3672     }
3673 }
3674 
3675 /**
3676  * determine if the next line starts a comment
3677  * and a header follows the comment or comments
3678  */
3679 bool ASFormatter::commentAndHeaderFollows() const
3680 {
3681     // is the next line a comment
3682     string nextLine = sourceIterator->peekNextLine();
3683     size_t firstChar = nextLine.find_first_not_of(" \t");
3684     if (firstChar == string::npos
3685             || !(nextLine.compare(firstChar, 2, "//") == 0
3686                  || nextLine.compare(firstChar, 2, "/*") == 0))
3687     {
3688         sourceIterator->peekReset();
3689         return false;
3690     }
3691 
3692     // if next line is a comment, find the next non-comment text
3693     string nextText = peekNextText(nextLine, true);
3694     if (nextText.length() == 0 || !isCharPotentialHeader(nextText, 0))
3695         return false;
3696 
3697     const string* newHeader = ASBeautifier::findHeader(nextText, 0, headers);
3698 
3699     if (newHeader == NULL)
3700         return false;
3701 
3702     bool isClosingHeader = (newHeader == &AS_ELSE
3703                             || newHeader == &AS_CATCH
3704                             || newHeader == &AS_FINALLY);
3705 
3706     if (isClosingHeader && !shouldBreakClosingHeaderBlocks)
3707         return false;
3708 
3709     return true;
3710 }
3711 
3712 /**
3713  * determine if a bracket should be attached or broken
3714  * uses brackets in the bracketTypeStack
3715  * the last bracket in the bracketTypeStack is the one being formatted
3716  * returns true if the bracket should be broken
3717  */
3718 bool ASFormatter::isCurrentBracketBroken() const
3719 {
3720     assert(bracketTypeStack->size() > 0);
3721 
3722     bool breakBracket = false;
3723     size_t bracketTypeStackEnd = bracketTypeStack->size()-1;
3724 
3725     if (isBracketType((*bracketTypeStack)[bracketTypeStackEnd], EXTERN_TYPE))
3726     {
3727         if (currentLineBeginsWithBracket
3728                 || bracketFormatMode == HORSTMANN_MODE)
3729             breakBracket = true;
3730     }
3731     else if (bracketFormatMode == NONE_MODE)
3732     {
3733         if (currentLineBeginsWithBracket
3734                 && (int)currentLineFirstBracketNum == charNum)      // lineBeginsWith('{')
3735             breakBracket = true;
3736     }
3737     else if (bracketFormatMode == BREAK_MODE || bracketFormatMode == HORSTMANN_MODE)
3738     {
3739         breakBracket = true;
3740     }
3741     else if (bracketFormatMode == LINUX_MODE || bracketFormatMode == STROUSTRUP_MODE)
3742     {
3743         // break a class if Linux
3744         if (isBracketType((*bracketTypeStack)[bracketTypeStackEnd], CLASS_TYPE))
3745         {
3746             if (bracketFormatMode == LINUX_MODE)
3747                 breakBracket = true;
3748         }
3749         // break a namespace or interface if Linux
3750         else if (isBracketType((*bracketTypeStack)[bracketTypeStackEnd], NAMESPACE_TYPE)
3751                  || isBracketType((*bracketTypeStack)[bracketTypeStackEnd], INTERFACE_TYPE))
3752         {
3753             if (bracketFormatMode == LINUX_MODE)
3754                 breakBracket = true;
3755         }
3756         // break the first bracket if a function
3757         else if (bracketTypeStackEnd == 1
3758                  && isBracketType((*bracketTypeStack)[bracketTypeStackEnd], COMMAND_TYPE))
3759         {
3760             breakBracket = true;
3761         }
3762         else if (bracketTypeStackEnd > 1)
3763         {
3764             // break the first bracket after a namespace or extern if a function
3765             if (isBracketType((*bracketTypeStack)[bracketTypeStackEnd-1], NAMESPACE_TYPE)
3766                     || isBracketType((*bracketTypeStack)[bracketTypeStackEnd-1], EXTERN_TYPE))
3767             {
3768                 if (isBracketType((*bracketTypeStack)[bracketTypeStackEnd], COMMAND_TYPE))
3769                     breakBracket = true;
3770             }
3771             // if not C style then break the first bracket after a class if a function
3772             else if (!isCStyle())
3773             {
3774                 if ((isBracketType((*bracketTypeStack)[bracketTypeStackEnd-1], CLASS_TYPE)
3775                         || isBracketType((*bracketTypeStack)[bracketTypeStackEnd-1], ARRAY_TYPE)
3776                         || isBracketType((*bracketTypeStack)[bracketTypeStackEnd-1], STRUCT_TYPE))
3777                         && isBracketType((*bracketTypeStack)[bracketTypeStackEnd], COMMAND_TYPE))
3778                     breakBracket = true;
3779             }
3780         }
3781     }
3782     return breakBracket;
3783 }
3784 
3785 /**
3786  * format comment body
3787  * the calling function should have a continue statement after calling this method
3788  */
3789 void ASFormatter::formatCommentBody()
3790 {
3791     assert(isInComment);
3792 
3793     if (isSequenceReached("*/"))
3794     {
3795         isInComment = false;
3796         noTrimCommentContinuation = false;
3797         isImmediatelyPostComment = true;
3798         appendSequence(AS_CLOSE_COMMENT);
3799         goForward(1);
3800         if (doesLineStartComment
3801                 && (currentLine.find_first_not_of(" \t", charNum+1) == string::npos))
3802             lineEndsInCommentOnly = true;
3803         if (peekNextChar() == '}'
3804                 && previousCommandChar != ';'
3805                 && !isBracketType(bracketTypeStack->back(),  ARRAY_TYPE)
3806                 && isOkToBreakBlock(bracketTypeStack->back()))
3807             breakLine();
3808     }
3809     else
3810     {
3811         appendCurrentChar();
3812         // append the comment up to the next tab or comment end
3813         // tabs must be checked for convert-tabs before appending
3814         while (charNum + 1 < (int) currentLine.length()
3815                 && currentLine[charNum+1] != '\t'
3816                 && currentLine.compare(charNum+1, 2, "*/") != 0)
3817         {
3818             currentChar = currentLine[++charNum];
3819             appendCurrentChar();
3820         }
3821     }
3822 }
3823 
3824 /**
3825  * format a comment opener
3826  * the comment opener will be appended to the current formattedLine or a new formattedLine as necessary
3827  * the calling function should have a continue statement after calling this method
3828  */
3829 void ASFormatter::formatCommentOpener()
3830 {
3831     assert(isSequenceReached("/*"));
3832 
3833     isInComment = true;
3834     isImmediatelyPostLineComment = false;
3835 
3836     if (spacePadNum != 0)
3837         adjustComments();
3838     formattedLineCommentNum = formattedLine.length();
3839 
3840     // must be done BEFORE appendSequence
3841     if (previousCommandChar == '{'
3842             && !isImmediatelyPostComment
3843             && !isImmediatelyPostLineComment)
3844     {
3845         if (bracketFormatMode == NONE_MODE)
3846         {
3847             // should a run-in statement be attached?
3848             if (currentLineBeginsWithBracket)
3849                 formatRunIn();
3850         }
3851         else if (bracketFormatMode == ATTACH_MODE)
3852         {
3853             // if the bracket was not attached?
3854             if (formattedLine[0] == '{'
3855                     && !isBracketType(bracketTypeStack->back(), SINGLE_LINE_TYPE))
3856                 isInLineBreak = true;
3857         }
3858         else if (bracketFormatMode == HORSTMANN_MODE)
3859         {
3860             // should a run-in statement be attached?
3861             if (formattedLine[0] == '{')
3862                 formatRunIn();
3863         }
3864     }
3865     else if (!doesLineStartComment)
3866         noTrimCommentContinuation = true;
3867 
3868     // appendSequence will write the previous line
3869     appendSequence(AS_OPEN_COMMENT);
3870     goForward(1);
3871 
3872     // must be done AFTER appendSequence
3873     if (shouldBreakBlocks)
3874     {
3875         // break before the comment if a header follows the comment
3876         // for speed, do not check if previous line is empty,
3877         //     if previous line is a line comment or if previous line is '{'
3878         if (doesLineStartComment
3879                 && !isImmediatelyPostEmptyLine
3880                 && !isImmediatelyPostComment
3881                 && !isImmediatelyPostLineComment
3882                 && previousCommandChar != '{')
3883         {
3884             checkForFollowingHeader(currentLine.substr(charNum-1));
3885         }
3886     }
3887 
3888     if (previousCommandChar == '}')
3889         currentHeader = NULL;
3890 }
3891 
3892 /**
3893  * format a line comment body
3894  * the calling function should have a continue statement after calling this method
3895  */
3896 void ASFormatter::formatLineCommentBody()
3897 {
3898     assert(isInLineComment);
3899 
3900     appendCurrentChar();
3901     // append the comment up to the next tab
3902     // tabs must be checked for convert-tabs before appending
3903     while (charNum + 1 < (int) currentLine.length()
3904             && currentLine[charNum+1] != '\t')
3905     {
3906         currentChar = currentLine[++charNum];
3907         appendCurrentChar();
3908     }
3909 
3910     // explicitely break a line when a line comment's end is found.
3911     if (charNum + 1 == (int) currentLine.length())
3912     {
3913         isInLineBreak = true;
3914         isInLineComment = false;
3915         isImmediatelyPostLineComment = true;
3916         currentChar = 0;  //make sure it is a neutral char.
3917     }
3918 }
3919 
3920 /**
3921  * format a line comment opener
3922  * the line comment opener will be appended to the current formattedLine or a new formattedLine as necessary
3923  * the calling function should have a continue statement after calling this method
3924  */
3925 void ASFormatter::formatLineCommentOpener()
3926 {
3927     assert(isSequenceReached("//"));
3928 
3929     if (currentLine[charNum+2] == '\xf2')       // check for windows line marker
3930         isAppendPostBlockEmptyLineRequested = false;
3931 
3932     isInLineComment = true;
3933     isCharImmediatelyPostComment = false;
3934 
3935     // do not indent if in column 1 or 2
3936     if (!shouldIndentCol1Comments && !lineCommentNoIndent)
3937     {
3938         if (charNum == 0)
3939             lineCommentNoIndent = true;
3940         else if (charNum == 1 && currentLine[0] == ' ')
3941             lineCommentNoIndent = true;
3942     }
3943     // move comment if spaces were added or deleted
3944     if (lineCommentNoIndent == false && spacePadNum != 0)
3945         adjustComments();
3946     formattedLineCommentNum = formattedLine.length();
3947 
3948     // must be done BEFORE appendSequence
3949     // check for run-in statement
3950     if (previousCommandChar == '{'
3951             && !isImmediatelyPostComment
3952             && !isImmediatelyPostLineComment)
3953     {
3954         if (bracketFormatMode == NONE_MODE)
3955         {
3956             if (currentLineBeginsWithBracket)
3957                 formatRunIn();
3958         }
3959         else if (bracketFormatMode == HORSTMANN_MODE)
3960         {
3961             if (!lineCommentNoIndent)
3962                 formatRunIn();
3963             else
3964                 isInLineBreak = true;
3965         }
3966         else if (bracketFormatMode == BREAK_MODE)
3967         {
3968             if (formattedLine[0] == '{')
3969                 isInLineBreak = true;
3970         }
3971         else
3972         {
3973             if (currentLineBeginsWithBracket)
3974                 isInLineBreak = true;
3975         }
3976     }
3977 
3978     // appendSequence will write the previous line
3979     appendSequence(AS_OPEN_LINE_COMMENT);
3980     goForward(1);
3981 
3982     if (formattedLine.compare(0, 2, "//") == 0)
3983         lineIsLineCommentOnly = true;
3984 
3985     // must be done AFTER appendSequence
3986     if (shouldBreakBlocks)
3987     {
3988         // break before the comment if a header follows the line comment
3989         // for speed, do not check if previous line is empty,
3990         //     if previous line is a comment or if previous line is '{'
3991         if (lineIsLineCommentOnly
3992                 && previousCommandChar != '{'
3993                 && !isImmediatelyPostEmptyLine
3994                 && !isImmediatelyPostComment
3995                 && !isImmediatelyPostLineComment)
3996         {
3997             checkForFollowingHeader(currentLine.substr(charNum-1));
3998         }
3999     }
4000 
4001     if (previousCommandChar == '}')
4002         currentHeader = NULL;
4003 
4004     // if tabbed input don't convert the immediately following tabs to spaces
4005     if (getIndentString() == "\t" && lineCommentNoIndent)
4006     {
4007         while (charNum + 1 < (int) currentLine.length()
4008                 && currentLine[charNum+1] == '\t')
4009         {
4010             currentChar = currentLine[++charNum];
4011             appendCurrentChar();
4012         }
4013     }
4014 
4015     // explicitely break a line when a line comment's end is found.
4016     if (charNum + 1 == (int) currentLine.length())
4017     {
4018         isInLineBreak = true;
4019         isInLineComment = false;
4020         isImmediatelyPostLineComment = true;
4021         currentChar = 0;  //make sure it is a neutral char.
4022     }
4023 }
4024 
4025 /**
4026  * format quote body
4027  * the calling function should have a continue statement after calling this method
4028  */
4029 void ASFormatter::formatQuoteBody()
4030 {
4031     assert(isInQuote);
4032 
4033     if (isSpecialChar)
4034     {
4035         isSpecialChar = false;
4036     }
4037     else if (currentChar == '\\' && !isInVerbatimQuote)
4038     {
4039         if (peekNextChar() == ' ')              // is this '\' at end of line
4040             haveLineContinuationChar = true;
4041         else
4042             isSpecialChar = true;
4043     }
4044     else if (isInVerbatimQuote && currentChar == '"')
4045     {
4046         if (peekNextChar() == '"')              // check consecutive quotes
4047         {
4048             appendSequence("\"\"");
4049             goForward(1);
4050             return;
4051         }
4052         else
4053         {
4054             isInQuote = false;
4055             isInVerbatimQuote = false;
4056         }
4057     }
4058     else if (quoteChar == currentChar)
4059     {
4060         isInQuote = false;
4061     }
4062 
4063     appendCurrentChar();
4064 
4065     // append the text to the ending quoteChar or an escape sequence
4066     // tabs in quotes are NOT changed by convert-tabs
4067     if (isInQuote && currentChar != '\\')
4068     {
4069         while (charNum + 1 < (int) currentLine.length()
4070                 && currentLine[charNum+1] != quoteChar
4071                 && currentLine[charNum+1] != '\\')
4072         {
4073             currentChar = currentLine[++charNum];
4074             appendCurrentChar();
4075         }
4076     }
4077 }
4078 
4079 /**
4080  * format a quote opener
4081  * the quote opener will be appended to the current formattedLine or a new formattedLine as necessary
4082  * the calling function should have a continue statement after calling this method
4083  */
4084 void ASFormatter::formatQuoteOpener()
4085 {
4086     assert(currentChar == '"' || currentChar == '\'');
4087 
4088     isInQuote = true;
4089     quoteChar = currentChar;
4090     if (isSharpStyle() && previousChar == '@')
4091         isInVerbatimQuote = true;
4092 
4093     // a quote following a bracket is an array
4094     if (previousCommandChar == '{'
4095             && !isImmediatelyPostComment
4096             && !isImmediatelyPostLineComment
4097             && isNonInStatementArray
4098             && !isBracketType(bracketTypeStack->back(), SINGLE_LINE_TYPE)
4099             && !isWhiteSpace(peekNextChar()))
4100     {
4101         if (bracketFormatMode == NONE_MODE)
4102         {
4103             if (currentLineBeginsWithBracket)
4104                 formatRunIn();
4105         }
4106         else if (bracketFormatMode == HORSTMANN_MODE)
4107         {
4108             if (!lineCommentNoIndent)
4109                 formatRunIn();
4110             else
4111                 isInLineBreak = true;
4112         }
4113         else if (bracketFormatMode == BREAK_MODE)
4114         {
4115             if (formattedLine[0] == '{')
4116                 isInLineBreak = true;
4117         }
4118         else
4119         {
4120             if (currentLineBeginsWithBracket)
4121                 isInLineBreak = true;
4122         }
4123     }
4124     previousCommandChar = ' ';
4125     appendCurrentChar();
4126 }
4127 
4128 /**
4129  * get the next line comment adjustment that results from breaking a closing bracket.
4130  * the bracket must be on the same line as the closing header.
4131  * i.e "} else" changed to "} \n else".
4132  */
4133 int ASFormatter::getNextLineCommentAdjustment()
4134 {
4135     assert(foundClosingHeader && previousNonWSChar == '}');
4136     if (charNum < 1)
4137         return 0;
4138     size_t lastBracket = currentLine.rfind('}', charNum - 1);
4139     if (lastBracket != string::npos)
4140         return (lastBracket - charNum); // return a negative number
4141     return 0;
4142 }
4143 
4144 LineEndFormat ASFormatter::getLineEndFormat() const
4145 {
4146     return lineEnd;
4147 }
4148 
4149 /**
4150  * get the current line comment adjustment that results from attaching
4151  * a closing header to a closing bracket.
4152  * the bracket must be on the line previous to the closing header.
4153  * the adjustment is 2 chars, one for the bracket and one for the space.
4154  * i.e "} \n else" changed to "} else".
4155  */
4156 int ASFormatter::getCurrentLineCommentAdjustment()
4157 {
4158     assert(foundClosingHeader && previousNonWSChar == '}');
4159     if (charNum < 1)
4160         return 2;
4161     size_t lastBracket = currentLine.rfind('}', charNum - 1);
4162     if (lastBracket == string::npos)
4163         return 2;
4164     return 0;
4165 }
4166 
4167 /**
4168  * get the previous word
4169  * the argument 'end' must point to the search start.
4170  *
4171  * @return is the previous word.
4172  */
4173 string ASFormatter::getPreviousWord(const string& line, int currPos) const
4174 {
4175     // get the last legal word (may be a number)
4176     if (currPos == 0)
4177         return string();
4178 
4179     size_t end = line.find_last_not_of(" \t", currPos-1);
4180     if (end == string::npos || !isLegalNameChar(line[end]))
4181         return string();
4182 
4183     int start;          // start of the previous word
4184     for (start = end; start > -1; start--)
4185     {
4186         if (!isLegalNameChar(line[start]) || line[start] == '.')
4187             break;
4188     }
4189     start++;
4190 
4191     return (line.substr(start, end-start+1));
4192 }
4193 
4194 /**
4195  * check if a line break is needed when a closing bracket
4196  * is followed by a closing header.
4197  * the break depends on the bracketFormatMode and other factors.
4198  */
4199 void ASFormatter::isLineBreakBeforeClosingHeader()
4200 {
4201     assert(foundClosingHeader && previousNonWSChar == '}');
4202     if (bracketFormatMode == BREAK_MODE || bracketFormatMode == HORSTMANN_MODE)
4203     {
4204         isInLineBreak = true;
4205     }
4206     else if (bracketFormatMode == NONE_MODE)
4207     {
4208         if (shouldBreakClosingHeaderBrackets
4209                 || getBracketIndent() || getBlockIndent())
4210         {
4211             isInLineBreak = true;
4212         }
4213         else
4214         {
4215             appendSpacePad();
4216             // is closing bracket broken?
4217             size_t i = currentLine.find_first_not_of(" \t");
4218             if (i != string::npos && currentLine[i] == '}')
4219                 isInLineBreak = false;
4220 
4221             if (shouldBreakBlocks)
4222                 isAppendPostBlockEmptyLineRequested = false;
4223         }
4224     }
4225     // bracketFormatMode == ATTACH_MODE, LINUX_MODE, STROUSTRUP_MODE
4226     else
4227     {
4228         if (shouldBreakClosingHeaderBrackets
4229                 || getBracketIndent() || getBlockIndent())
4230         {
4231             isInLineBreak = true;
4232         }
4233         else
4234         {
4235             // if a blank line does not preceed this
4236             // or last line is not a one line block, attach header
4237             bool previousLineIsEmpty = isEmptyLine(formattedLine);
4238             bool previousLineIsOneLineBlock = false;
4239             size_t firstBracket = findNextChar(formattedLine, '{');
4240             if (firstBracket != string::npos)
4241                 previousLineIsOneLineBlock = isOneLineBlockReached(formattedLine, firstBracket);
4242             if (!previousLineIsEmpty
4243                     && !previousLineIsOneLineBlock)
4244             {
4245                 isInLineBreak = false;
4246                 appendSpacePad();
4247                 spacePadNum = 0;    // don't count as comment padding
4248             }
4249 
4250             if (shouldBreakBlocks)
4251                 isAppendPostBlockEmptyLineRequested = false;
4252         }
4253     }
4254 }
4255 
4256 /**
4257  * Add brackets to a single line statement following a header.
4258  * Brackets are not added if the proper conditions are not met.
4259  * Brackets are added to the currentLine.
4260  */
4261 bool ASFormatter::addBracketsToStatement()
4262 {
4263     assert(isImmediatelyPostHeader);
4264 
4265     if (currentHeader != &AS_IF
4266             && currentHeader != &AS_ELSE
4267             && currentHeader != &AS_FOR
4268             && currentHeader != &AS_WHILE
4269             && currentHeader != &AS_DO
4270             && currentHeader != &AS_FOREACH)
4271         return false;
4272 
4273     // do not add if a header follows (i.e. else if)
4274     if (isCharPotentialHeader(currentLine, charNum))
4275         if (findHeader(headers) != NULL)
4276             return false;
4277 
4278     // find the next semi-colon
4279     size_t nextSemiColon = findNextChar(currentLine, ';', charNum+1);
4280     if (nextSemiColon == string::npos)
4281         return false;
4282 
4283     // add closing bracket before changing the line length
4284     if (nextSemiColon == currentLine.length() - 1)
4285         currentLine.append(" }");
4286     else
4287         currentLine.insert(nextSemiColon + 1, " }");
4288     // add opening bracket
4289     currentLine.insert(charNum, "{ ");
4290     currentChar = '{';
4291     // remove extra spaces
4292     if (!shouldAddOneLineBrackets)
4293     {
4294         size_t lastText = formattedLine.find_last_not_of(" \t");
4295         if ((formattedLine.length() - 1) - lastText > 1)
4296             formattedLine.erase(lastText + 1);
4297     }
4298     return true;
4299 }
4300 
4301 /**
4302  * Find the next character that is not in quotes or a comment.
4303  *
4304  * @param line         the line to be searched.
4305  * @param searchChar   the char to find.
4306  * @param searchStart  the char to find.
4307  * @return the position on the line or string::npos if not found.
4308  */
4309 size_t ASFormatter::findNextChar(string& line, char searchChar, int searchStart /*0*/)
4310 {
4311     // find the next searchChar
4312     size_t i;
4313     for (i = searchStart; i < line.length(); i++)
4314     {
4315         if (line.compare(i, 2, "//") == 0)
4316             return string::npos;
4317         if (line.compare(i, 2, "/*") == 0)
4318         {
4319             size_t endComment = line.find("*/", i+2);
4320             if (endComment == string::npos)
4321                 return string::npos;
4322             i = endComment + 2;
4323         }
4324         if (line[i] == '\'' || line[i] == '\"')
4325         {
4326             char quote = line[i];
4327             while (i < line.length())
4328             {
4329                 size_t endQuote = line.find(quote, i+1);
4330                 if (endQuote == string::npos)
4331                     return string::npos;
4332                 i = endQuote;
4333                 if (line[endQuote-1] != '\\')   // check for '\"'
4334                     break;
4335                 if (line[endQuote-2] == '\\')   // check for '\\'
4336                     break;
4337             }
4338         }
4339 
4340         if (line[i] == searchChar)
4341             break;
4342 
4343         // for now don't process C# 'delegate' brackets
4344         // do this last in case the search char is a '{'
4345         if (line[i] == '{')
4346             return string::npos;
4347     }
4348     if (i >= line.length()) // didn't find searchChar
4349         return string::npos;
4350 
4351     return i;
4352 }
4353 
4354 /**
4355  * Look ahead in the file to see if a struct has access modifiers.
4356  *
4357  * @param line          a reference to the line to indent.
4358  * @param index         the current line index.
4359  * @return              true if the struct has access modifiers.
4360  */
4361 bool ASFormatter::isStructAccessModified(string  &firstLine, size_t index) const
4362 {
4363     assert(firstLine[index] == '{');
4364     assert(isCStyle());
4365 
4366     bool isFirstLine = true;
4367     bool needReset = false;
4368     size_t bracketCount = 1;
4369     string nextLine = firstLine.substr(index + 1);
4370 
4371     // find the first non-blank text, bypassing all comments.
4372     bool isInComment = false;
4373     while (sourceIterator->hasMoreLines())
4374     {
4375         if (isFirstLine)
4376             isFirstLine = false;
4377         else
4378         {
4379             nextLine = sourceIterator->peekNextLine();
4380             needReset = true;
4381         }
4382         // parse the line
4383         for (size_t i = 0; i < nextLine.length(); i++)
4384         {
4385             if (isWhiteSpace(nextLine[i]))
4386                 continue;
4387             if (nextLine.compare(i, 2, "/*") == 0)
4388                 isInComment = true;
4389             if (isInComment)
4390             {
4391                 i = nextLine.find("*/", i);
4392                 if (i == string::npos)
4393                 {
4394                     i = nextLine.length();
4395                     continue;
4396                 }
4397                 i++;
4398                 isInComment = false;
4399                 continue;
4400             }
4401             if (nextLine.compare(i, 2, "//") == 0)
4402             {
4403                 i = nextLine.length();
4404                 continue;
4405             }
4406             // handle brackets
4407             if (nextLine[i] == '{')
4408                 bracketCount++;
4409             if (nextLine[i] == '}')
4410                 bracketCount--;
4411             if (bracketCount == 0)
4412             {
4413                 if (needReset)
4414                     sourceIterator->peekReset();
4415                 return false;
4416             }
4417             // check for access modifiers
4418             if (isCharPotentialHeader(nextLine, i))
4419             {
4420                 if (findKeyword(nextLine, i, AS_PUBLIC)
4421                         || findKeyword(nextLine, i, AS_PRIVATE)
4422                         || findKeyword(nextLine, i, AS_PROTECTED))
4423                 {
4424                     if (needReset)
4425                         sourceIterator->peekReset();
4426                     return true;
4427                 }
4428                 string name = getCurrentWord(nextLine, i);
4429                 i += name.length() - 1;
4430             }
4431         }   // end of for loop
4432     }   // end of while loop
4433 
4434     if (needReset)
4435         sourceIterator->peekReset();
4436     return false;
4437 }
4438 
4439 /**
4440  * Check to see if this is an EXEC SQL statement.
4441  *
4442  * @param line          a reference to the line to indent.
4443  * @param index         the current line index.
4444  * @return              true if the statement is EXEC SQL.
4445  */
4446 bool ASFormatter::isExecSQL(string  &line, size_t index) const
4447 {
4448     if (line[index] != 'e' && line[index] != 'E')   // quick check to reject most
4449         return false;
4450     string word;
4451     if (isCharPotentialHeader(line, index))
4452         word = getCurrentWord(line, index);
4453     for (size_t i = 0; i < word.length(); i++)
4454         word[i] = (char) toupper(word[i]);
4455     if (word != "EXEC")
4456         return false;
4457     size_t index2 = index + word.length();
4458     index2 = line.find_first_not_of(" \t", index2);
4459     if (index2 == string::npos)
4460         return false;
4461     word.erase();
4462     if (isCharPotentialHeader(line, index2))
4463         word = getCurrentWord(line, index2);
4464     for (size_t i = 0; i < word.length(); i++)
4465         word[i] = (char) toupper(word[i]);
4466     if (word != "SQL")
4467         return false;
4468     return true;
4469 }
4470 
4471 /**
4472  * The continuation lines must be adjusted so the leading spaces
4473  *     is equivalent to the text on the opening line.
4474  *
4475  * Updates currentLine and charNum.
4476  */
4477 void ASFormatter::trimContinuationLine()
4478 {
4479     size_t len = currentLine.length();
4480     size_t indent = getIndentLength();
4481     charNum = 0;
4482 
4483     if (leadingSpaces > 0 && len > 0)
4484     {
4485         size_t i;
4486         size_t continuationIncrementIn = 0;
4487         for (i = 0; (i < len) && (i + continuationIncrementIn < leadingSpaces); i++)
4488         {
4489             if (!isWhiteSpace(currentLine[i]))      // don't delete any text
4490             {
4491                 i = 0;
4492                 continuationIncrementIn = tabIncrementIn;
4493                 break;
4494             }
4495             if (currentLine[i] == '\t')
4496                 continuationIncrementIn += indent - 1 - ((continuationIncrementIn + i) % indent);
4497         }
4498 
4499         if ((int) continuationIncrementIn == tabIncrementIn)
4500             charNum = i;
4501         else
4502         {
4503             // build a new line with the equivalent leading chars
4504             string newLine;
4505             int leadingChars = 0;
4506             if ((int) leadingSpaces > tabIncrementIn)
4507                 leadingChars = leadingSpaces - tabIncrementIn;
4508             newLine.append(leadingChars, ' ');
4509             newLine.append(currentLine, i, len-i);
4510             currentLine = newLine;
4511             charNum = leadingChars;
4512         }
4513         if (i >= len)
4514             charNum = 0;
4515     }
4516     return;
4517 }
4518 
4519 
4520 }   // end namespace astyle