File indexing completed on 2024-04-28 15:54:18
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 <iostream> 0031 0032 0033 namespace astyle 0034 { 0035 // static member variables 0036 int ASBeautifier::beautifierFileType = 9; // initialized with an invalid type 0037 vector<const string*>* ASBeautifier::headers = NULL; 0038 vector<const string*>* ASBeautifier::nonParenHeaders = NULL; 0039 vector<const string*>* ASBeautifier::preBlockStatements; 0040 vector<const string*>* ASBeautifier::assignmentOperators = NULL; 0041 vector<const string*>* ASBeautifier::nonAssignmentOperators; 0042 vector<const string*>* ASBeautifier::indentableHeaders; 0043 0044 0045 /** 0046 * ASBeautifier's constructor 0047 */ 0048 ASBeautifier::ASBeautifier() 0049 { 0050 waitingBeautifierStack = NULL; 0051 activeBeautifierStack = NULL; 0052 waitingBeautifierStackLengthStack = NULL; 0053 activeBeautifierStackLengthStack = NULL; 0054 0055 headerStack = NULL; 0056 tempStacks = NULL; 0057 blockParenDepthStack = NULL; 0058 blockStatementStack = NULL; 0059 parenStatementStack = NULL; 0060 bracketBlockStateStack = NULL; 0061 inStatementIndentStack = NULL; 0062 inStatementIndentStackSizeStack = NULL; 0063 parenIndentStack = NULL; 0064 sourceIterator = NULL; 0065 isIndentManuallySet = false; 0066 isMinConditionalManuallySet = false; 0067 isModeManuallySet = false; 0068 shouldForceTabIndentation = false; 0069 setSpaceIndentation(4); // also sets minConditionalIndent 0070 setMaxInStatementIndentLength(40); 0071 classInitializerTabs = 1; 0072 setClassIndent(false); 0073 setSwitchIndent(false); 0074 setCaseIndent(false); 0075 setBlockIndent(false); 0076 setBracketIndent(false); 0077 setNamespaceIndent(false); 0078 setLabelIndent(false); 0079 setEmptyLineFill(false); 0080 setCStyle(); 0081 setPreprocessorIndent(false); 0082 0083 // initialize ASBeautifier static member vectors 0084 beautifierFileType = 9; // reset to an invalid type 0085 initVector(headers); 0086 initVector(nonParenHeaders); 0087 initVector(assignmentOperators); 0088 initVector(nonAssignmentOperators); 0089 initVector(preBlockStatements); 0090 initVector(indentableHeaders); 0091 } 0092 0093 /** 0094 * ASBeautifier's copy constructor 0095 * must explicitly call the base class copy constructor 0096 */ 0097 ASBeautifier::ASBeautifier(const ASBeautifier &other) : ASBase(other) 0098 { 0099 // these don't need to copy the stack 0100 waitingBeautifierStack = NULL; 0101 activeBeautifierStack = NULL; 0102 waitingBeautifierStackLengthStack = NULL; 0103 activeBeautifierStackLengthStack = NULL; 0104 0105 // vector '=' operator performs a DEEP copy of all elements in the vector 0106 0107 headerStack = new vector<const string*>; 0108 *headerStack = *other.headerStack; 0109 0110 //tempStacks = new vector<vector<const string*>*>; 0111 //vector<vector<const string*>*>::iterator iter; 0112 //for (iter = other.tempStacks->begin(); 0113 // iter != other.tempStacks->end(); 0114 // ++iter) 0115 //{ 0116 // vector<const string*> *newVec = new vector<const string*>; 0117 // *newVec = **iter; 0118 // tempStacks->push_back(newVec); 0119 //} 0120 tempStacks = copyTempStacks(other); 0121 0122 blockParenDepthStack = new vector<int>; 0123 *blockParenDepthStack = *other.blockParenDepthStack; 0124 0125 blockStatementStack = new vector<bool>; 0126 *blockStatementStack = *other.blockStatementStack; 0127 0128 parenStatementStack = new vector<bool>; 0129 *parenStatementStack = *other.parenStatementStack; 0130 0131 bracketBlockStateStack = new vector<bool>; 0132 *bracketBlockStateStack = *other.bracketBlockStateStack; 0133 0134 inStatementIndentStack = new vector<int>; 0135 *inStatementIndentStack = *other.inStatementIndentStack; 0136 0137 inStatementIndentStackSizeStack = new vector<int>; 0138 *inStatementIndentStackSizeStack = *other.inStatementIndentStackSizeStack; 0139 0140 parenIndentStack = new vector<int>; 0141 *parenIndentStack = *other.parenIndentStack; 0142 0143 sourceIterator = other.sourceIterator; 0144 0145 // protected variables 0146 // variables set by ASFormatter 0147 // must also be updated in activeBeautifierStack 0148 inLineNumber = other.inLineNumber; 0149 horstmannIndentInStatement = other.horstmannIndentInStatement; 0150 nonInStatementBracket = other.nonInStatementBracket; 0151 lineCommentNoBeautify = other.lineCommentNoBeautify; 0152 isNonInStatementArray = other.isNonInStatementArray; 0153 isSharpAccessor = other.isSharpAccessor; 0154 isSharpDelegate = other.isSharpDelegate; 0155 isInExtern = other.isInExtern; 0156 isInBeautifySQL = other.isInBeautifySQL; 0157 isInIndentableStruct = other.isInIndentableStruct; 0158 0159 // private variables 0160 indentString = other.indentString; 0161 currentHeader = other.currentHeader; 0162 previousLastLineHeader = other.previousLastLineHeader; 0163 probationHeader = other.probationHeader; 0164 isInQuote = other.isInQuote; 0165 isInVerbatimQuote = other.isInVerbatimQuote; 0166 haveLineContinuationChar = other.haveLineContinuationChar; 0167 isInAsm = other.isInAsm; 0168 isInAsmOneLine = other.isInAsmOneLine; 0169 isInAsmBlock = other.isInAsmBlock; 0170 isInComment = other.isInComment; 0171 isInHorstmannComment = other.isInHorstmannComment; 0172 isInCase = other.isInCase; 0173 isInQuestion = other.isInQuestion; 0174 isInStatement = other.isInStatement; 0175 isInHeader = other.isInHeader; 0176 isInTemplate = other.isInTemplate; 0177 isInDefine = other.isInDefine; 0178 isInDefineDefinition = other.isInDefineDefinition; 0179 classIndent = other.classIndent; 0180 isInClassInitializer = other.isInClassInitializer; 0181 isInClassHeaderTab = other.isInClassHeaderTab; 0182 isInEnum = other.isInEnum; 0183 switchIndent = other.switchIndent; 0184 caseIndent = other.caseIndent; 0185 namespaceIndent = other.namespaceIndent; 0186 bracketIndent = other.bracketIndent; 0187 blockIndent = other.blockIndent; 0188 labelIndent = other.labelIndent; 0189 preprocessorIndent = other.preprocessorIndent; 0190 isInConditional = other.isInConditional; 0191 isIndentManuallySet = other.isIndentManuallySet; 0192 isMinConditionalManuallySet = other.isMinConditionalManuallySet; 0193 isModeManuallySet = other.isModeManuallySet; 0194 shouldForceTabIndentation = other.shouldForceTabIndentation; 0195 emptyLineFill = other.emptyLineFill; 0196 lineOpensComment = other.lineOpensComment; 0197 backslashEndsPrevLine = other.backslashEndsPrevLine; 0198 blockCommentNoIndent = other.blockCommentNoIndent; 0199 blockCommentNoBeautify = other.blockCommentNoBeautify; 0200 previousLineProbationTab = other.previousLineProbationTab; 0201 fileType = other.fileType; 0202 minConditionalIndent = other.minConditionalIndent; 0203 parenDepth = other.parenDepth; 0204 indentLength = other.indentLength; 0205 blockTabCount = other.blockTabCount; 0206 maxInStatementIndent = other.maxInStatementIndent; 0207 classInitializerTabs = other.classInitializerTabs; 0208 templateDepth = other.templateDepth; 0209 prevFinalLineSpaceTabCount = other.prevFinalLineSpaceTabCount; 0210 prevFinalLineTabCount = other.prevFinalLineTabCount; 0211 defineTabCount = other.defineTabCount; 0212 quoteChar = other.quoteChar; 0213 prevNonSpaceCh = other.prevNonSpaceCh; 0214 currentNonSpaceCh = other.currentNonSpaceCh; 0215 currentNonLegalCh = other.currentNonLegalCh; 0216 prevNonLegalCh = other.prevNonLegalCh; 0217 } 0218 0219 /** 0220 * ASBeautifier's destructor 0221 */ 0222 ASBeautifier::~ASBeautifier() 0223 { 0224 deleteContainer(waitingBeautifierStack); 0225 deleteContainer(activeBeautifierStack); 0226 deleteContainer(waitingBeautifierStackLengthStack); 0227 deleteContainer(activeBeautifierStackLengthStack); 0228 deleteContainer(headerStack); 0229 deleteContainer(tempStacks); 0230 deleteContainer(blockParenDepthStack); 0231 deleteContainer(blockStatementStack); 0232 deleteContainer(parenStatementStack); 0233 deleteContainer(bracketBlockStateStack); 0234 deleteContainer(inStatementIndentStack); 0235 deleteContainer(inStatementIndentStackSizeStack); 0236 deleteContainer(parenIndentStack); 0237 } 0238 0239 /** 0240 * initialize the ASBeautifier. 0241 * 0242 * init() should be called every time a ABeautifier object is to start 0243 * beautifying a NEW source file. 0244 * init() recieves a pointer to a ASSourceIterator object that will be 0245 * used to iterate through the source code. 0246 * 0247 * @param iter a pointer to the ASSourceIterator or ASStreamIterator object. 0248 */ 0249 void ASBeautifier::init(ASSourceIterator *iter) 0250 { 0251 sourceIterator = iter; 0252 init(); 0253 } 0254 0255 /** 0256 * initialize the ASBeautifier. 0257 */ 0258 void ASBeautifier::init() 0259 { 0260 initStatic(); 0261 ASBase::init(getFileType()); 0262 0263 initContainer(waitingBeautifierStack, new vector<ASBeautifier*>); 0264 initContainer(activeBeautifierStack, new vector<ASBeautifier*>); 0265 0266 initContainer(waitingBeautifierStackLengthStack, new vector<int>); 0267 initContainer(activeBeautifierStackLengthStack, new vector<int>); 0268 0269 initContainer(headerStack, new vector<const string*>); 0270 0271 initContainer(tempStacks, new vector<vector<const string*>*>); 0272 tempStacks->push_back(new vector<const string*>); 0273 0274 initContainer(blockParenDepthStack, new vector<int>); 0275 initContainer(blockStatementStack, new vector<bool>); 0276 initContainer(parenStatementStack, new vector<bool>); 0277 0278 initContainer(bracketBlockStateStack, new vector<bool>); 0279 bracketBlockStateStack->push_back(true); 0280 0281 initContainer(inStatementIndentStack, new vector<int>); 0282 initContainer(inStatementIndentStackSizeStack, new vector<int>); 0283 inStatementIndentStackSizeStack->push_back(0); 0284 initContainer(parenIndentStack, new vector<int>); 0285 0286 previousLastLineHeader = NULL; 0287 currentHeader = NULL; 0288 0289 isInQuote = false; 0290 isInVerbatimQuote = false; 0291 haveLineContinuationChar = false; 0292 isInAsm = false; 0293 isInAsmOneLine = false; 0294 isInAsmBlock = false; 0295 isInComment = false; 0296 isInHorstmannComment = false; 0297 isInStatement = false; 0298 isInCase = false; 0299 isInQuestion = false; 0300 isInClassInitializer = false; 0301 isInClassHeaderTab = false; 0302 isInEnum = false; 0303 isInHeader = false; 0304 isInTemplate = false; 0305 isInConditional = false; 0306 0307 templateDepth = 0; 0308 parenDepth = 0; 0309 blockTabCount = 0; 0310 prevNonSpaceCh = '{'; 0311 currentNonSpaceCh = '{'; 0312 prevNonLegalCh = '{'; 0313 currentNonLegalCh = '{'; 0314 quoteChar = ' '; 0315 prevFinalLineSpaceTabCount = 0; 0316 prevFinalLineTabCount = 0; 0317 probationHeader = NULL; 0318 backslashEndsPrevLine = false; 0319 lineOpensComment = false; 0320 isInDefine = false; 0321 isInDefineDefinition = false; 0322 defineTabCount = 0; 0323 lineCommentNoBeautify = false; 0324 blockCommentNoIndent = false; 0325 blockCommentNoBeautify = false; 0326 previousLineProbationTab = false; 0327 isNonInStatementArray = false; 0328 isSharpAccessor = false; 0329 isSharpDelegate = false; 0330 isInExtern = false; 0331 isInBeautifySQL = false; 0332 isInIndentableStruct = false; 0333 inLineNumber = 0; 0334 horstmannIndentInStatement = 0; 0335 nonInStatementBracket = 0; 0336 } 0337 0338 /* 0339 * initialize the static vars 0340 */ 0341 void ASBeautifier::initStatic() 0342 { 0343 if (fileType == beautifierFileType) // don't build unless necessary 0344 return; 0345 0346 beautifierFileType = fileType; 0347 0348 headers->clear(); 0349 nonParenHeaders->clear(); 0350 assignmentOperators->clear(); 0351 nonAssignmentOperators->clear(); 0352 preBlockStatements->clear(); 0353 indentableHeaders->clear(); 0354 0355 ASResource::buildHeaders(headers, fileType, true); 0356 ASResource::buildNonParenHeaders(nonParenHeaders, fileType, true); 0357 ASResource::buildAssignmentOperators(assignmentOperators); 0358 ASResource::buildNonAssignmentOperators(nonAssignmentOperators); 0359 ASResource::buildPreBlockStatements(preBlockStatements, fileType); 0360 ASResource::buildIndentableHeaders(indentableHeaders); 0361 } 0362 0363 /** 0364 * set indentation style to C/C++. 0365 */ 0366 void ASBeautifier::setCStyle() 0367 { 0368 fileType = C_TYPE; 0369 } 0370 0371 /** 0372 * set indentation style to Java. 0373 */ 0374 void ASBeautifier::setJavaStyle() 0375 { 0376 fileType = JAVA_TYPE; 0377 } 0378 0379 /** 0380 * set indentation style to C#. 0381 */ 0382 void ASBeautifier::setSharpStyle() 0383 { 0384 fileType = SHARP_TYPE; 0385 } 0386 0387 /** 0388 * set mode manually set flag 0389 */ 0390 void ASBeautifier::setModeManuallySet(bool state) 0391 { 0392 isModeManuallySet = state; 0393 } 0394 0395 /** 0396 * indent using one tab per indentation 0397 */ 0398 void ASBeautifier::setTabIndentation(int length, bool forceTabs) 0399 { 0400 indentString = "\t"; 0401 indentLength = length; 0402 shouldForceTabIndentation = forceTabs; 0403 0404 if (!isMinConditionalManuallySet) 0405 minConditionalIndent = indentLength * 2; 0406 } 0407 0408 /** 0409 * indent using a number of spaces per indentation. 0410 * 0411 * @param length number of spaces per indent. 0412 */ 0413 void ASBeautifier::setSpaceIndentation(int length) 0414 { 0415 indentString = string(length, ' '); 0416 indentLength = length; 0417 0418 if (!isMinConditionalManuallySet) 0419 minConditionalIndent = indentLength * 2; 0420 } 0421 0422 /** 0423 * set indent manually set flag 0424 */ 0425 void ASBeautifier::setIndentManuallySet(bool state) 0426 { 0427 isIndentManuallySet = state; 0428 } 0429 0430 /** 0431 * set the maximum indentation between two lines in a multi-line statement. 0432 * 0433 * @param max maximum indentation length. 0434 */ 0435 void ASBeautifier::setMaxInStatementIndentLength(int max) 0436 { 0437 maxInStatementIndent = max; 0438 } 0439 0440 /** 0441 * set the minimum indentation between two lines in a multi-line condition. 0442 * 0443 * @param min minimal indentation length. 0444 */ 0445 void ASBeautifier::setMinConditionalIndentLength(int min) 0446 { 0447 minConditionalIndent = min; 0448 } 0449 0450 /** 0451 * set min conditional manually set flag 0452 */ 0453 void ASBeautifier::setMinConditionalManuallySet(bool state) 0454 { 0455 isMinConditionalManuallySet = state; 0456 } 0457 0458 /** 0459 * set the state of the bracket indentation option. If true, brackets will 0460 * be indented one additional indent. 0461 * 0462 * @param state state of option. 0463 */ 0464 void ASBeautifier::setBracketIndent(bool state) 0465 { 0466 bracketIndent = state; 0467 } 0468 0469 /** 0470 * set the state of the block indentation option. If true, entire blocks 0471 * will be indented one additional indent, similar to the GNU indent style. 0472 * 0473 * @param state state of option. 0474 */ 0475 void ASBeautifier::setBlockIndent(bool state) 0476 { 0477 blockIndent = state; 0478 } 0479 0480 /** 0481 * set the state of the class indentation option. If true, C++ class 0482 * definitions will be indented one additional indent. 0483 * 0484 * @param state state of option. 0485 */ 0486 void ASBeautifier::setClassIndent(bool state) 0487 { 0488 classIndent = state; 0489 } 0490 0491 /** 0492 * set the state of the switch indentation option. If true, blocks of 'switch' 0493 * statements will be indented one additional indent. 0494 * 0495 * @param state state of option. 0496 */ 0497 void ASBeautifier::setSwitchIndent(bool state) 0498 { 0499 switchIndent = state; 0500 } 0501 0502 /** 0503 * set the state of the case indentation option. If true, lines of 'case' 0504 * statements will be indented one additional indent. 0505 * 0506 * @param state state of option. 0507 */ 0508 void ASBeautifier::setCaseIndent(bool state) 0509 { 0510 caseIndent = state; 0511 } 0512 0513 /** 0514 * set the state of the namespace indentation option. 0515 * If true, blocks of 'namespace' statements will be indented one 0516 * additional indent. Otherwise, NO indentation will be added. 0517 * 0518 * @param state state of option. 0519 */ 0520 void ASBeautifier::setNamespaceIndent(bool state) 0521 { 0522 namespaceIndent = state; 0523 } 0524 0525 /** 0526 * set the state of the label indentation option. 0527 * If true, labels will be indented one indent LESS than the 0528 * current indentation level. 0529 * If false, labels will be flushed to the left with NO 0530 * indent at all. 0531 * 0532 * @param state state of option. 0533 */ 0534 void ASBeautifier::setLabelIndent(bool state) 0535 { 0536 labelIndent = state; 0537 } 0538 0539 /** 0540 * set the state of the preprocessor indentation option. 0541 * If true, multiline #define statements will be indented. 0542 * 0543 * @param state state of option. 0544 */ 0545 void ASBeautifier::setPreprocessorIndent(bool state) 0546 { 0547 preprocessorIndent = state; 0548 } 0549 0550 /** 0551 * set the state of the empty line fill option. 0552 * If true, empty lines will be filled with the whitespace. 0553 * of their previous lines. 0554 * If false, these lines will remain empty. 0555 * 0556 * @param state state of option. 0557 */ 0558 void ASBeautifier::setEmptyLineFill(bool state) 0559 { 0560 emptyLineFill = state; 0561 } 0562 0563 /** 0564 * get the file type. 0565 */ 0566 int ASBeautifier::getFileType() 0567 { 0568 return fileType; 0569 } 0570 0571 /** 0572 * get the number of spaces per indent 0573 * 0574 * @return value of indentLength option. 0575 */ 0576 int ASBeautifier::getIndentLength(void) 0577 { 0578 return indentLength; 0579 } 0580 0581 /** 0582 * get the char used for indentation, space or tab 0583 * 0584 * @return the char used for indentation. 0585 */ 0586 string ASBeautifier::getIndentString(void) 0587 { 0588 return indentString; 0589 } 0590 0591 /** 0592 * get indent manually set flag 0593 */ 0594 bool ASBeautifier::getIndentManuallySet() 0595 { 0596 return isIndentManuallySet; 0597 } 0598 0599 /** 0600 * get the state of the isMinConditionalManuallySet flag 0601 * 0602 * @return the state of isMinConditionalManuallySet. 0603 */ 0604 bool ASBeautifier::getMinConditionalManuallySet() 0605 { 0606 return isMinConditionalManuallySet; 0607 } 0608 0609 /** 0610 * get mode manually set flag 0611 */ 0612 bool ASBeautifier::getModeManuallySet() 0613 { 0614 return isModeManuallySet; 0615 } 0616 0617 /** 0618 * get the state of the force tab indentation option. 0619 * 0620 * @return state of force tab indentation. 0621 */ 0622 bool ASBeautifier::getForceTabIndentation(void) 0623 { 0624 return shouldForceTabIndentation; 0625 } 0626 0627 /** 0628 * get the state of the block indentation option. 0629 * 0630 * @return state of blockIndent option. 0631 */ 0632 bool ASBeautifier::getBlockIndent(void) 0633 { 0634 return blockIndent; 0635 } 0636 0637 /** 0638 * get the state of the bracket indentation option. 0639 * 0640 * @return state of bracketIndent option. 0641 */ 0642 bool ASBeautifier::getBracketIndent(void) 0643 { 0644 return bracketIndent; 0645 } 0646 0647 /** 0648 * get the state of the class indentation option. If true, blocks of 0649 * the 'class' statement will be indented one additional indent. 0650 * 0651 * @return state of classIndent option. 0652 */ 0653 bool ASBeautifier::getClassIndent(void) 0654 { 0655 return classIndent; 0656 } 0657 0658 /** 0659 * get the state of the switch indentation option. If true, blocks of 0660 * the 'switch' statement will be indented one additional indent. 0661 * 0662 * @return state of switchIndent option. 0663 */ 0664 bool ASBeautifier::getSwitchIndent(void) 0665 { 0666 return switchIndent; 0667 } 0668 0669 /** 0670 * get the state of the case indentation option. If true, lines of 'case' 0671 * statements will be indented one additional indent. 0672 * 0673 * @return state of caseIndent option. 0674 */ 0675 bool ASBeautifier::getCaseIndent(void) 0676 { 0677 return caseIndent; 0678 } 0679 0680 /** 0681 * get the state of the empty line fill option. 0682 * If true, empty lines will be filled with the whitespace. 0683 * of their previous lines. 0684 * If false, these lines will remain empty. 0685 * 0686 * @return state of emptyLineFill option. 0687 */ 0688 bool ASBeautifier::getEmptyLineFill(void) 0689 { 0690 return emptyLineFill; 0691 } 0692 0693 /** 0694 * check if there are any indented lines ready to be read by nextLine() 0695 * 0696 * @return are there any indented lines ready? 0697 */ 0698 bool ASBeautifier::hasMoreLines() const 0699 { 0700 return sourceIterator->hasMoreLines(); 0701 } 0702 0703 /** 0704 * get the next indented line. 0705 * 0706 * @return indented line. 0707 */ 0708 string ASBeautifier::nextLine() 0709 { 0710 return beautify(sourceIterator->nextLine()); 0711 } 0712 0713 /** 0714 * beautify a line of source code. 0715 * every line of source code in a source code file should be sent 0716 * one after the other to the beautify method. 0717 * 0718 * @return the indented line. 0719 * @param originalLine the original unindented line. 0720 */ 0721 string ASBeautifier::beautify(const string &originalLine) 0722 { 0723 string line; 0724 bool isInLineComment = false; 0725 bool lineStartsInComment = false; 0726 bool isInClass = false; 0727 bool isInSwitch = false; 0728 bool isInOperator = false; 0729 bool isSpecialChar = false; 0730 bool haveCaseIndent = false; 0731 bool haveAssignmentThisLine = false; 0732 bool lineBeginsWithBracket = false; 0733 bool closingBracketReached = false; 0734 bool shouldIndentBrackettedLine = true; 0735 bool previousLineProbation = (probationHeader != NULL); 0736 bool isInQuoteContinuation = isInVerbatimQuote | haveLineContinuationChar; 0737 char ch = ' '; 0738 char prevCh; 0739 char tempCh; 0740 int tabCount = 0; 0741 int spaceTabCount = 0; 0742 int lineOpeningBlocksNum = 0; 0743 int lineClosingBlocksNum = 0; 0744 int tabIncrementIn = 0; 0745 int i; 0746 int iPrelim; 0747 string outBuffer; // the newly idented line is buffered here 0748 const string *lastLineHeader = NULL; 0749 0750 currentHeader = NULL; 0751 lineStartsInComment = isInComment; 0752 blockCommentNoBeautify = blockCommentNoIndent; 0753 isInAsmOneLine = false; 0754 lineOpensComment = false; 0755 previousLineProbationTab = false; 0756 haveLineContinuationChar = false; 0757 0758 // handle and remove white spaces around the line: 0759 // If not in comment, first find out size of white space before line, 0760 // so that possible comments starting in the line continue in 0761 // relation to the preliminary white-space. 0762 if (isInQuoteContinuation) 0763 { 0764 // trim a single space added by ASFormatter, otherwise leave it alone 0765 if (!(originalLine.length() == 1 && originalLine[0] == ' ')) 0766 line = originalLine; 0767 } 0768 else if (isInComment || isInBeautifySQL) 0769 { 0770 // trim the end of comment and SQL lines 0771 line = originalLine; 0772 size_t trimEnd = line.find_last_not_of(" \t"); 0773 if (trimEnd == string::npos) 0774 trimEnd = 0; 0775 else 0776 trimEnd++; 0777 if (trimEnd < line.length()) 0778 line.erase(trimEnd); 0779 } 0780 else 0781 { 0782 line = trim(originalLine); 0783 if (line.length() > 0 && line[0] == '{') 0784 lineBeginsWithBracket = true; 0785 0786 isInHorstmannComment = false; 0787 size_t j = line.find_first_not_of(" \t{"); 0788 if (j != string::npos && line.compare(j, 2, "/*") == 0) 0789 { 0790 lineOpensComment = true; 0791 size_t k = line.find_first_not_of(" \t"); 0792 if (k != string::npos && line.compare(k, 1, "{") == 0) 0793 isInHorstmannComment = true; 0794 } 0795 } 0796 0797 if (line.length() == 0) 0798 { 0799 if (backslashEndsPrevLine) // must continue to clear variables 0800 line = ' '; 0801 else if (emptyLineFill && !isInQuoteContinuation && headerStack->size() > 0) 0802 return preLineWS(prevFinalLineSpaceTabCount, prevFinalLineTabCount); 0803 else 0804 return line; 0805 } 0806 0807 // handle preprocessor commands 0808 // except C# region and endregion 0809 0810 if (!isInComment 0811 && (line[0] == '#' || backslashEndsPrevLine) 0812 && line.compare(0, 7, "#region") != 0 0813 && line.compare(0, 10, "#endregion") != 0) 0814 { 0815 if (line[0] == '#') 0816 { 0817 string preproc = trim(string(line.c_str() + 1)); 0818 0819 // When finding a multi-lined #define statement, the original beautifier 0820 // 1. sets its isInDefineDefinition flag 0821 // 2. clones a new beautifier that will be used for the actual indentation 0822 // of the #define. This clone is put into the activeBeautifierStack in order 0823 // to be called for the actual indentation. 0824 // The original beautifier will have isInDefineDefinition = true, isInDefine = false 0825 // The cloned beautifier will have isInDefineDefinition = true, isInDefine = true 0826 if (preprocessorIndent && preproc.compare(0, 6, "define") == 0 && line[line.length() - 1] == '\\') 0827 { 0828 if (!isInDefineDefinition) 0829 { 0830 ASBeautifier *defineBeautifier; 0831 0832 // this is the original beautifier 0833 isInDefineDefinition = true; 0834 0835 // push a new beautifier into the active stack 0836 // this beautifier will be used for the indentation of this define 0837 defineBeautifier = new ASBeautifier(*this); 0838 activeBeautifierStack->push_back(defineBeautifier); 0839 } 0840 else 0841 { 0842 // the is the cloned beautifier that is in charge of indenting the #define. 0843 isInDefine = true; 0844 } 0845 } 0846 else if (preproc.compare(0, 2, "if") == 0) 0847 { 0848 // push a new beautifier into the stack 0849 waitingBeautifierStackLengthStack->push_back(waitingBeautifierStack->size()); 0850 activeBeautifierStackLengthStack->push_back(activeBeautifierStack->size()); 0851 waitingBeautifierStack->push_back(new ASBeautifier(*this)); 0852 } 0853 else if (preproc.compare(0, 4/*2*/, "else") == 0) 0854 { 0855 if (waitingBeautifierStack && !waitingBeautifierStack->empty()) 0856 { 0857 // MOVE current waiting beautifier to active stack. 0858 activeBeautifierStack->push_back(waitingBeautifierStack->back()); 0859 waitingBeautifierStack->pop_back(); 0860 } 0861 } 0862 else if (preproc.compare(0, 4, "elif") == 0) 0863 { 0864 if (waitingBeautifierStack && !waitingBeautifierStack->empty()) 0865 { 0866 // append a COPY current waiting beautifier to active stack, WITHOUT deleting the original. 0867 activeBeautifierStack->push_back(new ASBeautifier(*(waitingBeautifierStack->back()))); 0868 } 0869 } 0870 else if (preproc.compare(0, 5, "endif") == 0) 0871 { 0872 int stackLength; 0873 ASBeautifier *beautifier; 0874 0875 if (waitingBeautifierStackLengthStack && !waitingBeautifierStackLengthStack->empty()) 0876 { 0877 stackLength = waitingBeautifierStackLengthStack->back(); 0878 waitingBeautifierStackLengthStack->pop_back(); 0879 while ((int) waitingBeautifierStack->size() > stackLength) 0880 { 0881 beautifier = waitingBeautifierStack->back(); 0882 waitingBeautifierStack->pop_back(); 0883 delete beautifier; 0884 } 0885 } 0886 0887 if (!activeBeautifierStackLengthStack->empty()) 0888 { 0889 stackLength = activeBeautifierStackLengthStack->back(); 0890 activeBeautifierStackLengthStack->pop_back(); 0891 while ((int) activeBeautifierStack->size() > stackLength) 0892 { 0893 beautifier = activeBeautifierStack->back(); 0894 activeBeautifierStack->pop_back(); 0895 delete beautifier; 0896 } 0897 } 0898 } 0899 } 0900 0901 // check if the last char is a backslash 0902 if (line.length() > 0) 0903 backslashEndsPrevLine = (line[line.length() - 1] == '\\'); 0904 else 0905 backslashEndsPrevLine = false; 0906 0907 // check if this line ends a multi-line #define 0908 // if so, use the #define's cloned beautifier for the line's indentation 0909 // and then remove it from the active beautifier stack and delete it. 0910 if (!backslashEndsPrevLine && isInDefineDefinition && !isInDefine) 0911 { 0912 string beautifiedLine; 0913 ASBeautifier *defineBeautifier; 0914 0915 isInDefineDefinition = false; 0916 defineBeautifier = activeBeautifierStack->back(); 0917 activeBeautifierStack->pop_back(); 0918 0919 beautifiedLine = defineBeautifier->beautify(line); 0920 delete defineBeautifier; 0921 return beautifiedLine; 0922 } 0923 0924 // unless this is a multi-line #define, return this precompiler line as is. 0925 if (!isInDefine && !isInDefineDefinition) 0926 return originalLine; 0927 } 0928 0929 // if there exists any worker beautifier in the activeBeautifierStack, 0930 // then use it instead of me to indent the current line. 0931 // variables set by ASFormatter must be updated. 0932 if (!isInDefine && activeBeautifierStack != NULL && !activeBeautifierStack->empty()) 0933 { 0934 activeBeautifierStack->back()->inLineNumber = inLineNumber; 0935 activeBeautifierStack->back()->horstmannIndentInStatement = horstmannIndentInStatement; 0936 activeBeautifierStack->back()->nonInStatementBracket = nonInStatementBracket; 0937 activeBeautifierStack->back()->lineCommentNoBeautify = lineCommentNoBeautify; 0938 activeBeautifierStack->back()->isNonInStatementArray = isNonInStatementArray; 0939 activeBeautifierStack->back()->isSharpAccessor = isSharpAccessor; 0940 activeBeautifierStack->back()->isSharpDelegate = isSharpDelegate; 0941 activeBeautifierStack->back()->isInExtern = isInExtern; 0942 activeBeautifierStack->back()->isInBeautifySQL = isInBeautifySQL; 0943 activeBeautifierStack->back()->isInIndentableStruct = isInIndentableStruct; 0944 // must return originalLine not the trimmed line 0945 return activeBeautifierStack->back()->beautify(originalLine); 0946 } 0947 0948 // calculate preliminary indentation based on data from past lines 0949 0950 if (!inStatementIndentStack->empty()) 0951 spaceTabCount = inStatementIndentStack->back(); 0952 0953 for (i = 0; i < (int) headerStack->size(); i++) 0954 { 0955 isInClass = false; 0956 0957 if (blockIndent) 0958 { 0959 // do NOT indent opening block for these headers 0960 if (!((*headerStack)[i] == &AS_NAMESPACE 0961 || (*headerStack)[i] == &AS_CLASS 0962 || (*headerStack)[i] == &AS_STRUCT 0963 || (*headerStack)[i] == &AS_UNION 0964 || (*headerStack)[i] == &AS_CONST 0965 || (*headerStack)[i] == &AS_INTERFACE 0966 || (*headerStack)[i] == &AS_THROWS 0967 || (*headerStack)[i] == &AS_STATIC)) 0968 ++tabCount; 0969 } 0970 else if (!(i > 0 && (*headerStack)[i-1] != &AS_OPEN_BRACKET 0971 && (*headerStack)[i] == &AS_OPEN_BRACKET)) 0972 ++tabCount; 0973 0974 if (!isJavaStyle() && !namespaceIndent && i >= 1 0975 && (*headerStack)[i-1] == &AS_NAMESPACE 0976 && (*headerStack)[i] == &AS_OPEN_BRACKET) 0977 --tabCount; 0978 0979 if (isCStyle() && i >= 1 0980 && (*headerStack)[i-1] == &AS_CLASS 0981 && (*headerStack)[i] == &AS_OPEN_BRACKET) 0982 { 0983 if (classIndent) 0984 ++tabCount; 0985 isInClass = true; 0986 } 0987 0988 // is the switchIndent option is on, indent switch statements an additional indent. 0989 else if (switchIndent && i > 1 0990 && (*headerStack)[i-1] == &AS_SWITCH 0991 && (*headerStack)[i] == &AS_OPEN_BRACKET) 0992 { 0993 ++tabCount; 0994 isInSwitch = true; 0995 } 0996 0997 } // end of for loop * end of for loop * end of for loop * end of for loop * end of for loop * 0998 0999 iPrelim = i; 1000 1001 if (!lineStartsInComment 1002 && isCStyle() 1003 && isInClass 1004 && classIndent 1005 && headerStack->size() >= 2 1006 && (*headerStack)[headerStack->size()-2] == &AS_CLASS 1007 && (*headerStack)[headerStack->size()-1] == &AS_OPEN_BRACKET 1008 && line[0] == '}' 1009 && bracketBlockStateStack->back() == true) 1010 --tabCount; 1011 1012 else if (!lineStartsInComment 1013 && isInSwitch 1014 && switchIndent 1015 && headerStack->size() >= 2 1016 && (*headerStack)[headerStack->size()-2] == &AS_SWITCH 1017 && (*headerStack)[headerStack->size()-1] == &AS_OPEN_BRACKET 1018 && line[0] == '}') 1019 --tabCount; 1020 1021 if (isInClassInitializer) 1022 { 1023 if (lineStartsInComment || lineOpensComment) 1024 { 1025 if (!lineBeginsWithBracket) 1026 tabCount--; 1027 } 1028 else if (isCStyle() && !isClassAccessModifier(line)) 1029 { 1030 isInClassHeaderTab = true; 1031 tabCount += classInitializerTabs; 1032 } 1033 else if (blockIndent) 1034 { 1035 if (!lineBeginsWithBracket) 1036 tabCount++; 1037 } 1038 } 1039 // handle special case of indented horstmann brackets 1040 else if (lineStartsInComment && isInHorstmannComment && bracketIndent) 1041 tabCount++; 1042 1043 // handle special case of horstmann comment in an indented class statement 1044 if (isInClass 1045 && classIndent 1046 && isInHorstmannComment 1047 && !lineOpensComment 1048 && headerStack->size() >= 2 1049 && (*headerStack)[headerStack->size()-2] == &AS_CLASS) 1050 --tabCount; 1051 1052 if (isInConditional) 1053 { 1054 --tabCount; 1055 } 1056 1057 1058 // parse characters in the current line. 1059 1060 for (i = 0; i < (int) line.length(); i++) 1061 { 1062 outBuffer.append(1, line[i]); 1063 1064 tempCh = line[i]; 1065 prevCh = ch; 1066 ch = tempCh; 1067 1068 if (isInBeautifySQL) 1069 continue; 1070 1071 if (isWhiteSpace(ch)) 1072 { 1073 if (ch == '\t') 1074 tabIncrementIn += convertTabToSpaces(i, tabIncrementIn); 1075 continue; 1076 } 1077 1078 // handle special characters (i.e. backslash+character such as \n, \t, ...) 1079 1080 if (isInQuote && !isInVerbatimQuote) 1081 { 1082 if (isSpecialChar) 1083 { 1084 isSpecialChar = false; 1085 continue; 1086 } 1087 if (line.compare(i, 2, "\\\\") == 0) 1088 { 1089 outBuffer.append(1, '\\'); 1090 i++; 1091 continue; 1092 } 1093 if (ch == '\\') 1094 { 1095 if (peekNextChar(line, i) == ' ') // is this '\' at end of line 1096 haveLineContinuationChar = true; 1097 else 1098 isSpecialChar = true; 1099 continue; 1100 } 1101 } 1102 else if (isInDefine && ch == '\\') 1103 continue; 1104 1105 // handle quotes (such as 'x' and "Hello Dolly") 1106 if (!(isInComment || isInLineComment) && (ch == '"' || ch == '\'')) 1107 { 1108 if (!isInQuote) 1109 { 1110 quoteChar = ch; 1111 isInQuote = true; 1112 if (isSharpStyle() && prevCh == '@') 1113 isInVerbatimQuote = true; 1114 } 1115 else if (isInVerbatimQuote && ch == '"') 1116 { 1117 if (peekNextChar(line, i) == '"') // check consecutive quotes 1118 { 1119 outBuffer.append(1, '"'); 1120 i++; 1121 } 1122 else 1123 { 1124 isInQuote = false; 1125 isInVerbatimQuote = false; 1126 } 1127 } 1128 else if (quoteChar == ch) 1129 { 1130 isInQuote = false; 1131 isInStatement = true; 1132 continue; 1133 } 1134 } 1135 if (isInQuote) 1136 continue; 1137 1138 // handle comments 1139 1140 if (!(isInComment || isInLineComment) && line.compare(i, 2, "//") == 0) 1141 { 1142 isInLineComment = true; 1143 outBuffer.append(1, '/'); 1144 i++; 1145 continue; 1146 } 1147 else if (!(isInComment || isInLineComment) && line.compare(i, 2, "/*") == 0) 1148 { 1149 isInComment = true; 1150 outBuffer.append(1, '*'); 1151 i++; 1152 if (!lineOpensComment) // does line start with comment? 1153 blockCommentNoIndent = true; // if no, cannot indent continuation lines 1154 continue; 1155 } 1156 else if ((isInComment || isInLineComment) && line.compare(i, 2, "*/") == 0) 1157 { 1158 isInComment = false; 1159 outBuffer.append(1, '/'); 1160 i++; 1161 blockCommentNoIndent = false; // ok to indent next comment 1162 continue; 1163 } 1164 // treat C# '#region' and '#endregion' statements as a line comment 1165 else if (isSharpStyle() && 1166 (line.compare(i, 7, "#region") == 0 || line.compare(i, 10, "#endregion") == 0)) 1167 { 1168 isInLineComment = true; 1169 } 1170 1171 if (isInComment || isInLineComment) 1172 { 1173 // append rest of the comment up to the comment end 1174 while (i+1 < (int) line.length() 1175 && line.compare(i+1, 2, "*/") != 0) 1176 outBuffer.append(1, line[++i]); 1177 continue; 1178 } 1179 1180 // if we have reached this far then we are NOT in a comment or string of special character... 1181 1182 // SQL if formatted in ASEnhancer 1183 if (isInBeautifySQL) 1184 continue; 1185 1186 if (probationHeader != NULL) 1187 { 1188 if (((probationHeader == &AS_STATIC || probationHeader == &AS_CONST) && ch == '{') 1189 || (probationHeader == &AS_SYNCHRONIZED && ch == '(')) 1190 { 1191 // insert the probation header as a new header 1192 isInHeader = true; 1193 headerStack->push_back(probationHeader); 1194 1195 // handle the specific probation header 1196 isInConditional = (probationHeader == &AS_SYNCHRONIZED); 1197 1198 isInStatement = false; 1199 // if the probation comes from the previous line, then indent by 1 tab count. 1200 if (previousLineProbation 1201 && ch == '{' 1202 && !(blockIndent 1203 && (probationHeader == &AS_CONST || probationHeader == &AS_STATIC))) 1204 { 1205 tabCount++; 1206 previousLineProbationTab = true; 1207 } 1208 previousLineProbation = false; 1209 } 1210 1211 // dismiss the probation header 1212 probationHeader = NULL; 1213 } 1214 1215 prevNonSpaceCh = currentNonSpaceCh; 1216 currentNonSpaceCh = ch; 1217 if (!isLegalNameChar(ch) && ch != ',' && ch != ';') 1218 { 1219 prevNonLegalCh = currentNonLegalCh; 1220 currentNonLegalCh = ch; 1221 } 1222 1223 if (isInHeader) 1224 { 1225 isInHeader = false; 1226 currentHeader = headerStack->back(); 1227 } 1228 else 1229 currentHeader = NULL; 1230 1231 if (isCStyle() && isInTemplate 1232 && (ch == '<' || ch == '>') 1233 && findOperator(line, i, nonAssignmentOperators) == NULL) 1234 { 1235 if (ch == '<') 1236 { 1237 ++templateDepth; 1238 } 1239 else if (ch == '>') 1240 { 1241 if (--templateDepth <= 0) 1242 { 1243 if (isInTemplate) 1244 ch = ';'; 1245 else 1246 ch = 't'; 1247 isInTemplate = false; 1248 templateDepth = 0; 1249 } 1250 } 1251 } 1252 1253 // handle parenthesies 1254 if (ch == '(' || ch == '[' || ch == ')' || ch == ']') 1255 { 1256 if (ch == '(' || ch == '[') 1257 { 1258 isInOperator = false; 1259 // if have a struct header, this is a declaration not a definition 1260 if (ch == '(' 1261 && (isInClassInitializer || isInClassHeaderTab) 1262 && headerStack->size() > 0 1263 && headerStack->back() == &AS_STRUCT) 1264 { 1265 headerStack->pop_back(); 1266 isInClassInitializer = false; 1267 // -1 for isInClassInitializer, -2 for isInClassHeaderTab 1268 if (isInClassHeaderTab) 1269 { 1270 tabCount -= (1 + classInitializerTabs); 1271 isInClassHeaderTab = false; 1272 } 1273 if (tabCount < 0) 1274 tabCount = 0; 1275 } 1276 1277 if (parenDepth == 0) 1278 { 1279 parenStatementStack->push_back(isInStatement); 1280 isInStatement = true; 1281 } 1282 parenDepth++; 1283 1284 inStatementIndentStackSizeStack->push_back(inStatementIndentStack->size()); 1285 1286 if (currentHeader != NULL) 1287 registerInStatementIndent(line, i, spaceTabCount, tabIncrementIn, minConditionalIndent/*indentLength*2*/, true); 1288 else 1289 registerInStatementIndent(line, i, spaceTabCount, tabIncrementIn, 0, true); 1290 } 1291 else if (ch == ')' || ch == ']') 1292 { 1293 parenDepth--; 1294 if (parenDepth == 0) 1295 { 1296 if (!parenStatementStack->empty()) // in case of unmatched closing parens 1297 { 1298 isInStatement = parenStatementStack->back(); 1299 parenStatementStack->pop_back(); 1300 } 1301 ch = ' '; 1302 isInAsm = false; 1303 isInConditional = false; 1304 } 1305 1306 if (!inStatementIndentStackSizeStack->empty()) 1307 { 1308 int previousIndentStackSize = inStatementIndentStackSizeStack->back(); 1309 inStatementIndentStackSizeStack->pop_back(); 1310 while (previousIndentStackSize < (int) inStatementIndentStack->size()) 1311 inStatementIndentStack->pop_back(); 1312 1313 if (!parenIndentStack->empty()) 1314 { 1315 int poppedIndent = parenIndentStack->back(); 1316 parenIndentStack->pop_back(); 1317 1318 if (i == 0) 1319 spaceTabCount = poppedIndent; 1320 } 1321 } 1322 } 1323 1324 continue; 1325 } 1326 1327 1328 if (ch == '{') 1329 { 1330 // first, check if '{' is a block-opener or an static-array opener 1331 bool isBlockOpener = ((prevNonSpaceCh == '{' && bracketBlockStateStack->back()) 1332 || prevNonSpaceCh == '}' 1333 || prevNonSpaceCh == ')' 1334 || prevNonSpaceCh == ';' 1335 || peekNextChar(line, i) == '{' 1336 || isInClassInitializer 1337 || isNonInStatementArray 1338 || isSharpAccessor 1339 || isSharpDelegate 1340 || isInExtern 1341 || (isInDefine && 1342 (prevNonSpaceCh == '(' 1343 || isLegalNameChar(prevNonSpaceCh)))); 1344 1345 // remove inStatementIndent for C++ class initializer 1346 if (isInClassInitializer) 1347 { 1348 if (inStatementIndentStack->size() > 0) 1349 inStatementIndentStack->pop_back(); 1350 isInStatement = false; 1351 if (lineBeginsWithBracket) 1352 spaceTabCount = 0; 1353 isInClassInitializer = false; 1354 } 1355 1356 if (!isBlockOpener && currentHeader != NULL) 1357 { 1358 for (size_t n = 0; n < nonParenHeaders->size(); n++) 1359 if (currentHeader == (*nonParenHeaders)[n]) 1360 { 1361 isBlockOpener = true; 1362 break; 1363 } 1364 } 1365 1366 bracketBlockStateStack->push_back(isBlockOpener); 1367 1368 if (!isBlockOpener) 1369 { 1370 inStatementIndentStackSizeStack->push_back(inStatementIndentStack->size()); 1371 registerInStatementIndent(line, i, spaceTabCount, tabIncrementIn, 0, true); 1372 parenDepth++; 1373 if (i == 0) 1374 shouldIndentBrackettedLine = false; 1375 1376 continue; 1377 } 1378 1379 // this bracket is a block opener... 1380 1381 ++lineOpeningBlocksNum; 1382 1383 if (isInClassHeaderTab) 1384 { 1385 isInClassHeaderTab = false; 1386 // decrease tab count if bracket is broken 1387 size_t firstChar = line.find_first_not_of(" \t"); 1388 if (firstChar != string::npos 1389 && line[firstChar] == '{' 1390 && (int) firstChar == i) 1391 { 1392 tabCount -= classInitializerTabs; 1393 // decrease one more if an empty class 1394 if (headerStack->size() > 0 1395 && (*headerStack).back() == &AS_CLASS) 1396 { 1397 int nextChar = getNextProgramCharDistance(line, i); 1398 if (line[nextChar] == '}') 1399 tabCount--; 1400 } 1401 } 1402 } 1403 1404 if (bracketIndent && !namespaceIndent && headerStack->size() > 0 1405 && (*headerStack).back() == &AS_NAMESPACE) 1406 { 1407 shouldIndentBrackettedLine = false; 1408 tabCount--; 1409 } 1410 1411 // an indentable struct is treated like a class in the header stack 1412 if (headerStack->size() > 0 1413 && (*headerStack).back() == &AS_STRUCT 1414 && isInIndentableStruct) 1415 (*headerStack).back() = &AS_CLASS; 1416 1417 blockParenDepthStack->push_back(parenDepth); 1418 blockStatementStack->push_back(isInStatement); 1419 1420 inStatementIndentStackSizeStack->push_back(inStatementIndentStack->size()); 1421 if (inStatementIndentStack->size() > 0) 1422 { 1423 spaceTabCount = 0; 1424 inStatementIndentStack->back() = 0; 1425 } 1426 1427 blockTabCount += isInStatement ? 1 : 0; 1428 parenDepth = 0; 1429 isInStatement = false; 1430 1431 tempStacks->push_back(new vector<const string*>); 1432 headerStack->push_back(&AS_OPEN_BRACKET); 1433 lastLineHeader = &AS_OPEN_BRACKET; 1434 1435 continue; 1436 } 1437 1438 //check if a header has been reached 1439 bool isPotentialHeader = isCharPotentialHeader(line, i); 1440 1441 if (isPotentialHeader) 1442 { 1443 const string *newHeader = findHeader(line, i, headers); 1444 1445 if (newHeader != NULL) 1446 { 1447 char peekChar = peekNextChar(line, i + newHeader->length() - 1); 1448 1449 // is not a header if part of a definition 1450 if (peekChar == ',' || peekChar == ')') 1451 newHeader = NULL; 1452 // the following accessor definitions are NOT headers 1453 // goto default; is NOT a header 1454 // default(int) keyword in C# is NOT a header 1455 else if ((newHeader == &AS_GET || newHeader == &AS_SET || newHeader == &AS_DEFAULT) 1456 && (peekChar == ';' || peekChar == '(')) 1457 { 1458 newHeader = NULL; 1459 } 1460 } 1461 1462 if (newHeader != NULL) 1463 { 1464 // if we reached here, then this is a header... 1465 bool isIndentableHeader = true; 1466 1467 isInHeader = true; 1468 1469 vector<const string*> *lastTempStack; 1470 if (tempStacks->empty()) 1471 lastTempStack = NULL; 1472 else 1473 lastTempStack = tempStacks->back(); 1474 1475 // if a new block is opened, push a new stack into tempStacks to hold the 1476 // future list of headers in the new block. 1477 1478 // take care of the special case: 'else if (...)' 1479 if (newHeader == &AS_IF && lastLineHeader == &AS_ELSE) 1480 { 1481 headerStack->pop_back(); 1482 } 1483 1484 // take care of 'else' 1485 else if (newHeader == &AS_ELSE) 1486 { 1487 if (lastTempStack != NULL) 1488 { 1489 int indexOfIf = indexOf(*lastTempStack, &AS_IF); 1490 if (indexOfIf != -1) 1491 { 1492 // recreate the header list in headerStack up to the previous 'if' 1493 // from the temporary snapshot stored in lastTempStack. 1494 int restackSize = lastTempStack->size() - indexOfIf - 1; 1495 for (int r = 0; r < restackSize; r++) 1496 { 1497 headerStack->push_back(lastTempStack->back()); 1498 lastTempStack->pop_back(); 1499 } 1500 if (!closingBracketReached) 1501 tabCount += restackSize; 1502 } 1503 /* 1504 * If the above if is not true, i.e. no 'if' before the 'else', 1505 * then nothing beautiful will come out of this... 1506 * I should think about inserting an Exception here to notify the caller of this... 1507 */ 1508 } 1509 } 1510 1511 // check if 'while' closes a previous 'do' 1512 else if (newHeader == &AS_WHILE) 1513 { 1514 if (lastTempStack != NULL) 1515 { 1516 int indexOfDo = indexOf(*lastTempStack, &AS_DO); 1517 if (indexOfDo != -1) 1518 { 1519 // recreate the header list in headerStack up to the previous 'do' 1520 // from the temporary snapshot stored in lastTempStack. 1521 int restackSize = lastTempStack->size() - indexOfDo - 1; 1522 for (int r = 0; r < restackSize; r++) 1523 { 1524 headerStack->push_back(lastTempStack->back()); 1525 lastTempStack->pop_back(); 1526 } 1527 if (!closingBracketReached) 1528 tabCount += restackSize; 1529 } 1530 } 1531 } 1532 // check if 'catch' closes a previous 'try' or 'catch' 1533 else if (newHeader == &AS_CATCH || newHeader == &AS_FINALLY) 1534 { 1535 if (lastTempStack != NULL) 1536 { 1537 int indexOfTry = indexOf(*lastTempStack, &AS_TRY); 1538 if (indexOfTry == -1) 1539 indexOfTry = indexOf(*lastTempStack, &AS_CATCH); 1540 if (indexOfTry != -1) 1541 { 1542 // recreate the header list in headerStack up to the previous 'try' 1543 // from the temporary snapshot stored in lastTempStack. 1544 int restackSize = lastTempStack->size() - indexOfTry - 1; 1545 for (int r = 0; r < restackSize; r++) 1546 { 1547 headerStack->push_back(lastTempStack->back()); 1548 lastTempStack->pop_back(); 1549 } 1550 1551 if (!closingBracketReached) 1552 tabCount += restackSize; 1553 } 1554 } 1555 } 1556 else if (newHeader == &AS_CASE) 1557 { 1558 isInCase = true; 1559 if (!haveCaseIndent) 1560 { 1561 haveCaseIndent = true; 1562 if (!lineBeginsWithBracket) 1563 --tabCount; 1564 } 1565 } 1566 else if (newHeader == &AS_DEFAULT) 1567 { 1568 isInCase = true; 1569 --tabCount; 1570 } 1571 else if (newHeader == &AS_STATIC 1572 || newHeader == &AS_SYNCHRONIZED 1573 || (newHeader == &AS_CONST && isCStyle())) 1574 { 1575 if (!headerStack->empty() && 1576 (headerStack->back() == &AS_STATIC 1577 || headerStack->back() == &AS_SYNCHRONIZED 1578 || headerStack->back() == &AS_CONST)) 1579 { 1580 isIndentableHeader = false; 1581 } 1582 else 1583 { 1584 isIndentableHeader = false; 1585 probationHeader = newHeader; 1586 } 1587 } 1588 else if (newHeader == &AS_CONST) 1589 { 1590 isIndentableHeader = false; 1591 } 1592 else if (newHeader == &AS_TEMPLATE) 1593 { 1594 if (isCStyle()) 1595 isInTemplate = true; 1596 isIndentableHeader = false; 1597 } 1598 1599 if (isIndentableHeader) 1600 { 1601 headerStack->push_back(newHeader); 1602 isInStatement = false; 1603 if (indexOf(*nonParenHeaders, newHeader) == -1) 1604 { 1605 isInConditional = true; 1606 } 1607 lastLineHeader = newHeader; 1608 } 1609 else 1610 isInHeader = false; 1611 1612 outBuffer.append(newHeader->substr(1)); 1613 i += newHeader->length() - 1; 1614 1615 continue; 1616 } // newHeader != NULL 1617 1618 if (isCStyle() && findKeyword(line, i, AS_ENUM)) 1619 isInEnum = true; 1620 1621 } // isPotentialHeader 1622 1623 if (ch == '?') 1624 isInQuestion = true; 1625 1626 // special handling of 'case' statements 1627 if (ch == ':') 1628 { 1629 if ((int) line.length() > i + 1 && line[i+1] == ':') // look for :: 1630 { 1631 ++i; 1632 outBuffer.append(1, ':'); 1633 ch = ' '; 1634 continue; 1635 } 1636 1637 else if (isInQuestion) 1638 { 1639 isInQuestion = false; 1640 } 1641 1642 else if (isCStyle() && isInClassInitializer) 1643 { 1644 // found a 'class A : public B' definition 1645 // so do nothing special 1646 } 1647 1648 else if (isCStyle() 1649 && (isInAsm || isInAsmOneLine || isInAsmBlock)) 1650 { 1651 // do nothing special 1652 } 1653 1654 else if (isCStyle() && isdigit(peekNextChar(line, i))) 1655 { 1656 // found a bit field 1657 // so do nothing special 1658 } 1659 1660 else if (isCStyle() && isInClass && prevNonSpaceCh != ')') 1661 { 1662 // found a 'private:' or 'public:' inside a class definition 1663 --tabCount; 1664 } 1665 1666 else if (isCStyle() && prevNonSpaceCh == ')' && !isInCase) 1667 { 1668 isInClassInitializer = true; 1669 if (i == 0) 1670 tabCount += classInitializerTabs; 1671 } 1672 1673 else if (isJavaStyle() && lastLineHeader == &AS_FOR) 1674 { 1675 // found a java for-each statement 1676 // so do nothing special 1677 } 1678 1679 else 1680 { 1681 currentNonSpaceCh = ';'; // so that brackets after the ':' will appear as block-openers 1682 if (isInCase) 1683 { 1684 isInCase = false; 1685 ch = ';'; // from here on, treat char as ';' 1686 } 1687 else if (isCStyle() || (isSharpStyle() && peekNextChar(line, i) == ';')) // is in a label (e.g. 'label1:') 1688 { 1689 if (labelIndent) 1690 --tabCount; // unindent label by one indent 1691 else if (!lineBeginsWithBracket) 1692 tabCount = 0; // completely flush indent to left 1693 } 1694 } 1695 } 1696 1697 if ((ch == ';' || (parenDepth > 0 && ch == ',')) && !inStatementIndentStackSizeStack->empty()) 1698 while ((int) inStatementIndentStackSizeStack->back() + (parenDepth > 0 ? 1 : 0) 1699 < (int) inStatementIndentStack->size()) 1700 inStatementIndentStack->pop_back(); 1701 1702 // handle commas 1703 // previous "isInStatement" will be from an assignment operator 1704 if (ch == ',' && parenDepth == 0 && !isInStatement && !isNonInStatementArray) 1705 { 1706 // is comma at end of line 1707 size_t nextChar = line.find_first_not_of(" \t", i + 1); 1708 if (nextChar != string::npos) 1709 { 1710 if (line.compare(nextChar, 2, "//") == 0 1711 || line.compare(nextChar, 2, "/*") == 0) 1712 nextChar = string::npos; 1713 } 1714 // register indent 1715 if (nextChar == string::npos) 1716 { 1717 // register indent at first word after the colon of a C++ class initializer 1718 if (isInClassInitializer) 1719 { 1720 size_t firstChar = line.find_first_not_of(" \t"); 1721 if (firstChar != string::npos && line[firstChar] == ':') 1722 { 1723 size_t firstWord = line.find_first_not_of(" \t", firstChar + 1); 1724 if (firstChar != string::npos) 1725 { 1726 int inStatementIndent = firstWord + spaceTabCount + tabIncrementIn; 1727 inStatementIndentStack->push_back(inStatementIndent); 1728 isInStatement = true; 1729 } 1730 } 1731 } 1732 // register indent at previous word 1733 else 1734 { 1735 int prevWord = getInStatementIndentComma(line, i); 1736 int inStatementIndent = prevWord + spaceTabCount + tabIncrementIn; 1737 inStatementIndentStack->push_back(inStatementIndent); 1738 isInStatement = true; 1739 } 1740 } 1741 } 1742 1743 // handle ends of statements 1744 if ((ch == ';' && parenDepth == 0) || ch == '}') 1745 { 1746 if (ch == '}') 1747 { 1748 // first check if this '}' closes a previous block, or a static array... 1749 if (!bracketBlockStateStack->empty()) 1750 { 1751 bool bracketBlockState = bracketBlockStateStack->back(); 1752 bracketBlockStateStack->pop_back(); 1753 if (!bracketBlockState) 1754 { 1755 if (!inStatementIndentStackSizeStack->empty()) 1756 { 1757 // this bracket is a static array 1758 1759 int previousIndentStackSize = inStatementIndentStackSizeStack->back(); 1760 inStatementIndentStackSizeStack->pop_back(); 1761 while (previousIndentStackSize < (int) inStatementIndentStack->size()) 1762 inStatementIndentStack->pop_back(); 1763 parenDepth--; 1764 if (i == 0) 1765 shouldIndentBrackettedLine = false; 1766 1767 if (!parenIndentStack->empty()) 1768 { 1769 int poppedIndent = parenIndentStack->back(); 1770 parenIndentStack->pop_back(); 1771 if (i == 0) 1772 spaceTabCount = poppedIndent; 1773 } 1774 } 1775 continue; 1776 } 1777 } 1778 1779 // this bracket is block closer... 1780 1781 ++lineClosingBlocksNum; 1782 1783 if (!inStatementIndentStackSizeStack->empty()) 1784 inStatementIndentStackSizeStack->pop_back(); 1785 1786 if (!blockParenDepthStack->empty()) 1787 { 1788 parenDepth = blockParenDepthStack->back(); 1789 blockParenDepthStack->pop_back(); 1790 isInStatement = blockStatementStack->back(); 1791 blockStatementStack->pop_back(); 1792 1793 if (isInStatement) 1794 blockTabCount--; 1795 } 1796 1797 closingBracketReached = true; 1798 isInAsmOneLine = false; 1799 1800 // added for release 1.24 1801 // TODO: remove at the appropriate time 1802 assert(isInAsm == false); 1803 assert(isInAsmOneLine == false); 1804 assert(isInQuote == false); 1805 isInAsm = isInAsmOneLine = isInQuote = false; 1806 // end remove 1807 1808 int headerPlace = indexOf(*headerStack, &AS_OPEN_BRACKET); 1809 if (headerPlace != -1) 1810 { 1811 const string *popped = headerStack->back(); 1812 while (popped != &AS_OPEN_BRACKET) 1813 { 1814 headerStack->pop_back(); 1815 popped = headerStack->back(); 1816 } 1817 headerStack->pop_back(); 1818 1819 // do not indent namespace bracket unless namespaces are indented 1820 if (!namespaceIndent && headerStack->size() > 0 1821 && (*headerStack).back() == &AS_NAMESPACE) 1822 shouldIndentBrackettedLine = false; 1823 1824 if (!tempStacks->empty()) 1825 { 1826 vector<const string*> *temp = tempStacks->back(); 1827 tempStacks->pop_back(); 1828 delete temp; 1829 } 1830 } 1831 1832 1833 ch = ' '; // needed due to cases such as '}else{', so that headers ('else' tn tih case) will be identified... 1834 } 1835 1836 /* 1837 * Create a temporary snapshot of the current block's header-list in the 1838 * uppermost inner stack in tempStacks, and clear the headerStack up to 1839 * the begining of the block. 1840 * Thus, the next future statement will think it comes one indent past 1841 * the block's '{' unless it specifically checks for a companion-header 1842 * (such as a previous 'if' for an 'else' header) within the tempStacks, 1843 * and recreates the temporary snapshot by manipulating the tempStacks. 1844 */ 1845 if (!tempStacks->back()->empty()) 1846 while (!tempStacks->back()->empty()) 1847 tempStacks->back()->pop_back(); 1848 while (!headerStack->empty() && headerStack->back() != &AS_OPEN_BRACKET) 1849 { 1850 tempStacks->back()->push_back(headerStack->back()); 1851 headerStack->pop_back(); 1852 } 1853 1854 if (parenDepth == 0 && ch == ';') 1855 isInStatement = false; 1856 1857 previousLastLineHeader = NULL; 1858 isInClassInitializer = false; 1859 isInEnum = false; 1860 isInQuestion = false; 1861 1862 continue; 1863 } 1864 1865 if (isPotentialHeader) 1866 { 1867 // check for preBlockStatements in C/C++ ONLY if not within parenthesies 1868 // (otherwise 'struct XXX' statements would be wrongly interpreted...) 1869 if (!isInTemplate && !(isCStyle() && parenDepth > 0)) 1870 { 1871 const string *newHeader = findHeader(line, i, preBlockStatements); 1872 if (newHeader != NULL 1873 && !(isCStyle() && newHeader == &AS_CLASS && isInEnum)) // is it 'enum class' 1874 { 1875 isInClassInitializer = true; 1876 1877 if (!isSharpStyle()) 1878 headerStack->push_back(newHeader); 1879 // do not need 'where' in the headerStack 1880 // do not need second 'class' statement in a row 1881 else if (!(newHeader == &AS_WHERE 1882 || (newHeader == &AS_CLASS 1883 && headerStack->size() > 0 1884 && headerStack->back() == &AS_CLASS))) 1885 headerStack->push_back(newHeader); 1886 1887 outBuffer.append(newHeader->substr(1)); 1888 i += newHeader->length() - 1; 1889 continue; 1890 } 1891 } 1892 const string *foundIndentableHeader = findHeader(line, i, indentableHeaders); 1893 1894 if (foundIndentableHeader != NULL) 1895 { 1896 // must bypass the header before registering the in statement 1897 outBuffer.append(foundIndentableHeader->substr(1)); 1898 i += foundIndentableHeader->length() - 1; 1899 if (!isInOperator && !isInTemplate && !isNonInStatementArray) 1900 { 1901 registerInStatementIndent(line, i, spaceTabCount, tabIncrementIn, 0, false); 1902 isInStatement = true; 1903 } 1904 continue; 1905 } 1906 1907 if (isCStyle() && findKeyword(line, i, AS_OPERATOR)) 1908 isInOperator = true; 1909 1910 // "new" operator is a pointer, not a calculation 1911 if (findKeyword(line, i, AS_NEW)) 1912 { 1913 if (prevNonSpaceCh == '=' && isInStatement && !inStatementIndentStack->empty()) 1914 inStatementIndentStack->back() = 0; 1915 } 1916 1917 if (isCStyle()) 1918 { 1919 if (findKeyword(line, i, AS_ASM) 1920 || findKeyword(line, i, AS__ASM__)) 1921 { 1922 isInAsm = true; 1923 } 1924 else if (findKeyword(line, i, AS_MS_ASM) // microsoft specific 1925 || findKeyword(line, i, AS_MS__ASM)) 1926 { 1927 int index = 4; 1928 if (peekNextChar(line, i) == '_') // check for __asm 1929 index = 5; 1930 1931 char peekedChar = ASBase::peekNextChar(line, i + index); 1932 if (peekedChar == '{' || peekedChar == ' ') 1933 isInAsmBlock = true; 1934 else 1935 isInAsmOneLine = true; 1936 } 1937 } 1938 1939 // append the entire name for all others 1940 string name = getCurrentWord(line, i); 1941 outBuffer.append(name.substr(1)); 1942 i += name.length() - 1; 1943 continue; 1944 } 1945 1946 // Handle operators 1947 1948 bool isPotentialOperator = isCharPotentialOperator(ch); 1949 1950 if (isPotentialOperator) 1951 { 1952 // Check if an operator has been reached. 1953 const string *foundAssignmentOp = findOperator(line, i, assignmentOperators); 1954 const string *foundNonAssignmentOp = findOperator(line, i, nonAssignmentOperators); 1955 1956 // Since findHeader's boundry checking was not used above, it is possible 1957 // that both an assignment op and a non-assignment op where found, 1958 // e.g. '>>' and '>>='. If this is the case, treat the LONGER one as the 1959 // found operator. 1960 if (foundAssignmentOp != NULL && foundNonAssignmentOp != NULL) 1961 { 1962 if (foundAssignmentOp->length() < foundNonAssignmentOp->length()) 1963 foundAssignmentOp = NULL; 1964 else 1965 foundNonAssignmentOp = NULL; 1966 } 1967 1968 if (foundNonAssignmentOp != NULL) 1969 { 1970 if (foundNonAssignmentOp->length() > 1) 1971 { 1972 outBuffer.append(foundNonAssignmentOp->substr(1)); 1973 i += foundNonAssignmentOp->length() - 1; 1974 } 1975 1976 // For C++ input/output, operator<< and >> should be 1977 // aligned, if we are not in a statement already and 1978 // also not in the "operator<<(...)" header line 1979 if (!isInOperator 1980 && inStatementIndentStack->empty() 1981 && isCStyle() 1982 && (foundNonAssignmentOp == &AS_GR_GR || 1983 foundNonAssignmentOp == &AS_LS_LS)) 1984 { 1985 // this will be true if the line begins with the operator 1986 if (i < 2 && spaceTabCount == 0) 1987 spaceTabCount += 2 * indentLength; 1988 // align to the beginning column of the operator 1989 registerInStatementIndent(line, i - foundNonAssignmentOp->length(), spaceTabCount, tabIncrementIn, 0, false); 1990 } 1991 } 1992 1993 else if (foundAssignmentOp != NULL) 1994 { 1995 if (foundAssignmentOp->length() > 1) 1996 { 1997 outBuffer.append(foundAssignmentOp->substr(1)); 1998 i += foundAssignmentOp->length() - 1; 1999 } 2000 2001 if (!isInOperator && !isInTemplate && !isNonInStatementArray) 2002 { 2003 // if multiple assignments, align on the previous word 2004 if (foundAssignmentOp == &AS_ASSIGN 2005 && prevNonSpaceCh != ']' // an array 2006 && statementEndsWithComma(line, i)) 2007 { 2008 if (!haveAssignmentThisLine) // only one assignment indent per line 2009 { 2010 // register indent at previous word 2011 haveAssignmentThisLine = true; 2012 int prevWordIndex = getInStatementIndentAssign(line, i); 2013 int inStatementIndent = prevWordIndex + spaceTabCount + tabIncrementIn; 2014 inStatementIndentStack->push_back(inStatementIndent); 2015 } 2016 } 2017 else 2018 registerInStatementIndent(line, i, spaceTabCount, tabIncrementIn, 0, false); 2019 2020 isInStatement = true; 2021 } 2022 } 2023 } 2024 } // end of for loop * end of for loop * end of for loop * end of for loop * end of for loop * 2025 2026 // handle special cases of unindentation: 2027 2028 /* 2029 * if '{' doesn't follow an immediately previous '{' in the headerStack 2030 * (but rather another header such as "for" or "if", then unindent it 2031 * by one indentation relative to its block. 2032 */ 2033 2034 if (!lineStartsInComment 2035 && !blockIndent 2036 && outBuffer.length() > 0 2037 && outBuffer[0] == '{' 2038 && !(lineOpeningBlocksNum > 0 && lineOpeningBlocksNum == lineClosingBlocksNum) 2039 && !(headerStack->size() > 1 && (*headerStack)[headerStack->size()-2] == &AS_OPEN_BRACKET) 2040 && shouldIndentBrackettedLine) 2041 --tabCount; 2042 2043 // must check one less in headerStack if more than one header on a line (allow-addins)... 2044 else if (!lineStartsInComment 2045 && (int) headerStack->size() > iPrelim + 1 2046 && !blockIndent 2047 && outBuffer.length() > 0 2048 && outBuffer[0] == '{' 2049 && !(lineOpeningBlocksNum > 0 && lineOpeningBlocksNum == lineClosingBlocksNum) 2050 && !(headerStack->size() > 2 && (*headerStack)[headerStack->size()-3] == &AS_OPEN_BRACKET) 2051 && shouldIndentBrackettedLine) 2052 --tabCount; 2053 2054 // unindent a closing bracket... 2055 else if (!lineStartsInComment 2056 && outBuffer.length() > 0 2057 && outBuffer[0] == '}' 2058 && shouldIndentBrackettedLine) 2059 --tabCount; 2060 2061 // correctly indent one-line-blocks... 2062 else if (!lineStartsInComment 2063 && outBuffer.length() > 0 2064 && lineOpeningBlocksNum > 0 2065 && lineOpeningBlocksNum == lineClosingBlocksNum 2066 && previousLineProbationTab) 2067 --tabCount; //lineOpeningBlocksNum - (blockIndent ? 1 : 0); 2068 2069 // correctly indent class continuation lines... 2070 else if (!lineStartsInComment 2071 && !lineOpensComment 2072 && isInClassHeaderTab 2073 && !blockIndent 2074 && outBuffer.length() > 0 2075 && lineOpeningBlocksNum == 0 2076 && lineOpeningBlocksNum == lineClosingBlocksNum 2077 && (headerStack->size() > 0 && headerStack->back() == &AS_CLASS)) 2078 --tabCount; 2079 2080 if (tabCount < 0) 2081 tabCount = 0; 2082 2083 // take care of extra bracket indentatation option... 2084 if (!lineStartsInComment 2085 && bracketIndent 2086 && shouldIndentBrackettedLine 2087 && outBuffer.length() > 0 2088 && (outBuffer[0] == '{' || outBuffer[0] == '}')) 2089 tabCount++; 2090 2091 if (isInDefine) 2092 { 2093 if (outBuffer[0] == '#') 2094 { 2095 string preproc = trim(string(outBuffer.c_str() + 1)); 2096 if (preproc.compare(0, 6, "define") == 0) 2097 { 2098 if (!inStatementIndentStack->empty() 2099 && inStatementIndentStack->back() > 0) 2100 { 2101 defineTabCount = tabCount; 2102 } 2103 else 2104 { 2105 defineTabCount = tabCount - 1; 2106 tabCount--; 2107 } 2108 } 2109 } 2110 2111 tabCount -= defineTabCount; 2112 } 2113 2114 if (tabCount < 0) 2115 tabCount = 0; 2116 if (lineCommentNoBeautify || blockCommentNoBeautify || isInQuoteContinuation) 2117 tabCount = spaceTabCount = 0; 2118 2119 // finally, insert indentations into begining of line 2120 2121 if (shouldForceTabIndentation) 2122 { 2123 tabCount += spaceTabCount / indentLength; 2124 spaceTabCount = spaceTabCount % indentLength; 2125 } 2126 2127 outBuffer = preLineWS(spaceTabCount, tabCount) + outBuffer; 2128 2129 prevFinalLineSpaceTabCount = spaceTabCount; 2130 prevFinalLineTabCount = tabCount; 2131 2132 if (lastLineHeader != NULL) 2133 previousLastLineHeader = lastLineHeader; 2134 2135 return outBuffer; 2136 } 2137 2138 2139 string ASBeautifier::preLineWS(int spaceTabCount, int tabCount) 2140 { 2141 string ws; 2142 2143 for (int i = 0; i < tabCount; i++) 2144 ws += indentString; 2145 2146 while ((spaceTabCount--) > 0) 2147 ws += string(" "); 2148 2149 return ws; 2150 2151 } 2152 2153 bool ASBeautifier::isClassAccessModifier(string& line) const 2154 { 2155 size_t firstChar = line.find_first_not_of(" \t"); 2156 if (firstChar == string::npos) 2157 return false; 2158 // bypass a colon 2159 if (line[firstChar] == ':') 2160 { 2161 firstChar = line.find_first_not_of(" \t"); 2162 if (firstChar == string::npos) 2163 return false; 2164 } 2165 if (line.compare(firstChar, 7, "public ") == 0 2166 || line.compare(firstChar, 8, "private ") == 0 2167 || line.compare(firstChar, 10, "protected ") == 0) 2168 return true; 2169 return false; 2170 } 2171 2172 /** 2173 * register an in-statement indent. 2174 */ 2175 void ASBeautifier::registerInStatementIndent(const string &line, int i, int spaceTabCount, 2176 int tabIncrementIn, int minIndent, bool updateParenStack) 2177 { 2178 int inStatementIndent; 2179 int remainingCharNum = line.length() - i; 2180 int nextNonWSChar = getNextProgramCharDistance(line, i); 2181 2182 // if indent is around the last char in the line, indent instead one indent from the previous indent 2183 if (nextNonWSChar == remainingCharNum) 2184 { 2185 int previousIndent = spaceTabCount; 2186 if (!inStatementIndentStack->empty()) 2187 previousIndent = inStatementIndentStack->back(); 2188 int currIndent = /*2*/ indentLength + previousIndent; 2189 if (currIndent > maxInStatementIndent 2190 && line[i] != '{') 2191 currIndent = indentLength * 2 + spaceTabCount; 2192 inStatementIndentStack->push_back(currIndent); 2193 if (updateParenStack) 2194 parenIndentStack->push_back(previousIndent); 2195 return; 2196 } 2197 2198 if (updateParenStack) 2199 parenIndentStack->push_back(i + spaceTabCount - horstmannIndentInStatement); 2200 2201 int tabIncrement = tabIncrementIn; 2202 2203 // check for following tabs 2204 for (int j = i + 1; j < (i + nextNonWSChar); j++) 2205 { 2206 if (line[j] == '\t') 2207 tabIncrement += convertTabToSpaces(j, tabIncrement); 2208 } 2209 2210 inStatementIndent = i + nextNonWSChar + spaceTabCount + tabIncrement; 2211 2212 // check for run-in statement 2213 if (i > 0 && line[0] == '{') 2214 inStatementIndent -= indentLength; 2215 2216 // if (i + nextNonWSChar < minIndent) 2217 // inStatementIndent = minIndent + spaceTabCount; 2218 2219 if (inStatementIndent < minIndent) 2220 inStatementIndent = minIndent + spaceTabCount; 2221 2222 // if (i + nextNonWSChar > maxInStatementIndent) 2223 // inStatementIndent = indentLength * 2 + spaceTabCount; 2224 2225 if (inStatementIndent > maxInStatementIndent) 2226 inStatementIndent = indentLength * 2 + spaceTabCount; 2227 2228 if (!inStatementIndentStack->empty() && 2229 inStatementIndent < inStatementIndentStack->back()) 2230 inStatementIndent = inStatementIndentStack->back(); 2231 2232 // the block opener is not indented for a NonInStatementArray 2233 if (isNonInStatementArray && !bracketBlockStateStack->empty() && bracketBlockStateStack->back()) 2234 inStatementIndent = 0; 2235 2236 inStatementIndentStack->push_back(inStatementIndent); 2237 } 2238 2239 /** 2240 * get distance to the next non-white space, non-comment character in the line. 2241 * if no such character exists, return the length remaining to the end of the line. 2242 */ 2243 int ASBeautifier::getNextProgramCharDistance(const string &line, int i) const 2244 { 2245 bool inComment = false; 2246 int remainingCharNum = line.length() - i; 2247 int charDistance; 2248 char ch; 2249 2250 for (charDistance = 1; charDistance < remainingCharNum; charDistance++) 2251 { 2252 ch = line[i + charDistance]; 2253 if (inComment) 2254 { 2255 if (line.compare(i + charDistance, 2, "*/") == 0) 2256 { 2257 charDistance++; 2258 inComment = false; 2259 } 2260 continue; 2261 } 2262 else if (isWhiteSpace(ch)) 2263 continue; 2264 else if (ch == '/') 2265 { 2266 if (line.compare(i + charDistance, 2, "//") == 0) 2267 return remainingCharNum; 2268 else if (line.compare(i + charDistance, 2, "/*") == 0) 2269 { 2270 charDistance++; 2271 inComment = true; 2272 } 2273 } 2274 else 2275 return charDistance; 2276 } 2277 2278 return charDistance; 2279 } 2280 2281 // check if a specific line position contains a header. 2282 const string* ASBeautifier::findHeader(const string &line, int i, 2283 const vector<const string*>* possibleHeaders) const 2284 { 2285 assert(isCharPotentialHeader(line, i)); 2286 // check the word 2287 size_t maxHeaders = possibleHeaders->size(); 2288 for (size_t p = 0; p < maxHeaders; p++) 2289 { 2290 const string* header = (*possibleHeaders)[p]; 2291 const size_t wordEnd = i + header->length(); 2292 if (wordEnd > line.length()) 2293 continue; 2294 int result = (line.compare(i, header->length(), *header)); 2295 if (result > 0) 2296 continue; 2297 if (result < 0) 2298 break; 2299 // check that this is not part of a longer word 2300 if (wordEnd == line.length()) 2301 return header; 2302 if (isLegalNameChar(line[wordEnd])) 2303 continue; 2304 // is not a header if part of a definition 2305 const char peekChar = peekNextChar(line, wordEnd - 1); 2306 if (peekChar == ',' || peekChar == ')') 2307 break; 2308 return header; 2309 } 2310 return NULL; 2311 } 2312 2313 // check if a specific line position contains an operator. 2314 const string* ASBeautifier::findOperator(const string &line, int i, 2315 const vector<const string*>* possibleOperators) const 2316 { 2317 assert(isCharPotentialOperator(line[i])); 2318 // find the operator in the vector 2319 // the vector contains the LONGEST operators first 2320 // must loop thru the entire vector 2321 size_t maxOperators = possibleOperators->size(); 2322 for (size_t p = 0; p < maxOperators; p++) 2323 { 2324 const size_t wordEnd = i + (*(*possibleOperators)[p]).length(); 2325 if (wordEnd > line.length()) 2326 continue; 2327 if (line.compare(i, (*(*possibleOperators)[p]).length(), *(*possibleOperators)[p]) == 0) 2328 return (*possibleOperators)[p]; 2329 } 2330 return NULL; 2331 } 2332 2333 /** 2334 * find the index number of a string element in a container of strings 2335 * 2336 * @return the index number of element in the container. -1 if element not found. 2337 * @param container a vector of strings. 2338 * @param element the element to find . 2339 */ 2340 int ASBeautifier::indexOf(vector<const string*> &container, const string *element) 2341 { 2342 vector<const string*>::const_iterator where; 2343 2344 where = find(container.begin(), container.end(), element); 2345 if (where == container.end()) 2346 return -1; 2347 else 2348 return (int) (where - container.begin()); 2349 } 2350 2351 /** 2352 * convert tabs to spaces. 2353 * i is the position of the character to convert to spaces. 2354 * tabIncrementIn is the increment that must be added for tab indent characters 2355 * to get the correct column for the current tab. 2356 */ 2357 int ASBeautifier::convertTabToSpaces(int i, int tabIncrementIn) const 2358 { 2359 int tabToSpacesAdjustment = indentLength - 1 - ((tabIncrementIn + i) % indentLength); 2360 return tabToSpacesAdjustment; 2361 } 2362 2363 /** 2364 * trim removes the white space surrounding a line. 2365 * 2366 * @return the trimmed line. 2367 * @param str the line to trim. 2368 */ 2369 string ASBeautifier::trim(const string &str) 2370 { 2371 2372 int start = 0; 2373 int end = str.length() - 1; 2374 2375 while (start < end && isWhiteSpace(str[start])) 2376 start++; 2377 2378 while (start <= end && isWhiteSpace(str[end])) 2379 end--; 2380 2381 string returnStr(str, start, end + 1 - start); 2382 return returnStr; 2383 } 2384 2385 /** 2386 * Copy tempStacks for the copy constructor. 2387 * The value of the vectors must also be copied. 2388 */ 2389 vector<vector<const string*>*>* ASBeautifier::copyTempStacks(const ASBeautifier &other) const 2390 { 2391 vector<vector<const string*>*> *tempStacksNew = new vector<vector<const string*>*>; 2392 vector<vector<const string*>*>::iterator iter; 2393 for (iter = other.tempStacks->begin(); 2394 iter != other.tempStacks->end(); 2395 ++iter) 2396 { 2397 vector<const string*> *newVec = new vector<const string*>; 2398 *newVec = **iter; 2399 tempStacksNew->push_back(newVec); 2400 } 2401 return tempStacksNew; 2402 } 2403 2404 /** 2405 * delete a static member vector to eliminate memory leak reporting for the vector 2406 */ 2407 void ASBeautifier::deleteStaticVectors() 2408 { 2409 beautifierFileType = 9; // reset to an invalid type 2410 deleteVector(headers); 2411 deleteVector(nonParenHeaders); 2412 deleteVector(preBlockStatements); 2413 deleteVector(assignmentOperators); 2414 deleteVector(nonAssignmentOperators); 2415 deleteVector(indentableHeaders); 2416 } 2417 2418 /** 2419 * delete a vector object 2420 * T is the type of vector 2421 * used for all vectors except tempStacks 2422 */ 2423 template<typename T> 2424 void ASBeautifier::deleteContainer(T &container) 2425 { 2426 if (container != NULL) 2427 { 2428 container->clear(); 2429 delete (container); 2430 container = NULL; 2431 } 2432 } 2433 2434 /** 2435 * Delete the tempStacks vector object. 2436 * The tempStacks is a vector of pointers to strings allocated with 2437 * the 'new' operator. 2438 * Therefore the strings have to be deleted in addition to the 2439 * tempStacks entries. 2440 */ 2441 void ASBeautifier::deleteContainer(vector<vector<const string*>*>* &container) 2442 { 2443 if (container != NULL) 2444 { 2445 vector<vector<const string*>*>::iterator iter = container->begin(); 2446 for (; iter != container->end(); iter++) 2447 delete *iter; 2448 container->clear(); 2449 delete (container); 2450 container = NULL; 2451 } 2452 } 2453 2454 /** 2455 * delete a vector<const string*>* object 2456 */ 2457 void ASBeautifier::deleteVector(vector<const string*>*& container) 2458 { 2459 assert(container != NULL); 2460 delete container; 2461 container = NULL; 2462 } 2463 2464 /** 2465 * initialize a vector object 2466 * T is the type of vector 2467 * used for all vectors 2468 */ 2469 template<typename T> 2470 void ASBeautifier::initContainer(T &container, T value) 2471 { 2472 // since the ASFormatter object is never deleted, 2473 // the existing vectors must be deleted before creating new ones 2474 if (container != NULL ) 2475 deleteContainer(container); 2476 container = value; 2477 } 2478 2479 /** 2480 * initialize a vector<const string*>* object 2481 */ 2482 void ASBeautifier::initVector(vector<const string*>*& container) 2483 { 2484 assert(container == NULL); 2485 container = new vector<const string*>; 2486 } 2487 2488 /** 2489 * Determine if an assignment statement ends with a comma 2490 * that is not in a function argument. It ends with a 2491 * comma if a comma is the last char on the line. 2492 * 2493 * @return true if line ends with a comma, otherwise false. 2494 */ 2495 bool ASBeautifier::statementEndsWithComma(string &line, int index) 2496 { 2497 assert(line[index] == '='); 2498 2499 bool isInComment = false; 2500 bool isInQuote = false; 2501 int parenCount = 0; 2502 size_t lineLength = line.length(); 2503 size_t i = 0; 2504 char quoteChar = ' '; 2505 2506 for (i = index + 1; i < lineLength; ++i) 2507 { 2508 char ch = line[i]; 2509 2510 if (isInComment) 2511 { 2512 if (line.compare(i, 2, "*/") == 0) 2513 { 2514 isInComment = false; 2515 ++i; 2516 } 2517 continue; 2518 } 2519 2520 if (ch == '\\') 2521 { 2522 ++i; 2523 continue; 2524 } 2525 2526 if (isInQuote) 2527 { 2528 if (ch == quoteChar) 2529 isInQuote = false; 2530 continue; 2531 } 2532 2533 if (ch == '"' || ch == '\'') 2534 { 2535 isInQuote = true; 2536 quoteChar = ch; 2537 continue; 2538 } 2539 2540 if (line.compare(i, 2, "//") == 0) 2541 break; 2542 2543 if (line.compare(i, 2, "/*") == 0) 2544 { 2545 if (isLineEndComment(line, i)) 2546 break; 2547 else 2548 { 2549 isInComment = true; 2550 ++i; 2551 continue; 2552 } 2553 } 2554 2555 if (ch == '(') 2556 parenCount++; 2557 if (ch == ')') 2558 parenCount--; 2559 } 2560 if (isInComment 2561 || isInQuote 2562 || parenCount > 0) 2563 return false; 2564 2565 size_t lastChar = line.find_last_not_of(" \t", i - 1); 2566 2567 if (lastChar == string::npos || line[lastChar] != ',') 2568 return false; 2569 2570 return true; 2571 } 2572 2573 /** 2574 * check if current comment is a line-end comment 2575 * 2576 * @return is before a line-end comment. 2577 */ 2578 bool ASBeautifier::isLineEndComment(string& line, int startPos) const 2579 { 2580 assert(line.compare(startPos, 2, "/*") == 0); 2581 2582 // comment must be closed on this line with nothing after it 2583 size_t endNum = line.find("*/", startPos + 2); 2584 if (endNum != string::npos) 2585 { 2586 size_t nextChar = line.find_first_not_of(" \t", endNum + 2); 2587 if (nextChar == string::npos) 2588 return true; 2589 } 2590 return false; 2591 } 2592 2593 /** 2594 * get the previous word index for an assignment operator 2595 * 2596 * @return is the index to the previous word (the in statement indent). 2597 */ 2598 int ASBeautifier::getInStatementIndentAssign(const string& line, size_t currPos) const 2599 { 2600 assert(line[currPos] == '='); 2601 2602 if (currPos == 0) 2603 return 0; 2604 2605 // get the last legal word (may be a number) 2606 size_t end = line.find_last_not_of(" \t", currPos-1); 2607 if (end == string::npos || !isLegalNameChar(line[end])) 2608 return 0; 2609 2610 int start; // start of the previous word 2611 for (start = end; start > -1; start--) 2612 { 2613 if (!isLegalNameChar(line[start]) || line[start] == '.') 2614 break; 2615 } 2616 start++; 2617 2618 return start; 2619 } 2620 2621 /** 2622 * get the instatement indent for a comma 2623 * 2624 * @return is the indent to the second word on the line (the in statement indent). 2625 */ 2626 int ASBeautifier::getInStatementIndentComma(const string& line, size_t currPos) const 2627 { 2628 assert(line[currPos] == ','); 2629 2630 if (currPos == 0) 2631 return 0; 2632 2633 // get first word on a line 2634 size_t indent = line.find_first_not_of(" \t"); 2635 if (indent == string::npos || !isLegalNameChar(line[indent])) 2636 return 0; 2637 2638 // bypass first word 2639 for (; indent < currPos; indent++) 2640 { 2641 if (!isLegalNameChar(line[indent])) 2642 break; 2643 } 2644 indent++; 2645 if (indent >= currPos) 2646 return 0; 2647 2648 // point to second word or assignment operator 2649 indent = line.find_last_not_of(" \t", indent); 2650 if (indent == string::npos || indent >= currPos) 2651 return 0; 2652 2653 return indent; 2654 } 2655 2656 2657 } // end namespace astyle 2658