File indexing completed on 2024-04-14 04:31:30
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